diff --git a/README.md b/README.md index cdfa32d..c2b5378 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ A tool to parse and load module in memory, as well as attach a DLL in EXE. Most of the functions are inline, so that it can also be used in shellcode. -This project is tested on `windows xp `, `windows 7`, `windows 10`, `windows 11`. +This project is tested on `windows xp `, `windows 7`, `windows 10`, `windows 11`, +also the attached exe file packed by upx is tested. ## compile @@ -117,6 +118,13 @@ inline size_t winpe_memreloc(void *mempe, size_t newimagebase); inline size_t winpe_membindiat(void *mempe, PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress); + +/* + exec the tls callbacks for the mempe, before dll oep load + reason is for function PIMAGE_TLS_CALLBACK + return tls count +*/ +inline size_t winpe_membindtls(void *mempe, DWORD reason); ``` See `winpe.h` for parsing and loading PE structure in detail. @@ -124,5 +132,10 @@ See `winpe.h` for parsing and loading PE structure in detail. ## known issues * ~~attach x64 DLL to exe crash on calling some windows API~~ - problem occured by `movaps xmm0, xmmword ptr ss:[rsp]` - fixed by stack memory align with 0x10 \ No newline at end of file + problem occured by `movaps xmm0, xmmword ptr ss:[rsp]` + fixed by stack memory align with 0x10 + +## todo + +* ~~TLS initialize support~~ finished, but not tested, because I didn't find DLL with TLS example. +* support ASLR \ No newline at end of file diff --git a/src/memdll/win_injectmemdll.c b/src/memdll/win_injectmemdll.c index d39e6a5..88628f2 100644 --- a/src/memdll/win_injectmemdll.c +++ b/src/memdll/win_injectmemdll.c @@ -1,10 +1,9 @@ /* a tool to attach a dll inside a pe file - v0.3, developed by devseed + v0.3.2, developed by devseed history: - v0.2, support for x86 - v0.3, add test part, support for x64, optimizing code structure + see win_injectmemdll_shellcodestub.py */ #include @@ -22,89 +21,66 @@ unsigned char g_oepinit_code[] = {0x90}; unsigned char g_memreloc_code[] = {0x90}; unsigned char g_membindiat_code[] = {0x90}; +unsigned char g_membindtls_code[] = {0x90}; unsigned char g_findloadlibrarya_code[] = {0x90}; -unsigned char g_memGetProcAddress_code[] = {0x90}; +unsigned char g_findgetprocaddress_code[] = {0x90}; -size_t _sectpaddingsize(void *mempe, void *mempe_dll, size_t align) +void _makeoepcode(void *shellcode, + size_t shellcodebase, size_t exeimagebase, size_t dllimagebase, + DWORD exeoeprva, DWORD dlloeprva) { - 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, - size_t shellcodebase, size_t dllimagebase, DWORD orgoeprva) -{ - // PE struct declear - void *mempe; - PIMAGE_DOS_HEADER pDosHeader; - PIMAGE_NT_HEADERS pNtHeader; - PIMAGE_FILE_HEADER pFileHeader; - PIMAGE_OPTIONAL_HEADER pOptHeader; - PIMAGE_DATA_DIRECTORY pDataDirectory; - PIMAGE_DATA_DIRECTORY pImpEntry; - PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor; - PIMAGE_THUNK_DATA pFtThunk = NULL; - PIMAGE_THUNK_DATA pOftThunk = NULL; - LPCSTR pDllName = NULL; - PIMAGE_IMPORT_BY_NAME pFuncName = NULL; - // bind the pointer to buffer size_t oepinit_end = sizeof(g_oepinit_code); 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 membindiat_start = memreloc_start + FUNC_SIZE; + size_t membindtls_start = membindiat_start + FUNC_SIZE; + size_t findloadlibrarya_start = membindtls_start + FUNC_SIZE; + size_t findgetprocaddress_start = findloadlibrarya_start + FUNC_SIZE; + + // fill the address table + size_t *pexeoepva = (size_t*)(g_oepinit_code + oepinit_end - 8*sizeof(size_t)); + size_t *pdllbase = (size_t*)(g_oepinit_code + oepinit_end - 7*sizeof(size_t)); + size_t *pdlloepva = (size_t*)(g_oepinit_code + oepinit_end - 6*sizeof(size_t)); + size_t *pmemreloc = (size_t*)(g_oepinit_code + oepinit_end - 5*sizeof(size_t)); + size_t *pmembindiat = (size_t*)(g_oepinit_code + oepinit_end - 4*sizeof(size_t)); + size_t *pmembindtls = (size_t*)(g_oepinit_code + oepinit_end - 3*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; - pDosHeader = (PIMAGE_DOS_HEADER)mempe; - pNtHeader = (PIMAGE_NT_HEADERS)((void*)mempe + pDosHeader->e_lfanew); - pFileHeader = &pNtHeader->FileHeader; - pOptHeader = &pNtHeader->OptionalHeader; - pDataDirectory = pOptHeader->DataDirectory; - pImpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - pImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(mempe + pImpEntry->VirtualAddress); - size_t exeimagebase = pOptHeader->ImageBase; - - // get the information of dll - mempe = mempe_dll; - pDosHeader = (PIMAGE_DOS_HEADER)mempe; - pNtHeader = (PIMAGE_NT_HEADERS)((void*)mempe + pDosHeader->e_lfanew); - pFileHeader = &pNtHeader->FileHeader; - pOptHeader = &pNtHeader->OptionalHeader; - pDataDirectory = pOptHeader->DataDirectory; - DWORD dlloeprva = pOptHeader->AddressOfEntryPoint; - - // fill the address table - *pexeoepva = exeimagebase + orgoeprva; + size_t *pfindgetprocaddress = (size_t*)(g_oepinit_code + oepinit_end - 1*sizeof(size_t)); + *pexeoepva = exeimagebase + exeoeprva; *pdllbase = dllimagebase; - *pdlloepva = dllimagebase + pOptHeader->AddressOfEntryPoint; - *pmemiatbind = shellcodebase + memiatbind_start; - *pfindloadlibrarya = shellcodebase + memfindloadlibrarya_start; - *pgetprocessaddress = shellcodebase + memGetProcAddress_start; + *pdlloepva = dllimagebase + dlloeprva; + *pmemreloc = shellcodebase + memreloc_start; + *pmembindiat = shellcodebase + membindiat_start; + *pmembindtls = shellcodebase + membindtls_start; + *pfindloadlibrarya = shellcodebase + findloadlibrarya_start; + *pfindgetprocaddress = shellcodebase + findgetprocaddress_start; // copy to the target - memcpy(shellcode , g_oepinit_code, sizeof(g_oepinit_code)); + memcpy(shellcode , + g_oepinit_code, sizeof(g_oepinit_code)); memcpy(shellcode + memreloc_start, g_memreloc_code, sizeof(g_memreloc_code)); - memcpy(shellcode + memiatbind_start, + memcpy(shellcode + membindiat_start, g_membindiat_code, sizeof(g_membindiat_code)); - memcpy(shellcode + memfindloadlibrarya_start, + memcpy(shellcode + membindtls_start, + g_membindtls_code, sizeof(g_membindtls_code)); + memcpy(shellcode + findloadlibrarya_start, g_findloadlibrarya_code, sizeof(g_findloadlibrarya_code)); - memcpy(shellcode + memGetProcAddress_start, - g_memGetProcAddress_code, sizeof(g_memGetProcAddress_code)); + memcpy(shellcode + findgetprocaddress_start, + g_findgetprocaddress_code, sizeof(g_findgetprocaddress_code)); +} + + +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; } // memory structure: [exe sections], [shellcode, padding, dll] @@ -147,11 +123,13 @@ int injectdll_mem(const char *exepath, winpe_appendsecth(mempe_exe, §h); // adjust dll addr and append shellcode, iatbind is in runing - DWORD orgoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress); size_t shellcodebase = imgbase_exe + secth.VirtualAddress; size_t dllimagebase = shellcodebase + SHELLCODE_SIZE + padding; - _oepshellcode(mempe_exe, mempe_dll, shellcode, - shellcodebase, dllimagebase, orgoeprva); + size_t exeimagebase = winpe_imagebaseval(mempe_exe, 0); + DWORD dlloeprva = winpe_oepval(mempe_dll, 0); + DWORD exeoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress); + _makeoepcode(shellcode, shellcodebase, + exeimagebase, dllimagebase, exeoeprva, dlloeprva); winpe_memreloc(mempe_dll, dllimagebase); // write data to new exe @@ -230,7 +208,7 @@ int main(int argc, char *argv[]) if(argc < 3) { printf("usage: win_injectmemdll exepath dllpath [outpath]\n"); - printf("v0.2, developed by devseed\n"); + printf("v0.3.2, developed by devseed\n"); return 0; } char outpath[MAX_PATH]; diff --git a/src/memdll/win_injectmemdll_shellcodestub.py b/src/memdll/win_injectmemdll_shellcodestub.py index c99d49b..a2e0ddc 100644 --- a/src/memdll/win_injectmemdll_shellcodestub.py +++ b/src/memdll/win_injectmemdll_shellcodestub.py @@ -1,12 +1,13 @@ """ this file is for automaticly generate some shellcodes stub informations - v0.3, developed by devseed + v0.3.2, 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 v0.3.1, fix x64 attach dll crash by align stack with 0x10 + v0.3.2, add support for ordinal iat and tls """ import re import sys @@ -20,27 +21,33 @@ def gen_oepinit_code32(): call geteip; lea ebx, [eax-5]; + // get loadlibrarya, getprocaddress + call [ebx + findloadlibrarya]; + mov [ebx + findloadlibrarya], eax; + call [ebx + findgetprocaddress]; + mov [ebx + findgetprocaddress], eax; + // bind iat - lea eax, [ebx + getprocessaddress]; - mov eax, [eax]; - push eax; - lea eax, [ebx + findloadlibrarya]; - call [eax]; - push eax; - lea eax, [ebx + dllbase]; // dllbase addr - mov eax, [eax]; // dllbase value - push eax; - call [ebx + memiatbind]; + push [ebx + findgetprocaddress]; // arg3, getprocaddress + push [ebx + findloadlibrarya]; // arg2, loadlibraryas + push [ebx + dllbase]; // arg1, dllbase value + call [ebx + membindiat]; add esp, 0xc; + + // bind tls + xor edx, edx; + inc edx; // arg2, reason for tls + push edx; + push [ebx + dllbase] // arg1, dllbase + call [ebx + membindtls] + add esp, 0x8; // call dll oep, for dll entry xor eax, eax; push eax; // lpvReserved inc eax; push eax; // fdwReason, DLL_PROCESS_ATTACH - lea eax, [ebx + dllbase]; - mov eax, [eax]; - push eax; // hinstDLL + push [ebx + dllbase]; // hinstDLL call [ebx+dlloepva]; // jmp to origin oep @@ -53,9 +60,11 @@ def gen_oepinit_code32(): exeoepva: nop;nop;nop;nop; dllbase: nop;nop;nop;nop; dlloepva: nop;nop;nop;nop; - memiatbind: nop;nop;nop;nop; + memreloc: nop;nop;nop;nop; + membindiat: nop;nop;nop;nop; + membindtls: nop;nop;nop;nop; findloadlibrarya: nop;nop;nop;nop; - getprocessaddress: nop;nop;nop;nop; + findgetprocaddress: nop;nop;nop;nop; """ print("gen_oepinit_code32", code_str) payload, _ = ks.asm(code_str) @@ -74,22 +83,29 @@ def gen_oepinit_code64(): push r9; sub rsp, 0x28; // this is for memory 0x10 align + // get loadlibrarya, getprocaddress + call [rbx + findloadlibrarya]; + mov [rbx + findloadlibrarya], rax; + call [rbx + findgetprocaddress]; + mov [rbx + findgetprocaddress], rax; + // bind iat - 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]; + mov r8, [rbx + findgetprocaddress]; // arg3, getprocaddress + mov rdx, [rbx + findloadlibrarya]; // arg2, loadlibraryas + mov rcx, [rbx + dllbase]; // arg1, dllbase value + call [rbx + membindiat]; + + // bind tls + xor rdx, rdx; + inc rdx; // argc, reason for tls + mov rcx, [rbx + dllbase] // arg1, dllbase + call [rbx + membindtls] // call dll oep, for dll entry xor r8, r8; // lpvReserved xor rdx, rdx; inc rdx; // fdwReason, DLL_PROCESS_ATTACH - lea rcx, [rbx + dllbase]; - mov rcx, [rcx]; // hinstDLL + mov rcx, [rbx + dllbase]; // hinstDLL call [rbx+dlloepva]; // jmp to origin oep @@ -107,9 +123,11 @@ def gen_oepinit_code64(): exeoepva: nop;nop;nop;nop;nop;nop;nop;nop; 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; + memreloc: nop;nop;nop;nop;nop;nop;nop;nop; + membindiat: nop;nop;nop;nop;nop;nop;nop;nop; + membindtls: 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; + findgetprocaddress: nop;nop;nop;nop;nop;nop;nop;nop; """ print("gen_oepinit_code64", code_str) payload, _ = ks.asm(code_str) @@ -136,8 +154,9 @@ def inject_shellcodestubs(srcpath, libwinpepath, targetpath): FUNC_SIZE =0x400 codes = {"winpe_memreloc": 0, "winpe_membindiat": 0, + "winpe_membindtls": 0, "winpe_findloadlibrarya": 0, - "winpe_memGetProcAddress": 0} + "winpe_findgetprocaddress": 0} for k in codes.keys(): func = next(filter(lambda e : e.name == k, pedll.exported_functions)) diff --git a/util b/util index 9aad6f9..38cbf3a 160000 --- a/util +++ b/util @@ -1 +1 @@ -Subproject commit 9aad6f95f3959c267eb5909946b9fcc68d93efdb +Subproject commit 38cbf3a320db26b58f9d07b53daa214cb2a0b361