Skip to content

Commit

Permalink
change winpe function to inline
Browse files Browse the repository at this point in the history
  • Loading branch information
devseed committed Mar 19, 2022
1 parent 68510bc commit b87e84f
Show file tree
Hide file tree
Showing 6 changed files with 544 additions and 165 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ src/**/screenshot/*
src/**/release/*
src/**/debug/*
src/**/bin/*
src/**/sample/*
util/asset/**
util/bin/**
util/script/**
Expand Down
2 changes: 1 addition & 1 deletion src/memdll/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ libwinpe: libwinpe.c
@echo \#\#building $@ ...
$(CC) $< -o $(PREFIX)/$@$(ARCH_POSTFIX)$(DLL_EXT) \
-shared $(CFLAGS) $(LDFLAGS) $(INCS) $(LIBS) $(LIBDIRS)
rm -rf $(PREFIX)/*.exp

win_injectmemdll_shellcodestub: win_injectmemdll.c libwinpe
python $@.py $< \
Expand All @@ -73,6 +72,7 @@ win_injectmemdll: win_injectmemdll_shellcodestub libwinpe
$(CC) $(PREFIX)/_$(ARCH_POSTFIX)$@.c \
-o $(PREFIX)/$@$(ARCH_POSTFIX)$(EXE_EXT)\
-llibwinpe$(ARCH_POSTFIX) \
-Wno-undefined-inline \
$(CFLAGS) $(LDFLAGS) $(INCS) $(LIBS) $(LIBDIRS)

.PHONY: all clean prepare libwinpe win_injectmemdll
Empty file added src/memdll/libwinpe.def
Empty file.
101 changes: 76 additions & 25 deletions src/memdll/win_injectmemdll.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@
*/

#include <stdio.h>
#include <assert.h>
#include "winpe.h"

#define DUMP(path, addr, size)\
FILE *_fp = fopen(path, "wb");\
fwrite(addr, 1, size, _fp);\
fclose(_fp)

// these functions are stub function, will be filled by python
unsigned char g_oepshellcode[] = {0x90};
unsigned char g_memiatshellcode[] = {0x90};
unsigned char g_oepinit_code[] = {0x90};
unsigned char g_membindiat_code[] = {0x90};
unsigned char g_memfindexp_code[] = {0x90};

void _oepshellcode(void *mempe_exe, void *mempe_dll,
void *shellcode, PIMAGE_SECTION_HEADER psecth, DWORD orgoeprva)
{
// PE struct declear
#define FUNC_SIZE 0x200
void *mempe;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
Expand All @@ -28,13 +36,15 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll,
PIMAGE_IMPORT_BY_NAME pFuncName = NULL;

// bind the pointer to buffer
size_t end = sizeof(g_oepshellcode);
size_t *pexeoepva = (size_t*)(g_oepshellcode + end - 6*sizeof(size_t));
size_t *pdllbase = (size_t*)(g_oepshellcode + end - 5*sizeof(size_t));
size_t *pdlloepva = (size_t*)(g_oepshellcode + end - 4*sizeof(size_t));
size_t *pmemiatbind = (size_t*)(g_oepshellcode + end - 3*sizeof(size_t));
size_t *pexeloadlibrarya = (size_t*)(g_oepshellcode + end - 2*sizeof(size_t));
size_t *pexegetprocessaddress = (size_t*)(g_oepshellcode + end - 1*sizeof(size_t));
size_t oepinit_end = sizeof(g_oepinit_code);
size_t memiatbind_start = FUNC_SIZE;
size_t memfindexp_start = memiatbind_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));

// get the information of exe
mempe = mempe_exe;
Expand All @@ -46,12 +56,8 @@ 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;
DWORD exeoeprva = pOptHeader->AddressOfEntryPoint;
DWORD exeloadlibrarya_rva = winpe_memfindiat(
mempe, "kernel32.dll", "LoadLibraryA");
DWORD exegetprocessaddress_rva = winpe_memfindiat(
mempe, "kernel32.dll", "GetProcAddress");

size_t shellcodebase = exeimagebase + psecth->VirtualAddress;

// get the information of dll
mempe = mempe_dll;
pDosHeader = (PIMAGE_DOS_HEADER)mempe;
Expand All @@ -65,14 +71,22 @@ void _oepshellcode(void *mempe_exe, void *mempe_dll,
// fill the address table
*pexeoepva = exeimagebase + orgoeprva;
*pdllbase = dllimagebase;
*pdlloepva = dllimagebase + dlloeprva;
*pmemiatbind = exeimagebase + psecth->VirtualAddress + end;
*pexeloadlibrarya = exeimagebase + exeloadlibrarya_rva;
*pexegetprocessaddress = exeimagebase + exegetprocessaddress_rva;
*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);

// copy to the target
memcpy(shellcode, g_oepshellcode, sizeof(g_oepshellcode));
memcpy(shellcode + end, g_memiatshellcode, sizeof(g_memiatshellcode));
memcpy(shellcode , g_oepinit_code, sizeof(g_oepinit_code));
memcpy(shellcode + memiatbind_start,
g_membindiat_code, sizeof(g_membindiat_code));
memcpy(shellcode + memfindexp_start,
g_memfindexp_code, sizeof(g_memfindexp_code));
}

int injectdll_mem(const char *exepath,
Expand Down Expand Up @@ -111,7 +125,7 @@ int injectdll_mem(const char *exepath,
strcpy((char*)secth.Name, ".module");
winpe_noaslr(mempe_exe);
winpe_appendsecth(mempe_exe, &secth);
DWORD orgoeprva = winpe_setoep(mempe_exe, secth.VirtualAddress);
DWORD orgoeprva = winpe_oepval(mempe_exe, secth.VirtualAddress);
winpe_memreloc(mempe_dll, imgbase_exe + secth.VirtualAddress + SHELLCODE_SIZE);
_oepshellcode(mempe_exe, mempe_dll, shellcode, &secth, orgoeprva);

Expand All @@ -129,16 +143,53 @@ int injectdll_mem(const char *exepath,
return 0;
}

int main(int argc, char *argv[])
void test_exp()
{
char outpath[MAX_PATH];
// test loadlibrary, getprocaddress
HMODULE hmod = NULL;
size_t exprva = 0;
size_t expva = 0;
void* func = NULL;

hmod = LoadLibraryA("kernel32.dll");
assert(hmod!=NULL);
expva = (size_t)GetProcAddress(hmod, "LoadLibraryA");
exprva = (size_t)winpe_memfindexp(hmod, "LoadLibraryA") - (size_t)hmod;
func = winpe_memforwardexp(hmod, exprva, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
assert(exprva!=0 && (size_t)func==expva && func!=NULL);
expva = (size_t)GetProcAddress(hmod, "InitializeSListHead");
exprva = (size_t)winpe_memfindexp(hmod, "InitializeSListHead") - (size_t)hmod;
func = winpe_memforwardexp(hmod, exprva, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
assert(exprva!=0 && (size_t)func==expva && func!=NULL);
expva = (size_t)GetProcAddress(hmod, "GetSystemTimeAsFileTime");
exprva = (size_t)winpe_memfindexp(hmod, "GetSystemTimeAsFileTime") - (size_t)hmod;
func = winpe_memforwardexp(hmod, exprva, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
assert(exprva!=0 && (size_t)func==expva && func!=NULL);
}

void test_memdll(char *dllpath)
{
size_t mempesize = 0;
void *mempe = winpe_memload_file(dllpath, &mempesize, TRUE);;
assert(mempe!=0 && mempesize!=0);
winpe_membindiat(mempe, LoadLibraryA, (PFN_GetProcAddress)winpe_memfindexp);
winpe_memLoadLibrary(mempe);
free(mempe);
}

int main(int argc, char *argv[])
{
#ifdef _DEBUG
test_exp();
if(argc>3) test_memdll(argv[2]);
#endif
if(argc < 3)
{
printf("usage: win_injectmemdll exepath dllpath [outpath]\n");
printf("v0.2, developed by devseed\n");
return 0;
}

char outpath[MAX_PATH];
if(argc >= 4) strcpy(outpath, argv[3]);
else strcpy(outpath, "out.exe");
return injectdll_mem(argv[1], argv[2], outpath);
Expand Down
69 changes: 43 additions & 26 deletions src/memdll/win_injectmemdll_shellcodestub.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
import lief
from keystone import Ks, KS_ARCH_X86, KS_MODE_32, KS_MODE_64

def gen_oepshellcode32():
def gen_oepinit_code32():
ks = Ks(KS_ARCH_X86, KS_MODE_32)
code_str = f"""
// for relative address, get the base of addr
call geteip;
lea ebx, [eax-5];
// bind iat
push eax; // rvaaddr = 0
lea eax, [ebx + exegetprocessaddress];
mov eax, [eax]; // iat
mov eax, [eax]; // iat->addr
Expand All @@ -27,7 +28,7 @@ def gen_oepshellcode32():
mov eax, [eax]; // dllbase value
push eax;
call [ebx + memiatbind];
add esp, 0xC;
add esp, 0x10;
// call dll oep, for dll entry
xor eax, eax;
Expand All @@ -53,12 +54,12 @@ def gen_oepshellcode32():
exeloadlibrarya: nop;nop;nop;nop;
exegetprocessaddress: nop;nop;nop;nop;
"""
print("gen_oepshellcode32", code_str)
print("gen_oepinit_code32", code_str)
payload, _ = ks.asm(code_str)
print("payload: ", [hex(x) for x in payload])
return payload

def gen_oepshellcode64():
def gen_oepinit_code64():
ks = Ks(KS_ARCH_X86, KS_MODE_64)
code_str = f"""
// for relative address, get the base of addr
Expand All @@ -71,8 +72,7 @@ def gen_oepshellcode64():
// bind iat
lea r8, [rbx + exegetprocessaddress];
mov r8, [r8]; // iat
mov r8, [r8]; // iat->addr
mov r8, [r8]; // winpe_memfindexp
lea rdx, [rbx + exeloadlibrarya];
mov rdx, [rdx]; // iat
mov rdx, [rdx]; // iat->addr
Expand Down Expand Up @@ -106,7 +106,7 @@ def gen_oepshellcode64():
exeloadlibrarya: nop;nop;nop;nop;nop;nop;nop;nop;
exegetprocessaddress: nop;nop;nop;nop;nop;nop;nop;nop;
"""
print("gen_oepshellcode64", code_str)
print("gen_oepinit_code64", code_str)
payload, _ = ks.asm(code_str)
print("payload: ", [hex(x) for x in payload])
return payload
Expand All @@ -115,41 +115,58 @@ def gen_oepshellcode64():
def inject_shellcodestubs(srcpath, libwinpepath, targetpath):
pedll = lief.parse(libwinpepath)
pedll_oph = pedll.optional_header
memiatfunc = next(filter(
lambda e : e.name == "winpe_membindiat",
pedll.exported_functions))
memiatshellcode = \
pedll.get_content_from_virtual_address(
memiatfunc.address, 0x200)
# memiatshellcode = memiatshellcode[:memiatshellcode.index(0xC3)+1] # retn


# generate oepint shellcode
if pedll_oph.magic == lief.PE.PE_TYPE.PE32_PLUS:
oepshellcode = gen_oepshellcode64()
oepinit_code = gen_oepinit_code64()
pass
elif pedll_oph.magic == lief.PE.PE_TYPE.PE32:
oepshellcode = gen_oepshellcode32()
oepinit_code = gen_oepinit_code32()
pass
else:
print("error invalid pe magic!", pedll_oph.magic)
return
# 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
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)

# write shellcode to c source file
with open(srcpath, "rb") as fp:
srctext = fp.read().decode('utf8')

_codetext = ",".join([hex(x) for x in oepshellcode])
srctext = re.sub(r"g_oepshellcode(.+?)(\{0x90\})",
r"g_oepshellcode\1{" + _codetext +"}", srctext)
_codetext = ",".join([hex(x) for x in memiatshellcode])
srctext = re.sub(r"g_memiatshellcode(.+?)(\{0x90\})",
r"g_memiatshellcode\1{" + _codetext +"}", srctext)

_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)
with open(targetpath, "wb") as fp:
fp.write(srctext.encode('utf8'))

def debug():
inject_shellcodestubs("win_injectmemdll.c",
"./bin/libwinpe64.dll",
"./bin/_win_injectmemdll.c")
"./bin/_64win_injectmemdll.c")
pass

def main():
Expand Down
Loading

0 comments on commit b87e84f

Please sign in to comment.