From e5c40d331e33763794cc0431d16dcf19f93c2810 Mon Sep 17 00:00:00 2001 From: devseed Date: Sun, 20 Mar 2022 12:57:20 +0900 Subject: [PATCH] x64 memdll support --- README.md | 115 ++++++- src/memdll/Makefile | 5 +- src/memdll/libwinpe.def | 23 ++ src/memdll/win_injectmemdll.c | 138 +++++--- src/memdll/win_injectmemdll_shellcodestub.py | 88 +++--- util/include/winpe.h | 313 +++++++++++++++++-- 6 files changed, 538 insertions(+), 144 deletions(-) diff --git a/README.md b/README.md index 721427b..867d27a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,105 @@ # MemoryModule A tool to parse and load module in memory, as well as attach a DLL in EXE. -## winpe +Most of the functions are inline, so that it can also be used in shellcode. + +## compile + +```shell +cd ./src/memdll +pip install lief +pip install keystone +make ARCH=i686 # x86 release +make ARCH=x86_64 # x64 release +make ARCH=i686 DEBUG=1 # x86 debug +make ARCH=x86_64 DEBUG=1 # x64 debug +``` + +## usage + +### load DLL in memory + +```c +const char *dllpath = "test.dll"; +size_t mempesize = 0; +void *memdll = NULL; + +// load the pe file in memory and align it to memory align +void *mempe = winpe_memload_file(dllpath, &mempesize, TRUE); + +// memory loadlibrary +memdll = winpe_memLoadLibrary(mempe); +winpe_memFreeLibrary(memdll); + +// memory loadlibrary at specific address +size_t targetaddr = sizeof(size_t) > 4 ? 0x140030000: 0x90000; +memdll = winpe_memLoadLibraryEx(memdll, targetaddr, + WINPE_LDFLAG_MEMALLOC, (PFN_LoadLibraryA)winpe_findloadlibrarya(), + (PFN_GetProcAddress)winpe_memGetProcAddress); +winpe_memFreeLibrary(memdll); +free(mempe); +``` + + + +### attach DLL in exe + +```shell +win_injectmemdll.exe exepath dllpath [outpath] +``` + +## memory module API These functions are essential to load memory module in windows. ```c +/* + similar to LoadlibrayA, will call dllentry + will load the mempe in a valid imagebase + return hmodule base +*/ +WINPEDEF WINPE_EXPORT +inline void* STDCALL winpe_memLoadLibrary(void *mempe); + +/* + if imagebase==0, will load on mempe, or in imagebase + will load the mempe in a valid imagebase, flag as below: + WINPE_LDFLAG_MEMALLOC 0x1, will alloc memory to imagebase + WINPE_LDFLAG_MEMFIND 0x2, will find a valid space, + must combined with WINPE_LDFLAG_MEMALLOC + return hmodule base +*/ +WINPEDEF WINPE_EXPORT +inline void* STDCALL winpe_memLoadLibraryEx(void *mempe, + size_t imagebase, DWORD flag, + PFN_LoadLibraryA pfnLoadLibraryA, + PFN_GetProcAddress pfnGetProcAddress); + +/* + similar to FreeLibrary, will call dllentry + return true or false +*/ +WINPEDEF WINPE_EXPORT +inline BOOL STDCALL winpe_memFreeLibrary(void *mempe); + +/* + FreeLibraryEx with VirtualFree custom function + return true or false +*/ +WINPEDEF WINPE_EXPORT +inline BOOL STDCALL winpe_memFreeLibraryEx(void *mempe, + PFN_LoadLibraryA pfnLoadLibraryA, + PFN_GetProcAddress pfnGetProcAddress); + +/* + similar to GetProcAddress + return function va +*/ +WINPEDEF WINPE_EXPORT +inline PROC STDCALL winpe_memGetProcAddress( + void *mempe, const char *funcname); + +// mempe internal functions /* load the origin rawpe in memory buffer by mem align return memsize @@ -31,21 +125,8 @@ size_t winpe_membindiat(void *mempe, See `winpe.h` for parsing and loading PE structure in detail. -## compile +## known issues -```shell -cd ./src/memdll -pip install lief -pip install keystone -make ARCH=i686 # x86 release -make ARCH=x86_64 # x64 release -make ARCH=i686 DEBUG=1 # x86 debug -make ARCH=x86_64 DEBUG=1 # x64 debug -``` - -## usage - -```shell -win_injectmemdll exepath dllpath [outpath] -``` +* attach x64 DLL to exe crash on calling some windows API + (load x64 DLL in memory after main function doesn't have this problem) diff --git a/src/memdll/Makefile b/src/memdll/Makefile index d155b9a..f1c4435 100644 --- a/src/memdll/Makefile +++ b/src/memdll/Makefile @@ -1,3 +1,5 @@ +# make -j12 ARCH=i686 && make -j12 ARCH=i686 DEBUG=1 +# make -j12 ARCH=x86_64 && make -j12 ARCH=x86_64 DEBUG=1 LIBPREFIX?=./../../ ARCH?=i686 PREFIX?=./bin @@ -60,7 +62,8 @@ prepare: libwinpe: libwinpe.c @echo \#\#building $@ ... $(CC) $< -o $(PREFIX)/$@$(ARCH_POSTFIX)$(DLL_EXT) \ - -shared $(CFLAGS) $(LDFLAGS) $(INCS) $(LIBS) $(LIBDIRS) + -shared -Wl,/DEF:$@.def\ + $(CFLAGS) $(LDFLAGS) $(INCS) $(LIBS) $(LIBDIRS) win_injectmemdll_shellcodestub: win_injectmemdll.c libwinpe python $@.py $< \ diff --git a/src/memdll/libwinpe.def b/src/memdll/libwinpe.def index e69de29..a431a8d 100644 --- a/src/memdll/libwinpe.def +++ b/src/memdll/libwinpe.def @@ -0,0 +1,23 @@ +EXPORTS + winpe_appendsecth + winpe_findgetprocaddress + winpe_findkernel32 + winpe_findloadlibrarya + winpe_findspace + winpe_imagebaseval + winpe_memFreeLibrary + winpe_memFreeLibraryEx + winpe_memGetProcAddress + winpe_memLoadLibrary + winpe_memLoadLibraryEx + winpe_membindiat + winpe_memfindexp + winpe_memfindiat + winpe_memforwardexp + winpe_memload + winpe_memload_file + winpe_memreloc + winpe_noaslr + winpe_oepval + winpe_overlayload_file + winpe_overlayoffset \ No newline at end of file diff --git a/src/memdll/win_injectmemdll.c b/src/memdll/win_injectmemdll.c index 66ee5d1..d39e6a5 100644 --- a/src/memdll/win_injectmemdll.c +++ b/src/memdll/win_injectmemdll.c @@ -1,6 +1,10 @@ /* - a tool to attach a dll inside a pe file - v0.2, developed by devseed + a tool to attach a dll inside a pe file + v0.3, developed by devseed + + history: + v0.2, support for x86 + v0.3, add test part, support for x64, optimizing code structure */ #include @@ -13,15 +17,30 @@ fclose(_fp) // these functions are stub function, will be filled by python +#define FUNC_SIZE 0x400 +#define SHELLCODE_SIZE 0X2000 unsigned char g_oepinit_code[] = {0x90}; +unsigned char g_memreloc_code[] = {0x90}; unsigned char g_membindiat_code[] = {0x90}; -unsigned char g_memfindexp_code[] = {0x90}; +unsigned char g_findloadlibrarya_code[] = {0x90}; +unsigned char g_memGetProcAddress_code[] = {0x90}; + +size_t _sectpaddingsize(void *mempe, void *mempe_dll, size_t align) +{ + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe; + PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS) + ((void*)mempe + pDosHeader->e_lfanew); + PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader; + PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader; + size_t _v = (pOptHeader->SizeOfImage + SHELLCODE_SIZE) % align; + if (_v) return align - _v; + else return 0; +} -void _oepshellcode(void *mempe_exe, void *mempe_dll, - void *shellcode, PIMAGE_SECTION_HEADER psecth, DWORD orgoeprva) +void _oepshellcode(void *mempe_exe, void *mempe_dll, void *shellcode, + size_t shellcodebase, size_t dllimagebase, DWORD orgoeprva) { // PE struct declear -#define FUNC_SIZE 0x200 void *mempe; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; @@ -37,14 +56,16 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll, // bind the pointer to buffer size_t oepinit_end = sizeof(g_oepinit_code); - size_t memiatbind_start = FUNC_SIZE; - size_t memfindexp_start = memiatbind_start + FUNC_SIZE; + size_t memreloc_start = FUNC_SIZE; + size_t memiatbind_start = memreloc_start + FUNC_SIZE; + size_t memfindloadlibrarya_start = memiatbind_start + FUNC_SIZE; + size_t memGetProcAddress_start = memfindloadlibrarya_start + FUNC_SIZE; size_t *pexeoepva = (size_t*)(g_oepinit_code + oepinit_end - 6*sizeof(size_t)); size_t *pdllbase = (size_t*)(g_oepinit_code + oepinit_end - 5*sizeof(size_t)); size_t *pdlloepva = (size_t*)(g_oepinit_code + oepinit_end - 4*sizeof(size_t)); size_t *pmemiatbind = (size_t*)(g_oepinit_code + oepinit_end - 3*sizeof(size_t)); - size_t *pexeloadlibrarya = (size_t*)(g_oepinit_code + oepinit_end - 2*sizeof(size_t)); - size_t *pexegetprocessaddress = (size_t*)(g_oepinit_code + oepinit_end - 1*sizeof(size_t)); + size_t *pfindloadlibrarya = (size_t*)(g_oepinit_code + oepinit_end - 2*sizeof(size_t)); + size_t *pgetprocessaddress = (size_t*)(g_oepinit_code + oepinit_end - 1*sizeof(size_t)); // get the information of exe mempe = mempe_exe; @@ -56,7 +77,6 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll, pImpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; pImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(mempe + pImpEntry->VirtualAddress); size_t exeimagebase = pOptHeader->ImageBase; - size_t shellcodebase = exeimagebase + psecth->VirtualAddress; // get the information of dll mempe = mempe_dll; @@ -65,7 +85,6 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll, pFileHeader = &pNtHeader->FileHeader; pOptHeader = &pNtHeader->OptionalHeader; pDataDirectory = pOptHeader->DataDirectory; - size_t dllimagebase = pOptHeader->ImageBase; DWORD dlloeprva = pOptHeader->AddressOfEntryPoint; // fill the address table @@ -73,22 +92,22 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll, *pdllbase = dllimagebase; *pdlloepva = dllimagebase + pOptHeader->AddressOfEntryPoint; *pmemiatbind = shellcodebase + memiatbind_start; - *pexeloadlibrarya = exeimagebase + - (size_t)(winpe_memfindiat(mempe_exe, - "kernel32.dll", "LoadLibraryA") - mempe_exe); - *pexegetprocessaddress = sizeof(size_t) > 4 ? - shellcodebase + memfindexp_start : // x64 - exeimagebase + (size_t)(winpe_memfindiat(mempe_exe, // x86 - "kernel32.dll", "GetProcAddress") - mempe_exe); + *pfindloadlibrarya = shellcodebase + memfindloadlibrarya_start; + *pgetprocessaddress = shellcodebase + memGetProcAddress_start; // copy to the target memcpy(shellcode , g_oepinit_code, sizeof(g_oepinit_code)); + memcpy(shellcode + memreloc_start, + g_memreloc_code, sizeof(g_memreloc_code)); memcpy(shellcode + memiatbind_start, g_membindiat_code, sizeof(g_membindiat_code)); - memcpy(shellcode + memfindexp_start, - g_memfindexp_code, sizeof(g_memfindexp_code)); + memcpy(shellcode + memfindloadlibrarya_start, + g_findloadlibrarya_code, sizeof(g_findloadlibrarya_code)); + memcpy(shellcode + memGetProcAddress_start, + g_memGetProcAddress_code, sizeof(g_memGetProcAddress_code)); } +// memory structure: [exe sections], [shellcode, padding, dll] int injectdll_mem(const char *exepath, const char *dllpath, const char *outpath) { @@ -102,7 +121,6 @@ int injectdll_mem(const char *exepath, size_t overlay_exesize = 0; size_t imgbase_exe = 0; IMAGE_SECTION_HEADER secth = {0}; - #define SHELLCODE_SIZE 0X1000 char shellcode[SHELLCODE_SIZE]; // load exe and dll pe @@ -117,22 +135,30 @@ int injectdll_mem(const char *exepath, PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader; imgbase_exe = pOptHeader->ImageBase; - // append the dll section and adjust + // append section header to exe + size_t align = sizeof(size_t) > 4 ? 0x10000: 0x1000; + size_t padding = _sectpaddingsize(mempe_exe, mempe_dll, align); secth.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE; - secth.Misc.VirtualSize = mempe_dllsize + SHELLCODE_SIZE; - secth.SizeOfRawData = mempe_dllsize + SHELLCODE_SIZE; + secth.Misc.VirtualSize = SHELLCODE_SIZE + padding + mempe_dllsize; + secth.SizeOfRawData = SHELLCODE_SIZE + padding + mempe_dllsize; strcpy((char*)secth.Name, ".module"); winpe_noaslr(mempe_exe); winpe_appendsecth(mempe_exe, §h); + + // adjust dll addr and append shellcode, iatbind is in runing DWORD orgoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress); - winpe_memreloc(mempe_dll, imgbase_exe + secth.VirtualAddress + SHELLCODE_SIZE); - _oepshellcode(mempe_exe, mempe_dll, shellcode, §h, orgoeprva); + size_t shellcodebase = imgbase_exe + secth.VirtualAddress; + size_t dllimagebase = shellcodebase + SHELLCODE_SIZE + padding; + _oepshellcode(mempe_exe, mempe_dll, shellcode, + shellcodebase, dllimagebase, orgoeprva); + winpe_memreloc(mempe_dll, dllimagebase); // write data to new exe FILE *fp = fopen(outpath, "wb"); fwrite(mempe_exe, 1, mempe_exesize, fp); fwrite(shellcode, 1, SHELLCODE_SIZE, fp); + for(int i=0;i 4 ? 0x140030000: 0x90000; + memdll = winpe_memLoadLibraryEx(memdll, targetaddr, + WINPE_LDFLAG_MEMALLOC, (PFN_LoadLibraryA)winpe_findloadlibrarya(), + (PFN_GetProcAddress)winpe_memGetProcAddress); + assert((size_t)memdll==targetaddr); + printf("winpe_memLoadLibraryEx, load at %p passed!\n", memdll); + winpe_memFreeLibrary(memdll); + + printf("test_memdll %s passed]\n\n", dllpath); free(mempe); } diff --git a/src/memdll/win_injectmemdll_shellcodestub.py b/src/memdll/win_injectmemdll_shellcodestub.py index e561365..de070ca 100644 --- a/src/memdll/win_injectmemdll_shellcodestub.py +++ b/src/memdll/win_injectmemdll_shellcodestub.py @@ -1,6 +1,11 @@ """ this file is for automaticly generate some shellcodes stub informations - v0.1, developed by devseed + v0.3, developed by devseed + + history: + v0.1, initial version + v0.2, add more function for shellcode + v0.3, x86 and x64 no need to use exe's LoadLibraryA """ import re import sys @@ -15,20 +20,17 @@ def gen_oepinit_code32(): lea ebx, [eax-5]; // bind iat - push eax; // rvaaddr = 0 - lea eax, [ebx + exegetprocessaddress]; - mov eax, [eax]; // iat - mov eax, [eax]; // iat->addr + lea eax, [ebx + getprocessaddress]; + mov eax, [eax]; push eax; - lea eax, [ebx + exeloadlibrarya]; - mov eax, [eax]; // iat - mov eax, [eax]; // iat->addr + lea eax, [ebx + findloadlibrarya]; + call [eax]; push eax; lea eax, [ebx + dllbase]; // dllbase addr mov eax, [eax]; // dllbase value push eax; call [ebx + memiatbind]; - add esp, 0x10; + add esp, 0xc; // call dll oep, for dll entry xor eax, eax; @@ -51,8 +53,8 @@ def gen_oepinit_code32(): dllbase: nop;nop;nop;nop; dlloepva: nop;nop;nop;nop; memiatbind: nop;nop;nop;nop; - exeloadlibrarya: nop;nop;nop;nop; - exegetprocessaddress: nop;nop;nop;nop; + findloadlibrarya: nop;nop;nop;nop; + getprocessaddress: nop;nop;nop;nop; """ print("gen_oepinit_code32", code_str) payload, _ = ks.asm(code_str) @@ -71,13 +73,13 @@ def gen_oepinit_code64(): push r9; // bind iat - lea r8, [rbx + exegetprocessaddress]; - mov r8, [r8]; // winpe_memfindexp - lea rdx, [rbx + exeloadlibrarya]; - mov rdx, [rdx]; // iat - mov rdx, [rdx]; // iat->addr - lea rcx, [rbx + dllbase]; // dllbase addr - mov rcx, [rcx]; // dllbase value + lea rdx, [rbx + findloadlibrarya]; + call [rdx]; + mov rdx, rax; // arg2, loadlibraryas + lea r8, [rbx + getprocessaddress]; + mov r8, [r8]; // arg3, getprocaddress + lea rcx, [rbx + dllbase]; + mov rcx, [rcx]; // arg1, dllbase value call [rbx + memiatbind]; // call dll oep, for dll entry @@ -103,14 +105,13 @@ def gen_oepinit_code64(): dllbase: nop;nop;nop;nop;nop;nop;nop;nop; dlloepva: nop;nop;nop;nop;nop;nop;nop;nop; memiatbind: nop;nop;nop;nop;nop;nop;nop;nop; - exeloadlibrarya: nop;nop;nop;nop;nop;nop;nop;nop; - exegetprocessaddress: nop;nop;nop;nop;nop;nop;nop;nop; + findloadlibrarya: nop;nop;nop;nop;nop;nop;nop;nop; + getprocessaddress: nop;nop;nop;nop;nop;nop;nop;nop; """ print("gen_oepinit_code64", code_str) payload, _ = ks.asm(code_str) print("payload: ", [hex(x) for x in payload]) return payload - pass def inject_shellcodestubs(srcpath, libwinpepath, targetpath): pedll = lief.parse(libwinpepath) @@ -129,37 +130,26 @@ def inject_shellcodestubs(srcpath, libwinpepath, targetpath): # if len(oepinit_code) < 0x200: oepinit_code.extend([0x00] * (0x200 - len(oepinit_code))) # find necessary functions - membindiat_func = next(filter( - lambda e : e.name == "winpe_membindiat", - pedll.exported_functions)) - membindiat_code = \ - pedll.get_content_from_virtual_address( - membindiat_func.address, 0x200) - # memiatshellcode = memiatshellcode[:memiatshellcode.index(0xC3)+1] # retn - try: - memfindexp_func = next(filter( - lambda e : e.name == "winpe_memfindexp", # x64 stdcall name + FUNC_SIZE =0x400 + codes = {"winpe_memreloc": 0, + "winpe_membindiat": 0, + "winpe_findloadlibrarya": 0, + "winpe_memGetProcAddress": 0} + for k in codes.keys(): + func = next(filter(lambda e : e.name == k, pedll.exported_functions)) - except StopIteration: - memfindexp_func = next(filter( - lambda e : e.name == "_winpe_memfindexp@8", # x86 stdcall name - pedll.exported_functions)) - memfindexp_code = \ - pedll.get_content_from_virtual_address( - memfindexp_func.address, 0x200) - + codes[k] = pedll.get_content_from_virtual_address( + func.address, FUNC_SIZE) + codes['winpe_oepinit'] = oepinit_code + # write shellcode to c source file with open(srcpath, "rb") as fp: srctext = fp.read().decode('utf8') - _codetext = ",".join([hex(x) for x in oepinit_code]) - srctext = re.sub(r"g_oepinit_code(.+?)(\{0x90\})", - r"g_oepinit_code\1{" + _codetext +"}", srctext) - _codetext = ",".join([hex(x) for x in membindiat_code]) - srctext = re.sub(r"g_membindiat_code(.+?)(\{0x90\})", - r"g_membindiat_code\1{" + _codetext +"}", srctext) - _codetext = ",".join([hex(x) for x in memfindexp_code]) - srctext = re.sub(r"g_memfindexp_code(.+?)(\{0x90\})", - r"g_memfindexp_code\1{" + _codetext +"}", srctext) + for k, v in codes.items(): + k = k.replace("winpe_", "") + _codetext = ",".join([hex(x) for x in v]) + srctext = re.sub("g_" + k + r"_code(.+?)(\{0x90\})", + "g_" + k + r"_code\1{" + _codetext +"}", srctext) with open(targetpath, "wb") as fp: fp.write(srctext.encode('utf8')) @@ -178,6 +168,6 @@ def main(): pass if __name__ == "__main__": - #debug() + # debug() main() pass \ No newline at end of file diff --git a/util/include/winpe.h b/util/include/winpe.h index 897a47d..d6ead93 100644 --- a/util/include/winpe.h +++ b/util/include/winpe.h @@ -1,16 +1,18 @@ /* - winpe.h, by devseed, v0.2.2 + winpe.h, by devseed, v0.3.2 for parsing windows pe structure, adjust realoc addrs, or iat - this function for shellcode should only use release version + most functions are single by inline all parts, + can be also used as shellcode history: - v0.1 initial version, with load pe in memory align - V0.1.2 adjust declear name, load pe iat - v0.2 add append section, findiat function - v0.2.2 add function winpe_memfindexp - v0.2.5 inline basic functions, better for shellcode - v0.3 add winpe_memloadlibrary, winpe_memgetprocaddress, winpe_memfreelibrary - + v0.1, initial version, with load pe in memory align + V0.1.2, adjust declear name, load pe iat + v0.2, add append section, findiat function + v0.2.2, add function winpe_memfindexp + v0.2.5, inline basic functions, better for shellcode + v0.3, add winpe_memloadlibrary, winpe_memGetprocaddress, winpe_memFreelibrary + v0.3.1, fix the stdcall function name by .def, load memory moudule aligned with 0x1000(x86), 0x10000(x64) + v0.3.2, x64 memory load support, winpe_findkernel32, winpe_finmodule by asm */ #ifndef _WINPE_H @@ -38,8 +40,10 @@ #ifdef _WIN32 #define STDCALL __stdcall +#define NAKED __declspec(naked) #else #define STDCALL __attribute__((stdcall)) +#define NAKED __attribute__((naked)) #endif #ifdef __cplusplus @@ -81,7 +85,8 @@ typedef SIZE_T (WINAPI *PFN_VirtualQuery)( typedef BOOL (WINAPI *PFN_DllMain)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ); -#define WINPE_LDFLAG_RVAPROC 0x1 +#define WINPE_LDFLAG_MEMALLOC 0x1 +#define WINPE_LDFLAG_MEMFIND 0x2 // PE high order fnctions /* @@ -107,11 +112,14 @@ void* winpe_overlayload_file(const char *path, return hmodule base */ WINPEDEF WINPE_EXPORT -void* STDCALL winpe_memLoadLibrary(void *mempe); +inline void* STDCALL winpe_memLoadLibrary(void *mempe); /* if imagebase==0, will load on mempe, or in imagebase - will load the mempe in a valid imagebase, + will load the mempe in a valid imagebase, flag as below: + WINPE_LDFLAG_MEMALLOC 0x1, will alloc memory to imagebase + WINPE_LDFLAG_MEMFIND 0x2, will find a valid space, + must combined with WINPE_LDFLAG_MEMALLOC return hmodule base */ WINPEDEF WINPE_EXPORT @@ -127,6 +135,16 @@ inline void* STDCALL winpe_memLoadLibraryEx(void *mempe, WINPEDEF WINPE_EXPORT inline BOOL STDCALL winpe_memFreeLibrary(void *mempe); +/* + FreeLibraryEx with VirtualFree custom function + return true or false +*/ +WINPEDEF WINPE_EXPORT +inline BOOL STDCALL winpe_memFreeLibraryEx(void *mempe, + PFN_LoadLibraryA pfnLoadLibraryA, + PFN_GetProcAddress pfnGetProcAddress); + + /* similar to GetProcAddress return function va @@ -137,15 +155,28 @@ inline PROC STDCALL winpe_memGetProcAddress( // PE query functions /* - use ped to find kernel32.dll address + use peb and ldr list, to obtain to find kernel32.dll address return kernel32.dll address */ WINPEDEF WINPE_EXPORT inline void* winpe_findkernel32(); +/* + use peb and ldr list, similar as GetModuleHandleA + return ldr module address +*/ +WINPEDEF WINPE_EXPORT +inline void* STDCALL winpe_findmodulea(char *modulename); + +/* + return LoadLibraryA func addr +*/ WINPEDEF WINPE_EXPORT inline PROC winpe_findloadlibrarya(); +/* + return GetProcAddress func addr +*/ WINPEDEF WINPE_EXPORT inline PROC winpe_findgetprocaddress(); @@ -156,7 +187,7 @@ inline PROC winpe_findgetprocaddress(); */ WINPEDEF WINPE_EXPORT inline void* winpe_findspace( - size_t imagebase, size_t imagesize, + size_t imagebase, size_t imagesize, size_t alignsize, PFN_VirtualQuery pfnVirtualQuery); // PE load, adjust functions @@ -230,14 +261,24 @@ inline void *winpe_memforwardexp( return the old oep rva */ WINPEDEF WINPE_EXPORT -inline DWORD winpe_oepval(void *mempe, DWORD newoeprva); +inline DWORD winpe_oepval( + void *mempe, DWORD newoeprva); /* change the imagebase of the pe if newimagebase!=0 return the old imagebase va */ WINPEDEF WINPE_EXPORT -inline size_t winpe_imagebaseval(void *mempe, size_t newimagebase); +inline size_t winpe_imagebaseval( + void *mempe, size_t newimagebase); + +/* + change the imagesize of the pe if newimagesize!=0 + return the old imagesize +*/ +WINPEDEF WINPE_EXPORT +inline size_t winpe_imagesizeval( + void *pe, size_t newimagesize); /* close the aslr feature of an pe @@ -251,8 +292,8 @@ inline void winpe_noaslr(void *pe); return image size */ WINPEDEF WINPE_EXPORT -inline size_t winpe_appendsecth(void *mempe, - PIMAGE_SECTION_HEADER psecth); +inline size_t winpe_appendsecth( + void *mempe, PIMAGE_SECTION_HEADER psecth); #ifdef __cplusplus @@ -267,7 +308,9 @@ inline size_t winpe_appendsecth(void *mempe, #endif #include #include +#include +// util inline functions inline static int _inl_stricmp(const char *str1, const char *str2) { int i=0; @@ -287,6 +330,25 @@ inline static int _inl_stricmp(const char *str1, const char *str2) return (int)str1[i] - (int)str2[i]; } +inline static int _inl_stricmp2(const char *str1, const wchar_t* str2) +{ + int i=0; + while(str1[i]!=0 && str2[i]!=0) + { + if ((wchar_t)str1[i] == str2[i] + || (wchar_t)str1[i] + 0x20 == str2[i] + || str2[i] + 0x20 == (wchar_t)str1[i]) + { + i++; + } + else + { + return (int)str1[i] - (int)str2[i]; + } + } + return (int)str1[i] - (int)str2[i]; +} + inline static void* _inl_memset(void *buf, int ch, size_t n) { char *p = buf; @@ -353,11 +415,16 @@ void* winpe_overlayload_file( return overlay; } - WINPEDEF WINPE_EXPORT -void* STDCALL winpe_memLoadLibrary(void *mempe) +inline void* STDCALL winpe_memLoadLibrary(void *mempe) { - return NULL; + PFN_LoadLibraryA pfnLoadLibraryA = + (PFN_LoadLibraryA)winpe_findloadlibrarya(); + PFN_GetProcAddress pfnGetProcAddress = + (PFN_GetProcAddress)winpe_findgetprocaddress(); + return winpe_memLoadLibraryEx(mempe, 0, + WINPE_LDFLAG_MEMFIND | WINPE_LDFLAG_MEMALLOC, + pfnLoadLibraryA, pfnGetProcAddress); } WINPEDEF WINPE_EXPORT @@ -366,13 +433,100 @@ inline void* STDCALL winpe_memLoadLibraryEx(void *mempe, PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress) { - return NULL; + // bind windows api + char name_kernel32[] = {'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '\0'}; + char name_VirtualQuery[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'Q', 'u', 'e', 'r', 'y', '\0'}; + char name_VirtualAlloc[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', '\0'}; + char name_VirtualProtect[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', '\0'}; + HMODULE hmod_kernel32 = pfnLoadLibraryA(name_kernel32); + PFN_VirtualQuery pfnVirtualQuery = (PFN_VirtualQuery) + pfnGetProcAddress(hmod_kernel32, name_VirtualQuery); + PFN_VirtualAlloc pfnVirtualAlloc = (PFN_VirtualAlloc) + pfnGetProcAddress(hmod_kernel32, name_VirtualAlloc); + PFN_VirtualProtect pfnVirtualProtect =(PFN_VirtualProtect) + pfnGetProcAddress(hmod_kernel32, name_VirtualProtect); + assert(pfnVirtualQuery!=0 && pfnVirtualAlloc!=0 && pfnVirtualProtect!=0); + + // find proper imagebase + size_t imagesize = winpe_imagesizeval(mempe, 0); + if(flag & WINPE_LDFLAG_MEMFIND) + { + imagebase = winpe_imagebaseval(mempe, 0); + imagebase = (size_t)winpe_findspace(imagebase, + imagesize, 0x10000, pfnVirtualQuery); + } + if(flag & WINPE_LDFLAG_MEMALLOC) // find proper memory to reloc + { + + imagebase = (size_t)pfnVirtualAlloc((void*)imagebase, + imagesize, MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + if(!imagebase) // try alloc in arbitary place + { + imagebase = (size_t)pfnVirtualAlloc(NULL, + imagesize, MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if(!imagebase) return NULL; + } + else + { + imagebase = (size_t)pfnVirtualAlloc((void*)imagebase, + imagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(!imagebase) return NULL; + } + } + + // copy to imagebase + if(!imagebase) + { + imagebase = (size_t)mempe; + } + else + { + DWORD oldprotect; + pfnVirtualProtect((void*)imagebase, imagesize, + PAGE_EXECUTE_READWRITE, &oldprotect); + _inl_memcpy((void*)imagebase, mempe, imagesize); + pfnVirtualProtect((void*)imagebase, imagesize, + oldprotect, &oldprotect); + } + + // initial memory module + if(!winpe_memreloc((void*)imagebase, imagebase)) + return NULL; + if(!winpe_membindiat((void*)imagebase, + pfnLoadLibraryA, pfnGetProcAddress)) return NULL; + PFN_DllMain pfnDllMain = (PFN_DllMain) + (imagebase + winpe_oepval((void*)imagebase, 0)); + pfnDllMain((HINSTANCE)imagebase, DLL_PROCESS_ATTACH, NULL); + return (void*)imagebase; } WINPEDEF WINPE_EXPORT inline BOOL STDCALL winpe_memFreeLibrary(void *mempe) { - return TRUE; + PFN_LoadLibraryA pfnLoadLibraryA = + (PFN_LoadLibraryA)winpe_findloadlibrarya(); + PFN_GetProcAddress pfnGetProcAddress = + (PFN_GetProcAddress)winpe_findgetprocaddress(); + return winpe_memFreeLibraryEx(mempe, + pfnLoadLibraryA, pfnGetProcAddress); +} + +WINPEDEF WINPE_EXPORT +inline BOOL STDCALL winpe_memFreeLibraryEx(void *mempe, + PFN_LoadLibraryA pfnLoadLibraryA, + PFN_GetProcAddress pfnGetProcAddress) +{ + char name_kernel32[] = {'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '\0'}; + char name_VirtualFree[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'F', 'r', 'e', 'e', '\0'}; + HMODULE hmod_kernel32 = pfnLoadLibraryA(name_kernel32); + PFN_VirtualFree pfnVirtualFree = (PFN_VirtualFree) + pfnGetProcAddress(hmod_kernel32, name_VirtualFree); + PFN_DllMain pfnDllMain = (PFN_DllMain) + (mempe + winpe_oepval(mempe, 0)); + pfnDllMain((HINSTANCE)mempe, DLL_PROCESS_DETACH, NULL); + return pfnVirtualFree(mempe, 0, MEM_FREE); } WINPEDEF WINPE_EXPORT @@ -390,26 +544,109 @@ inline PROC STDCALL winpe_memGetProcAddress( WINPEDEF WINPE_EXPORT inline void* winpe_findkernel32() { + // return (void*)LoadLibrary("kernel32.dll"); + // TEB->PEB->Ldr->InMemoryOrderLoadList->curProgram->ntdll->kernel32 + void *kerenl32 = NULL; +#ifdef _WIN64 + __asm{ + mov rax, gs:[60h]; peb + mov rax, [rax+18h]; ldr + mov rax, [rax+20h]; InMemoryOrderLoadList, currentProgramEntry + mov rax, [rax]; ntdllEntry, currentProgramEntry->->Flink + mov rax, [rax]; kernel32Entry, ntdllEntry->Flink + mov rax, [rax-10h+30h]; kernel32.DllBase + mov kerenl32, rax; + } +#else + __asm{ + mov eax, fs:[30h]; peb + mov eax, [eax+0ch]; ldr + mov eax, [eax+14h]; InMemoryOrderLoadList, currentProgramEntry + mov eax, [eax]; ntdllEntry, currentProgramEntry->->Flink + mov eax, [eax]; kernel32Entry, ntdllEntry->Flink + mov eax, [eax - 8h +18h]; kernel32.DllBase + mov kerenl32, eax; + } +#endif + return kerenl32; +} + +WINPEDEF WINPE_EXPORT +inline void* STDCALL winpe_findmodulea(char *modulename) +{ + PPEB_LDR_DATA ldr = NULL; + PLDR_DATA_TABLE_ENTRY ldrentry = NULL; +#ifdef _WIN64 + __asm{ + mov rax, gs:[60h]; peb + mov rax, [rax+18h]; ldr + mov ldr, rax + } +#else + __asm{ + mov eax, fs:[30h]; peb + mov eax, [eax+0ch]; ldr + mov ldr, eax; + } +#endif + // InMemoryOrderModuleList is the second entry + ldrentry = (PLDR_DATA_TABLE_ENTRY)((size_t) + ldr->InMemoryOrderModuleList.Flink - 2*sizeof(size_t)); + while(ldrentry->InMemoryOrderLinks.Flink != + ldr->InMemoryOrderModuleList.Flink) + { + PUNICODE_STRING ustr = &ldrentry->FullDllName; + int i; + for(i=ustr->MaximumLength/2-1; i>0 && ustr->Buffer[i]!='\\';i--); + if(ustr->Buffer[i]=='\\') i++; + if(_inl_stricmp2(modulename, ustr->Buffer + i)==0) + { + return ldrentry->DllBase; + } + ldrentry = (PLDR_DATA_TABLE_ENTRY)((size_t) + ldrentry->InMemoryOrderLinks.Flink - 2*sizeof(size_t)); + } return NULL; } WINPEDEF WINPE_EXPORT inline PROC winpe_findloadlibrarya() { - return NULL; + // return (PROC)LoadLibraryA; + HMODULE hmod_kernel32 = (HMODULE)winpe_findkernel32(); + char name_LoadLibraryA[] = {'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0'}; + return (PROC)winpe_memfindexp( // suppose exp no forward, to avoid recursive + (void*)hmod_kernel32, name_LoadLibraryA); } WINPEDEF WINPE_EXPORT inline PROC winpe_findgetprocaddress() { - return NULL; + // return (PROC)GetProcAddress; + HMODULE hmod_kernel32 = (HMODULE)winpe_findkernel32(); + char name_GetProcAddress[] = {'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', '\0'}; + return winpe_memGetProcAddress(hmod_kernel32, name_GetProcAddress); } WINPEDEF WINPE_EXPORT inline void* winpe_findspace( - size_t imagebase, size_t imagesize, + size_t imagebase, size_t imagesize, size_t alignsize, PFN_VirtualQuery pfnVirtualQuery) { +#define MAX_QUERY 0x1000 + size_t addr = imagebase; + MEMORY_BASIC_INFORMATION minfo; + for (int i=0;i= imagesize) + return (void*)addr; + addr += minfo.RegionSize; + } return NULL; } @@ -546,8 +783,11 @@ inline size_t winpe_membindiat(void *mempe, PIMAGE_IMPORT_BY_NAME pImpByName = NULL; // origin GetProcAddress will crash at InitializeSListHead - if(!pfnLoadLibraryA) pfnLoadLibraryA = LoadLibraryA; - if(!pfnGetProcAddress) pfnGetProcAddress = GetProcAddress; + if(!pfnLoadLibraryA) pfnLoadLibraryA = + (PFN_LoadLibraryA)winpe_findloadlibrarya(); + if(!pfnGetProcAddress) pfnGetProcAddress = + (PFN_GetProcAddress)winpe_findgetprocaddress(); + DWORD iat_count = 0; for (; pImpDescriptor->Name; pImpDescriptor++) { @@ -567,8 +807,8 @@ inline size_t winpe_membindiat(void *mempe, pOftThunk[j].u1.AddressOfData); size_t addr = (size_t)pfnGetProcAddress( (HMODULE)dllbase, pImpByName->Name); - addr = (size_t)winpe_memforwardexp((void*)dllbase, - addr-dllbase, pfnLoadLibraryA, pfnGetProcAddress); + // addr = (size_t)winpe_memforwardexp((void*)dllbase, + // addr-dllbase, pfnLoadLibraryA, pfnGetProcAddress); if(!addr) continue; pFtThunk[j].u1.Function = addr; assert(addr == (size_t)GetProcAddress( @@ -760,6 +1000,19 @@ inline size_t winpe_imagebaseval(void *pe, size_t newimagebase) return imagebase; } +WINPEDEF WINPE_EXPORT +inline size_t winpe_imagesizeval(void *pe, size_t newimagesize) +{ + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe; + PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS) + ((void*)pe + pDosHeader->e_lfanew); + PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader; + PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader; + size_t imagesize = pOptHeader->SizeOfImage; + if(newimagesize) pOptHeader->SizeOfImage = newimagesize; + return imagesize; +} + WINPEDEF WINPE_EXPORT inline size_t winpe_appendsecth(void *pe, PIMAGE_SECTION_HEADER psecth)