From 887129bea8e6fd83f3fd66532df6168d44e30a6e Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Sat, 22 Jan 2022 13:57:02 +1300 Subject: [PATCH 1/2] Fix LdrLoadDll signature --- memlib.nim | 4 ++-- memlib.nimble | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/memlib.nim b/memlib.nim index 2842cf7..9ea62cf 100644 --- a/memlib.nim +++ b/memlib.nim @@ -830,9 +830,9 @@ proc loadString*(lib: MemoryModule, id: UINT, lang: WORD = 0): string # for hooks -proc LdrLoadDll(PathToFile: PWCHAR, Flags: ULONG, ModuleFileName: PUNICODE_STRING, ModuleHandle: PHANDLE): NTSTATUS {.stdcall, dynlib: "ntdll", importc.} +proc LdrLoadDll(PathToFile: PWCHAR, Flags: PULONG, ModuleFileName: PUNICODE_STRING, ModuleHandle: PHANDLE): NTSTATUS {.stdcall, dynlib: "ntdll", importc.} -proc myLdrLoadDll(PathToFile: PWCHAR, Flags: ULONG, ModuleFileName: PUNICODE_STRING, ModuleHandle: PHANDLE): NTSTATUS {.stdcall, minhook: LdrLoadDll.} = +proc myLdrLoadDll(PathToFile: PWCHAR, Flags: PULONG, ModuleFileName: PUNICODE_STRING, ModuleHandle: PHANDLE): NTSTATUS {.stdcall, minhook: LdrLoadDll.} = withLock(gLock): for i in 0 ..< memLibs.len: if memLibs[i].name != nil and lstrcmpiW(ModuleFileName[].Buffer, memLibs[i].name) == 0: diff --git a/memlib.nimble b/memlib.nimble index 2ea62f2..645cc3e 100644 --- a/memlib.nimble +++ b/memlib.nimble @@ -1,6 +1,6 @@ # Package -version = "1.2.0" +version = "1.2.1" author = "Ward" description = "Memlib - Load Windows DLL from memory" license = "MIT" From 944341cc701a772101b4b1681f054d552f6341b4 Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Mon, 2 May 2022 10:11:29 +1200 Subject: [PATCH 2/2] Support GetModuleHandleExW, EnumProcessModules --- memlib.nim | 44 +++++++++++++++++++++++++++++++++++++++++++- memlib.nimble | 2 +- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/memlib.nim b/memlib.nim index 9ea62cf..bbc71f3 100644 --- a/memlib.nim +++ b/memlib.nim @@ -10,7 +10,7 @@ ## implementation of the famous MemoryModule library. ## So that the we can embed all DLLs into the main EXE file. -import tables, macros, md5, locks, os, terminal, strutils, dynlib +import tables, macros, md5, locks, os, terminal, strutils, dynlib, bitops import winim/lean, minhook import memlib/private/sharedseq @@ -849,6 +849,42 @@ proc myGetProcAddress(hModule: HMODULE, lpProcName: LPCSTR): FARPROC {.stdcall, if hModule == memLibs[i][HANDLE]: return memLibs[i].symAddr(lpProcName) +proc myGetModuleHandleExW(dwFlags: DWORD, lpModuleName: LPCWSTR, phModule: ptr HMODULE): WINBOOL {.stdcall, minhook: GetModuleHandleExW.} = + let pageSize = getPageSize() + withLock(gLock): + for i in 0 ..< memLibs.len: + if bitAnd(dwFlags, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS): + let address = lpModuleName[uint] + let start = memLibs[i].codeBase[uint] + let size = alignUp(memLibs[i].headers.OptionalHeader.SizeOfImage{uint}, pageSize) + if start <= address and address < start + size: + phModule[] = memLibs[i][HANDLE] + return TRUE + else: + if memLibs[i].name != nil and lstrcmpiW(lpModuleName, memLibs[i].name) == 0: + phModule[] = memLibs[i][HANDLE] + return TRUE + return GetModuleHandleExW(dwFlags, lpModuleName, phModule) + +proc K32EnumProcessModules(hProcess: HANDLE, lphModule: ptr UncheckedArray[HMODULE], cb: DWORD, cbNeeded: ptr DWORD): WINBOOL {. dynlib: "kernel32", importc: "K32EnumProcessModules", stdcall.} +proc myK32EnumProcessModules(hProcess: HANDLE, lphModule: ptr UncheckedArray[HMODULE], cb: DWORD, cbNeeded: ptr DWORD): WINBOOL {.stdcall, minhook: K32EnumProcessModules.} = + result = K32EnumProcessModules(hProcess, lphModule, cb, cbNeeded) + if result == 1: + var sz = cbNeeded[] div 8 + var mx = cb div 8 + for i in 0 ..< memLibs.len: + if sz >= mx: + break + if memLibs[i].name != nil: + lphModule[sz] = memLibs[i][HANDLE] + sz += 1 + cbNeeded[] = sz * 8 + +# TODO: only if PSAPI_VERSION >= 2 +proc EnumProcessModules(hProcess: HANDLE, lphModule: ptr UncheckedArray[HMODULE], cb: DWORD, cbNeeded: ptr DWORD): WINBOOL {. dynlib: "psapi", importc: "EnumProcessModules", stdcall.} +proc myEnumProcessModules(hProcess: HANDLE, lphModule: ptr UncheckedArray[HMODULE], cb: DWORD, cbNeeded: ptr DWORD): WINBOOL {.stdcall, minhook: EnumProcessModules.} = + return myK32EnumProcessModules(hProcess, lphModule, cb, cbNeeded) + proc unhook*(lib: MemoryModule) {.raises: [].} = ## Removes the hooks. assert lib != nil @@ -865,6 +901,9 @@ proc unhook*(lib: MemoryModule) {.raises: [].} = try: queueDisableHook(LdrLoadDll) queueDisableHook(GetProcAddress) + queueDisableHook(GetModuleHandleExW) + queueDisableHook(K32EnumProcessModules) + queueDisableHook(EnumProcessModules) applyQueued() except: discard hookEnabled = false @@ -887,6 +926,9 @@ proc hook*(lib: MemoryModule, name: string) {.raises: [LibraryError].} = try: queueEnableHook(LdrLoadDll) queueEnableHook(GetProcAddress) + queueEnableHook(GetModuleHandleExW) + queueEnableHook(K32EnumProcessModules) + queueEnableHook(EnumProcessModules) applyQueued() except: discard hookEnabled = true diff --git a/memlib.nimble b/memlib.nimble index 645cc3e..a853b08 100644 --- a/memlib.nimble +++ b/memlib.nimble @@ -1,6 +1,6 @@ # Package -version = "1.2.1" +version = "1.2.2" author = "Ward" description = "Memlib - Load Windows DLL from memory" license = "MIT"