Skip to content

Commit b87e84f

Browse files
author
devseed
committed
change winpe function to inline
1 parent 68510bc commit b87e84f

6 files changed

Lines changed: 544 additions & 165 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ src/**/screenshot/*
1414
src/**/release/*
1515
src/**/debug/*
1616
src/**/bin/*
17+
src/**/sample/*
1718
util/asset/**
1819
util/bin/**
1920
util/script/**

src/memdll/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ libwinpe: libwinpe.c
6161
@echo \#\#building $@ ...
6262
$(CC) $< -o $(PREFIX)/$@$(ARCH_POSTFIX)$(DLL_EXT) \
6363
-shared $(CFLAGS) $(LDFLAGS) $(INCS) $(LIBS) $(LIBDIRS)
64-
rm -rf $(PREFIX)/*.exp
6564

6665
win_injectmemdll_shellcodestub: win_injectmemdll.c libwinpe
6766
python $@.py $< \
@@ -73,6 +72,7 @@ win_injectmemdll: win_injectmemdll_shellcodestub libwinpe
7372
$(CC) $(PREFIX)/_$(ARCH_POSTFIX)$@.c \
7473
-o $(PREFIX)/$@$(ARCH_POSTFIX)$(EXE_EXT)\
7574
-llibwinpe$(ARCH_POSTFIX) \
75+
-Wno-undefined-inline \
7676
$(CFLAGS) $(LDFLAGS) $(INCS) $(LIBS) $(LIBDIRS)
7777

7878
.PHONY: all clean prepare libwinpe win_injectmemdll

src/memdll/libwinpe.def

Whitespace-only changes.

src/memdll/win_injectmemdll.c

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,24 @@
44
*/
55

66
#include <stdio.h>
7+
#include <assert.h>
78
#include "winpe.h"
89

10+
#define DUMP(path, addr, size)\
11+
FILE *_fp = fopen(path, "wb");\
12+
fwrite(addr, 1, size, _fp);\
13+
fclose(_fp)
14+
915
// these functions are stub function, will be filled by python
10-
unsigned char g_oepshellcode[] = {0x90};
11-
unsigned char g_memiatshellcode[] = {0x90};
16+
unsigned char g_oepinit_code[] = {0x90};
17+
unsigned char g_membindiat_code[] = {0x90};
18+
unsigned char g_memfindexp_code[] = {0x90};
1219

1320
void _oepshellcode(void *mempe_exe, void *mempe_dll,
1421
void *shellcode, PIMAGE_SECTION_HEADER psecth, DWORD orgoeprva)
1522
{
1623
// PE struct declear
24+
#define FUNC_SIZE 0x200
1725
void *mempe;
1826
PIMAGE_DOS_HEADER pDosHeader;
1927
PIMAGE_NT_HEADERS pNtHeader;
@@ -28,13 +36,15 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll,
2836
PIMAGE_IMPORT_BY_NAME pFuncName = NULL;
2937

3038
// bind the pointer to buffer
31-
size_t end = sizeof(g_oepshellcode);
32-
size_t *pexeoepva = (size_t*)(g_oepshellcode + end - 6*sizeof(size_t));
33-
size_t *pdllbase = (size_t*)(g_oepshellcode + end - 5*sizeof(size_t));
34-
size_t *pdlloepva = (size_t*)(g_oepshellcode + end - 4*sizeof(size_t));
35-
size_t *pmemiatbind = (size_t*)(g_oepshellcode + end - 3*sizeof(size_t));
36-
size_t *pexeloadlibrarya = (size_t*)(g_oepshellcode + end - 2*sizeof(size_t));
37-
size_t *pexegetprocessaddress = (size_t*)(g_oepshellcode + end - 1*sizeof(size_t));
39+
size_t oepinit_end = sizeof(g_oepinit_code);
40+
size_t memiatbind_start = FUNC_SIZE;
41+
size_t memfindexp_start = memiatbind_start + FUNC_SIZE;
42+
size_t *pexeoepva = (size_t*)(g_oepinit_code + oepinit_end - 6*sizeof(size_t));
43+
size_t *pdllbase = (size_t*)(g_oepinit_code + oepinit_end - 5*sizeof(size_t));
44+
size_t *pdlloepva = (size_t*)(g_oepinit_code + oepinit_end - 4*sizeof(size_t));
45+
size_t *pmemiatbind = (size_t*)(g_oepinit_code + oepinit_end - 3*sizeof(size_t));
46+
size_t *pexeloadlibrarya = (size_t*)(g_oepinit_code + oepinit_end - 2*sizeof(size_t));
47+
size_t *pexegetprocessaddress = (size_t*)(g_oepinit_code + oepinit_end - 1*sizeof(size_t));
3848

3949
// get the information of exe
4050
mempe = mempe_exe;
@@ -46,12 +56,8 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll,
4656
pImpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
4757
pImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(mempe + pImpEntry->VirtualAddress);
4858
size_t exeimagebase = pOptHeader->ImageBase;
49-
DWORD exeoeprva = pOptHeader->AddressOfEntryPoint;
50-
DWORD exeloadlibrarya_rva = winpe_memfindiat(
51-
mempe, "kernel32.dll", "LoadLibraryA");
52-
DWORD exegetprocessaddress_rva = winpe_memfindiat(
53-
mempe, "kernel32.dll", "GetProcAddress");
54-
59+
size_t shellcodebase = exeimagebase + psecth->VirtualAddress;
60+
5561
// get the information of dll
5662
mempe = mempe_dll;
5763
pDosHeader = (PIMAGE_DOS_HEADER)mempe;
@@ -65,14 +71,22 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll,
6571
// fill the address table
6672
*pexeoepva = exeimagebase + orgoeprva;
6773
*pdllbase = dllimagebase;
68-
*pdlloepva = dllimagebase + dlloeprva;
69-
*pmemiatbind = exeimagebase + psecth->VirtualAddress + end;
70-
*pexeloadlibrarya = exeimagebase + exeloadlibrarya_rva;
71-
*pexegetprocessaddress = exeimagebase + exegetprocessaddress_rva;
74+
*pdlloepva = dllimagebase + pOptHeader->AddressOfEntryPoint;
75+
*pmemiatbind = shellcodebase + memiatbind_start;
76+
*pexeloadlibrarya = exeimagebase +
77+
(size_t)(winpe_memfindiat(mempe_exe,
78+
"kernel32.dll", "LoadLibraryA") - mempe_exe);
79+
*pexegetprocessaddress = sizeof(size_t) > 4 ?
80+
shellcodebase + memfindexp_start : // x64
81+
exeimagebase + (size_t)(winpe_memfindiat(mempe_exe, // x86
82+
"kernel32.dll", "GetProcAddress") - mempe_exe);
7283

7384
// copy to the target
74-
memcpy(shellcode, g_oepshellcode, sizeof(g_oepshellcode));
75-
memcpy(shellcode + end, g_memiatshellcode, sizeof(g_memiatshellcode));
85+
memcpy(shellcode , g_oepinit_code, sizeof(g_oepinit_code));
86+
memcpy(shellcode + memiatbind_start,
87+
g_membindiat_code, sizeof(g_membindiat_code));
88+
memcpy(shellcode + memfindexp_start,
89+
g_memfindexp_code, sizeof(g_memfindexp_code));
7690
}
7791

7892
int injectdll_mem(const char *exepath,
@@ -111,7 +125,7 @@ int injectdll_mem(const char *exepath,
111125
strcpy((char*)secth.Name, ".module");
112126
winpe_noaslr(mempe_exe);
113127
winpe_appendsecth(mempe_exe, &secth);
114-
DWORD orgoeprva = winpe_setoep(mempe_exe, secth.VirtualAddress);
128+
DWORD orgoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress);
115129
winpe_memreloc(mempe_dll, imgbase_exe + secth.VirtualAddress + SHELLCODE_SIZE);
116130
_oepshellcode(mempe_exe, mempe_dll, shellcode, &secth, orgoeprva);
117131

@@ -129,16 +143,53 @@ int injectdll_mem(const char *exepath,
129143
return 0;
130144
}
131145

132-
int main(int argc, char *argv[])
146+
void test_exp()
133147
{
134-
char outpath[MAX_PATH];
148+
// test loadlibrary, getprocaddress
149+
HMODULE hmod = NULL;
150+
size_t exprva = 0;
151+
size_t expva = 0;
152+
void* func = NULL;
153+
154+
hmod = LoadLibraryA("kernel32.dll");
155+
assert(hmod!=NULL);
156+
expva = (size_t)GetProcAddress(hmod, "LoadLibraryA");
157+
exprva = (size_t)winpe_memfindexp(hmod, "LoadLibraryA") - (size_t)hmod;
158+
func = winpe_memforwardexp(hmod, exprva, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
159+
assert(exprva!=0 && (size_t)func==expva && func!=NULL);
160+
expva = (size_t)GetProcAddress(hmod, "InitializeSListHead");
161+
exprva = (size_t)winpe_memfindexp(hmod, "InitializeSListHead") - (size_t)hmod;
162+
func = winpe_memforwardexp(hmod, exprva, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
163+
assert(exprva!=0 && (size_t)func==expva && func!=NULL);
164+
expva = (size_t)GetProcAddress(hmod, "GetSystemTimeAsFileTime");
165+
exprva = (size_t)winpe_memfindexp(hmod, "GetSystemTimeAsFileTime") - (size_t)hmod;
166+
func = winpe_memforwardexp(hmod, exprva, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
167+
assert(exprva!=0 && (size_t)func==expva && func!=NULL);
168+
}
169+
170+
void test_memdll(char *dllpath)
171+
{
172+
size_t mempesize = 0;
173+
void *mempe = winpe_memload_file(dllpath, &mempesize, TRUE);;
174+
assert(mempe!=0 && mempesize!=0);
175+
winpe_membindiat(mempe, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
176+
winpe_memLoadLibrary(mempe);
177+
free(mempe);
178+
}
179+
180+
int main(int argc, char *argv[])
181+
{
182+
#ifdef _DEBUG
183+
test_exp();
184+
if(argc>3) test_memdll(argv[2]);
185+
#endif
135186
if(argc < 3)
136187
{
137188
printf("usage: win_injectmemdll exepath dllpath [outpath]\n");
138189
printf("v0.2, developed by devseed\n");
139190
return 0;
140191
}
141-
192+
char outpath[MAX_PATH];
142193
if(argc >= 4) strcpy(outpath, argv[3]);
143194
else strcpy(outpath, "out.exe");
144195
return injectdll_mem(argv[1], argv[2], outpath);

src/memdll/win_injectmemdll_shellcodestub.py

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
import lief
88
from keystone import Ks, KS_ARCH_X86, KS_MODE_32, KS_MODE_64
99

10-
def gen_oepshellcode32():
10+
def gen_oepinit_code32():
1111
ks = Ks(KS_ARCH_X86, KS_MODE_32)
1212
code_str = f"""
1313
// for relative address, get the base of addr
1414
call geteip;
1515
lea ebx, [eax-5];
1616
1717
// bind iat
18+
push eax; // rvaaddr = 0
1819
lea eax, [ebx + exegetprocessaddress];
1920
mov eax, [eax]; // iat
2021
mov eax, [eax]; // iat->addr
@@ -27,7 +28,7 @@ def gen_oepshellcode32():
2728
mov eax, [eax]; // dllbase value
2829
push eax;
2930
call [ebx + memiatbind];
30-
add esp, 0xC;
31+
add esp, 0x10;
3132
3233
// call dll oep, for dll entry
3334
xor eax, eax;
@@ -53,12 +54,12 @@ def gen_oepshellcode32():
5354
exeloadlibrarya: nop;nop;nop;nop;
5455
exegetprocessaddress: nop;nop;nop;nop;
5556
"""
56-
print("gen_oepshellcode32", code_str)
57+
print("gen_oepinit_code32", code_str)
5758
payload, _ = ks.asm(code_str)
5859
print("payload: ", [hex(x) for x in payload])
5960
return payload
6061

61-
def gen_oepshellcode64():
62+
def gen_oepinit_code64():
6263
ks = Ks(KS_ARCH_X86, KS_MODE_64)
6364
code_str = f"""
6465
// for relative address, get the base of addr
@@ -71,8 +72,7 @@ def gen_oepshellcode64():
7172
7273
// bind iat
7374
lea r8, [rbx + exegetprocessaddress];
74-
mov r8, [r8]; // iat
75-
mov r8, [r8]; // iat->addr
75+
mov r8, [r8]; // winpe_memfindexp
7676
lea rdx, [rbx + exeloadlibrarya];
7777
mov rdx, [rdx]; // iat
7878
mov rdx, [rdx]; // iat->addr
@@ -106,7 +106,7 @@ def gen_oepshellcode64():
106106
exeloadlibrarya: nop;nop;nop;nop;nop;nop;nop;nop;
107107
exegetprocessaddress: nop;nop;nop;nop;nop;nop;nop;nop;
108108
"""
109-
print("gen_oepshellcode64", code_str)
109+
print("gen_oepinit_code64", code_str)
110110
payload, _ = ks.asm(code_str)
111111
print("payload: ", [hex(x) for x in payload])
112112
return payload
@@ -115,41 +115,58 @@ def gen_oepshellcode64():
115115
def inject_shellcodestubs(srcpath, libwinpepath, targetpath):
116116
pedll = lief.parse(libwinpepath)
117117
pedll_oph = pedll.optional_header
118-
memiatfunc = next(filter(
119-
lambda e : e.name == "winpe_membindiat",
120-
pedll.exported_functions))
121-
memiatshellcode = \
122-
pedll.get_content_from_virtual_address(
123-
memiatfunc.address, 0x200)
124-
# memiatshellcode = memiatshellcode[:memiatshellcode.index(0xC3)+1] # retn
125-
118+
119+
# generate oepint shellcode
126120
if pedll_oph.magic == lief.PE.PE_TYPE.PE32_PLUS:
127-
oepshellcode = gen_oepshellcode64()
121+
oepinit_code = gen_oepinit_code64()
128122
pass
129123
elif pedll_oph.magic == lief.PE.PE_TYPE.PE32:
130-
oepshellcode = gen_oepshellcode32()
124+
oepinit_code = gen_oepinit_code32()
131125
pass
132126
else:
133127
print("error invalid pe magic!", pedll_oph.magic)
134128
return
129+
# if len(oepinit_code) < 0x200: oepinit_code.extend([0x00] * (0x200 - len(oepinit_code)))
130+
131+
# find necessary functions
132+
membindiat_func = next(filter(
133+
lambda e : e.name == "winpe_membindiat",
134+
pedll.exported_functions))
135+
membindiat_code = \
136+
pedll.get_content_from_virtual_address(
137+
membindiat_func.address, 0x200)
138+
# memiatshellcode = memiatshellcode[:memiatshellcode.index(0xC3)+1] # retn
139+
try:
140+
memfindexp_func = next(filter(
141+
lambda e : e.name == "winpe_memfindexp", # x64 stdcall name
142+
pedll.exported_functions))
143+
except StopIteration:
144+
memfindexp_func = next(filter(
145+
lambda e : e.name == "_winpe_memfindexp@8", # x86 stdcall name
146+
pedll.exported_functions))
147+
memfindexp_code = \
148+
pedll.get_content_from_virtual_address(
149+
memfindexp_func.address, 0x200)
135150

151+
# write shellcode to c source file
136152
with open(srcpath, "rb") as fp:
137153
srctext = fp.read().decode('utf8')
138-
139-
_codetext = ",".join([hex(x) for x in oepshellcode])
140-
srctext = re.sub(r"g_oepshellcode(.+?)(\{0x90\})",
141-
r"g_oepshellcode\1{" + _codetext +"}", srctext)
142-
_codetext = ",".join([hex(x) for x in memiatshellcode])
143-
srctext = re.sub(r"g_memiatshellcode(.+?)(\{0x90\})",
144-
r"g_memiatshellcode\1{" + _codetext +"}", srctext)
145-
154+
_codetext = ",".join([hex(x) for x in oepinit_code])
155+
srctext = re.sub(r"g_oepinit_code(.+?)(\{0x90\})",
156+
r"g_oepinit_code\1{" + _codetext +"}", srctext)
157+
_codetext = ",".join([hex(x) for x in membindiat_code])
158+
srctext = re.sub(r"g_membindiat_code(.+?)(\{0x90\})",
159+
r"g_membindiat_code\1{" + _codetext +"}", srctext)
160+
_codetext = ",".join([hex(x) for x in memfindexp_code])
161+
srctext = re.sub(r"g_memfindexp_code(.+?)(\{0x90\})",
162+
r"g_memfindexp_code\1{" + _codetext +"}", srctext)
146163
with open(targetpath, "wb") as fp:
147164
fp.write(srctext.encode('utf8'))
148165

149166
def debug():
150167
inject_shellcodestubs("win_injectmemdll.c",
151168
"./bin/libwinpe64.dll",
152-
"./bin/_win_injectmemdll.c")
169+
"./bin/_64win_injectmemdll.c")
153170
pass
154171

155172
def main():

0 commit comments

Comments
 (0)