Skip to content

Commit b620e52

Browse files
author
devseed
committed
v0.3.2, add support for ordinal iat and tls
1 parent 0bbbf64 commit b620e52

4 files changed

Lines changed: 119 additions & 109 deletions

File tree

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
A tool to parse and load module in memory, as well as attach a DLL in EXE.
33
Most of the functions are inline, so that it can also be used in shellcode.
44

5-
This project is tested on `windows xp `, `windows 7`, `windows 10`, `windows 11`.
5+
This project is tested on `windows xp `, `windows 7`, `windows 10`, `windows 11`,
6+
also the attached exe file packed by upx is tested.
67

78
## compile
89

@@ -117,12 +118,24 @@ inline size_t winpe_memreloc(void *mempe, size_t newimagebase);
117118
inline size_t winpe_membindiat(void *mempe,
118119
PFN_LoadLibraryA pfnLoadLibraryA,
119120
PFN_GetProcAddress pfnGetProcAddress);
121+
122+
/*
123+
exec the tls callbacks for the mempe, before dll oep load
124+
reason is for function PIMAGE_TLS_CALLBACK
125+
return tls count
126+
*/
127+
inline size_t winpe_membindtls(void *mempe, DWORD reason);
120128
```
121129
122130
See `winpe.h` for parsing and loading PE structure in detail.
123131
124132
## known issues
125133
126134
* ~~attach x64 DLL to exe crash on calling some windows API~~
127-
problem occured by `movaps xmm0, xmmword ptr ss:[rsp]`
128-
fixed by stack memory align with 0x10
135+
problem occured by `movaps xmm0, xmmword ptr ss:[rsp]`
136+
fixed by stack memory align with 0x10
137+
138+
## todo
139+
140+
* ~~TLS initialize support~~ finished, but not tested, because I didn't find DLL with TLS example.
141+
* support ASLR

src/memdll/win_injectmemdll.c

Lines changed: 54 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/*
22
a tool to attach a dll inside a pe file
3-
v0.3, developed by devseed
3+
v0.3.2, developed by devseed
44
55
history:
6-
v0.2, support for x86
7-
v0.3, add test part, support for x64, optimizing code structure
6+
see win_injectmemdll_shellcodestub.py
87
*/
98

109
#include <stdio.h>
@@ -22,89 +21,66 @@
2221
unsigned char g_oepinit_code[] = {0x90};
2322
unsigned char g_memreloc_code[] = {0x90};
2423
unsigned char g_membindiat_code[] = {0x90};
24+
unsigned char g_membindtls_code[] = {0x90};
2525
unsigned char g_findloadlibrarya_code[] = {0x90};
26-
unsigned char g_memGetProcAddress_code[] = {0x90};
26+
unsigned char g_findgetprocaddress_code[] = {0x90};
2727

28-
size_t _sectpaddingsize(void *mempe, void *mempe_dll, size_t align)
28+
void _makeoepcode(void *shellcode,
29+
size_t shellcodebase, size_t exeimagebase, size_t dllimagebase,
30+
DWORD exeoeprva, DWORD dlloeprva)
2931
{
30-
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
31-
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)
32-
((void*)mempe + pDosHeader->e_lfanew);
33-
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
34-
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
35-
size_t _v = (pOptHeader->SizeOfImage + SHELLCODE_SIZE) % align;
36-
if (_v) return align - _v;
37-
else return 0;
38-
}
39-
40-
void _oepshellcode(void *mempe_exe, void *mempe_dll, void *shellcode,
41-
size_t shellcodebase, size_t dllimagebase, DWORD orgoeprva)
42-
{
43-
// PE struct declear
44-
void *mempe;
45-
PIMAGE_DOS_HEADER pDosHeader;
46-
PIMAGE_NT_HEADERS pNtHeader;
47-
PIMAGE_FILE_HEADER pFileHeader;
48-
PIMAGE_OPTIONAL_HEADER pOptHeader;
49-
PIMAGE_DATA_DIRECTORY pDataDirectory;
50-
PIMAGE_DATA_DIRECTORY pImpEntry;
51-
PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor;
52-
PIMAGE_THUNK_DATA pFtThunk = NULL;
53-
PIMAGE_THUNK_DATA pOftThunk = NULL;
54-
LPCSTR pDllName = NULL;
55-
PIMAGE_IMPORT_BY_NAME pFuncName = NULL;
56-
5732
// bind the pointer to buffer
5833
size_t oepinit_end = sizeof(g_oepinit_code);
5934
size_t memreloc_start = FUNC_SIZE;
60-
size_t memiatbind_start = memreloc_start + FUNC_SIZE;
61-
size_t memfindloadlibrarya_start = memiatbind_start + FUNC_SIZE;
62-
size_t memGetProcAddress_start = memfindloadlibrarya_start + FUNC_SIZE;
63-
size_t *pexeoepva = (size_t*)(g_oepinit_code + oepinit_end - 6*sizeof(size_t));
64-
size_t *pdllbase = (size_t*)(g_oepinit_code + oepinit_end - 5*sizeof(size_t));
65-
size_t *pdlloepva = (size_t*)(g_oepinit_code + oepinit_end - 4*sizeof(size_t));
66-
size_t *pmemiatbind = (size_t*)(g_oepinit_code + oepinit_end - 3*sizeof(size_t));
35+
size_t membindiat_start = memreloc_start + FUNC_SIZE;
36+
size_t membindtls_start = membindiat_start + FUNC_SIZE;
37+
size_t findloadlibrarya_start = membindtls_start + FUNC_SIZE;
38+
size_t findgetprocaddress_start = findloadlibrarya_start + FUNC_SIZE;
39+
40+
// fill the address table
41+
size_t *pexeoepva = (size_t*)(g_oepinit_code + oepinit_end - 8*sizeof(size_t));
42+
size_t *pdllbase = (size_t*)(g_oepinit_code + oepinit_end - 7*sizeof(size_t));
43+
size_t *pdlloepva = (size_t*)(g_oepinit_code + oepinit_end - 6*sizeof(size_t));
44+
size_t *pmemreloc = (size_t*)(g_oepinit_code + oepinit_end - 5*sizeof(size_t));
45+
size_t *pmembindiat = (size_t*)(g_oepinit_code + oepinit_end - 4*sizeof(size_t));
46+
size_t *pmembindtls = (size_t*)(g_oepinit_code + oepinit_end - 3*sizeof(size_t));
6747
size_t *pfindloadlibrarya = (size_t*)(g_oepinit_code + oepinit_end - 2*sizeof(size_t));
68-
size_t *pgetprocessaddress = (size_t*)(g_oepinit_code + oepinit_end - 1*sizeof(size_t));
69-
70-
// get the information of exe
71-
mempe = mempe_exe;
72-
pDosHeader = (PIMAGE_DOS_HEADER)mempe;
73-
pNtHeader = (PIMAGE_NT_HEADERS)((void*)mempe + pDosHeader->e_lfanew);
74-
pFileHeader = &pNtHeader->FileHeader;
75-
pOptHeader = &pNtHeader->OptionalHeader;
76-
pDataDirectory = pOptHeader->DataDirectory;
77-
pImpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
78-
pImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(mempe + pImpEntry->VirtualAddress);
79-
size_t exeimagebase = pOptHeader->ImageBase;
80-
81-
// get the information of dll
82-
mempe = mempe_dll;
83-
pDosHeader = (PIMAGE_DOS_HEADER)mempe;
84-
pNtHeader = (PIMAGE_NT_HEADERS)((void*)mempe + pDosHeader->e_lfanew);
85-
pFileHeader = &pNtHeader->FileHeader;
86-
pOptHeader = &pNtHeader->OptionalHeader;
87-
pDataDirectory = pOptHeader->DataDirectory;
88-
DWORD dlloeprva = pOptHeader->AddressOfEntryPoint;
89-
90-
// fill the address table
91-
*pexeoepva = exeimagebase + orgoeprva;
48+
size_t *pfindgetprocaddress = (size_t*)(g_oepinit_code + oepinit_end - 1*sizeof(size_t));
49+
*pexeoepva = exeimagebase + exeoeprva;
9250
*pdllbase = dllimagebase;
93-
*pdlloepva = dllimagebase + pOptHeader->AddressOfEntryPoint;
94-
*pmemiatbind = shellcodebase + memiatbind_start;
95-
*pfindloadlibrarya = shellcodebase + memfindloadlibrarya_start;
96-
*pgetprocessaddress = shellcodebase + memGetProcAddress_start;
51+
*pdlloepva = dllimagebase + dlloeprva;
52+
*pmemreloc = shellcodebase + memreloc_start;
53+
*pmembindiat = shellcodebase + membindiat_start;
54+
*pmembindtls = shellcodebase + membindtls_start;
55+
*pfindloadlibrarya = shellcodebase + findloadlibrarya_start;
56+
*pfindgetprocaddress = shellcodebase + findgetprocaddress_start;
9757

9858
// copy to the target
99-
memcpy(shellcode , g_oepinit_code, sizeof(g_oepinit_code));
59+
memcpy(shellcode ,
60+
g_oepinit_code, sizeof(g_oepinit_code));
10061
memcpy(shellcode + memreloc_start,
10162
g_memreloc_code, sizeof(g_memreloc_code));
102-
memcpy(shellcode + memiatbind_start,
63+
memcpy(shellcode + membindiat_start,
10364
g_membindiat_code, sizeof(g_membindiat_code));
104-
memcpy(shellcode + memfindloadlibrarya_start,
65+
memcpy(shellcode + membindtls_start,
66+
g_membindtls_code, sizeof(g_membindtls_code));
67+
memcpy(shellcode + findloadlibrarya_start,
10568
g_findloadlibrarya_code, sizeof(g_findloadlibrarya_code));
106-
memcpy(shellcode + memGetProcAddress_start,
107-
g_memGetProcAddress_code, sizeof(g_memGetProcAddress_code));
69+
memcpy(shellcode + findgetprocaddress_start,
70+
g_findgetprocaddress_code, sizeof(g_findgetprocaddress_code));
71+
}
72+
73+
74+
size_t _sectpaddingsize(void *mempe, void *mempe_dll, size_t align)
75+
{
76+
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
77+
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)
78+
((void*)mempe + pDosHeader->e_lfanew);
79+
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
80+
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
81+
size_t _v = (pOptHeader->SizeOfImage + SHELLCODE_SIZE) % align;
82+
if (_v) return align - _v;
83+
else return 0;
10884
}
10985

11086
// memory structure: [exe sections], [shellcode, padding, dll]
@@ -147,11 +123,13 @@ int injectdll_mem(const char *exepath,
147123
winpe_appendsecth(mempe_exe, &secth);
148124

149125
// adjust dll addr and append shellcode, iatbind is in runing
150-
DWORD orgoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress);
151126
size_t shellcodebase = imgbase_exe + secth.VirtualAddress;
152127
size_t dllimagebase = shellcodebase + SHELLCODE_SIZE + padding;
153-
_oepshellcode(mempe_exe, mempe_dll, shellcode,
154-
shellcodebase, dllimagebase, orgoeprva);
128+
size_t exeimagebase = winpe_imagebaseval(mempe_exe, 0);
129+
DWORD dlloeprva = winpe_oepval(mempe_dll, 0);
130+
DWORD exeoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress);
131+
_makeoepcode(shellcode, shellcodebase,
132+
exeimagebase, dllimagebase, exeoeprva, dlloeprva);
155133
winpe_memreloc(mempe_dll, dllimagebase);
156134

157135
// write data to new exe
@@ -230,7 +208,7 @@ int main(int argc, char *argv[])
230208
if(argc < 3)
231209
{
232210
printf("usage: win_injectmemdll exepath dllpath [outpath]\n");
233-
printf("v0.2, developed by devseed\n");
211+
printf("v0.3.2, developed by devseed\n");
234212
return 0;
235213
}
236214
char outpath[MAX_PATH];

src/memdll/win_injectmemdll_shellcodestub.py

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"""
22
this file is for automaticly generate some shellcodes stub informations
3-
v0.3, developed by devseed
3+
v0.3.2, developed by devseed
44
55
history:
66
v0.1, initial version
77
v0.2, add more function for shellcode
88
v0.3, x86 and x64 no need to use exe's LoadLibraryA
99
v0.3.1, fix x64 attach dll crash by align stack with 0x10
10+
v0.3.2, add support for ordinal iat and tls
1011
"""
1112
import re
1213
import sys
@@ -20,27 +21,33 @@ def gen_oepinit_code32():
2021
call geteip;
2122
lea ebx, [eax-5];
2223
24+
// get loadlibrarya, getprocaddress
25+
call [ebx + findloadlibrarya];
26+
mov [ebx + findloadlibrarya], eax;
27+
call [ebx + findgetprocaddress];
28+
mov [ebx + findgetprocaddress], eax;
29+
2330
// bind iat
24-
lea eax, [ebx + getprocessaddress];
25-
mov eax, [eax];
26-
push eax;
27-
lea eax, [ebx + findloadlibrarya];
28-
call [eax];
29-
push eax;
30-
lea eax, [ebx + dllbase]; // dllbase addr
31-
mov eax, [eax]; // dllbase value
32-
push eax;
33-
call [ebx + memiatbind];
31+
push [ebx + findgetprocaddress]; // arg3, getprocaddress
32+
push [ebx + findloadlibrarya]; // arg2, loadlibraryas
33+
push [ebx + dllbase]; // arg1, dllbase value
34+
call [ebx + membindiat];
3435
add esp, 0xc;
36+
37+
// bind tls
38+
xor edx, edx;
39+
inc edx; // arg2, reason for tls
40+
push edx;
41+
push [ebx + dllbase] // arg1, dllbase
42+
call [ebx + membindtls]
43+
add esp, 0x8;
3544
3645
// call dll oep, for dll entry
3746
xor eax, eax;
3847
push eax; // lpvReserved
3948
inc eax;
4049
push eax; // fdwReason, DLL_PROCESS_ATTACH
41-
lea eax, [ebx + dllbase];
42-
mov eax, [eax];
43-
push eax; // hinstDLL
50+
push [ebx + dllbase]; // hinstDLL
4451
call [ebx+dlloepva];
4552
4653
// jmp to origin oep
@@ -53,9 +60,11 @@ def gen_oepinit_code32():
5360
exeoepva: nop;nop;nop;nop;
5461
dllbase: nop;nop;nop;nop;
5562
dlloepva: nop;nop;nop;nop;
56-
memiatbind: nop;nop;nop;nop;
63+
memreloc: nop;nop;nop;nop;
64+
membindiat: nop;nop;nop;nop;
65+
membindtls: nop;nop;nop;nop;
5766
findloadlibrarya: nop;nop;nop;nop;
58-
getprocessaddress: nop;nop;nop;nop;
67+
findgetprocaddress: nop;nop;nop;nop;
5968
"""
6069
print("gen_oepinit_code32", code_str)
6170
payload, _ = ks.asm(code_str)
@@ -74,22 +83,29 @@ def gen_oepinit_code64():
7483
push r9;
7584
sub rsp, 0x28; // this is for memory 0x10 align
7685
86+
// get loadlibrarya, getprocaddress
87+
call [rbx + findloadlibrarya];
88+
mov [rbx + findloadlibrarya], rax;
89+
call [rbx + findgetprocaddress];
90+
mov [rbx + findgetprocaddress], rax;
91+
7792
// bind iat
78-
lea rdx, [rbx + findloadlibrarya];
79-
call [rdx];
80-
mov rdx, rax; // arg2, loadlibraryas
81-
lea r8, [rbx + getprocessaddress];
82-
mov r8, [r8]; // arg3, getprocaddress
83-
lea rcx, [rbx + dllbase];
84-
mov rcx, [rcx]; // arg1, dllbase value
85-
call [rbx + memiatbind];
93+
mov r8, [rbx + findgetprocaddress]; // arg3, getprocaddress
94+
mov rdx, [rbx + findloadlibrarya]; // arg2, loadlibraryas
95+
mov rcx, [rbx + dllbase]; // arg1, dllbase value
96+
call [rbx + membindiat];
97+
98+
// bind tls
99+
xor rdx, rdx;
100+
inc rdx; // argc, reason for tls
101+
mov rcx, [rbx + dllbase] // arg1, dllbase
102+
call [rbx + membindtls]
86103
87104
// call dll oep, for dll entry
88105
xor r8, r8; // lpvReserved
89106
xor rdx, rdx;
90107
inc rdx; // fdwReason, DLL_PROCESS_ATTACH
91-
lea rcx, [rbx + dllbase];
92-
mov rcx, [rcx]; // hinstDLL
108+
mov rcx, [rbx + dllbase]; // hinstDLL
93109
call [rbx+dlloepva];
94110
95111
// jmp to origin oep
@@ -107,9 +123,11 @@ def gen_oepinit_code64():
107123
exeoepva: nop;nop;nop;nop;nop;nop;nop;nop;
108124
dllbase: nop;nop;nop;nop;nop;nop;nop;nop;
109125
dlloepva: nop;nop;nop;nop;nop;nop;nop;nop;
110-
memiatbind: nop;nop;nop;nop;nop;nop;nop;nop;
126+
memreloc: nop;nop;nop;nop;nop;nop;nop;nop;
127+
membindiat: nop;nop;nop;nop;nop;nop;nop;nop;
128+
membindtls: nop;nop;nop;nop;nop;nop;nop;nop;
111129
findloadlibrarya: nop;nop;nop;nop;nop;nop;nop;nop;
112-
getprocessaddress: nop;nop;nop;nop;nop;nop;nop;nop;
130+
findgetprocaddress: nop;nop;nop;nop;nop;nop;nop;nop;
113131
"""
114132
print("gen_oepinit_code64", code_str)
115133
payload, _ = ks.asm(code_str)
@@ -136,8 +154,9 @@ def inject_shellcodestubs(srcpath, libwinpepath, targetpath):
136154
FUNC_SIZE =0x400
137155
codes = {"winpe_memreloc": 0,
138156
"winpe_membindiat": 0,
157+
"winpe_membindtls": 0,
139158
"winpe_findloadlibrarya": 0,
140-
"winpe_memGetProcAddress": 0}
159+
"winpe_findgetprocaddress": 0}
141160
for k in codes.keys():
142161
func = next(filter(lambda e : e.name == k,
143162
pedll.exported_functions))

util

Submodule util updated from 9aad6f9 to 38cbf3a

0 commit comments

Comments
 (0)