Skip to content

Commit

Permalink
v0.3.2, add support for ordinal iat and tls
Browse files Browse the repository at this point in the history
  • Loading branch information
devseed committed Mar 23, 2022
1 parent 0bbbf64 commit b620e52
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 109 deletions.
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -117,12 +118,24 @@ 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.
## 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
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
130 changes: 54 additions & 76 deletions src/memdll/win_injectmemdll.c
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
Expand All @@ -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]
Expand Down Expand Up @@ -147,11 +123,13 @@ int injectdll_mem(const char *exepath,
winpe_appendsecth(mempe_exe, &secth);

// 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
Expand Down Expand Up @@ -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];
Expand Down
77 changes: 48 additions & 29 deletions src/memdll/win_injectmemdll_shellcodestub.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion util
Submodule util updated from 9aad6f to 38cbf3

0 comments on commit b620e52

Please sign in to comment.