by devseed,此篇教程同时发在论坛和我的博客上,完整源码见我的github。
距离上次我写的SimpleDpack教程(为了理解加壳原理自己写的轻量级压缩壳),已经有一年多了。前几天修复x64
的IAT
载入序号问题,于是想着可以用这个原理自己重写一个解析PE
和内存加载DLL
的功能。虽然已有类似实现功能,如MemoryModule,但是这个项目还是有点复杂,模块间耦合度有些高,没法作为shellcode
附加到EXE来引导DLL。
因此我决定重写一个低耦合,同时支持x86
和x64
,可以作为shellcode
引导”附加到EXE区段上的DLL”的框架 。
本框架采取与windows加载DLL相似的名称来设计api,可以实现:
参考stb用XXX_IMPLEMENTATION
宏控制代码实现,使得include单个头文件就能把模块功能全部引入的做法,有着单头文件结成非常容易实用的特点。于是我就用了一周多时间,自己写了个类似的低耦合单头文件winpe.h,用于解析与加载PE。为了便于shellcode
引导,系统函数大多用函数指针传入参数,关键函数全部声明为inline
。另外,我还用内联汇编写了从ldr
中获取kernel32
的基地址,从而减少对IAT硬编码的依赖。
libwinpe.c
, 与libwinpe.def
(引入def
是因为stdcall
编译后会被修改名称),把winpe.h
的声明的导出函数编译为DLL,如下:
对于编写shellcode
, 这里为了方便调试,采取用pyhton
的keystone
进行jit
生成的机器码写入win_injectmemdll.c
的全局变量里的做法, 如下:
详见win_injectmemdll_shellcodestub.py
参考https://bbs.pediy.com/thread-252260.htm, windows对于加载DLL调用如下:
a) 当调用LoadLibrary时首先打开文件并将按照PE文件格式解析数据,并以IMAGE方式将PE各段内容
逐块映射到内存中,如果需要并修复重定位:
kernel32!LoadlibraryA
->kernel32!LoadLibraryExA
->kernel32!LoadLibraryExW
->ntdll!LdrLoadDll
->ntdll!LdrpLoadDll
->ntdll!LdrpMapDll
->ntdll!LdrpCreateDllSection
->ntdll!NtOpenFile //打开目标文件*
->ntdll!NtCreateSection //创建映射*
->ntdll!NtMapViewOfSection //映射*
->LdrRelocateImageWithBias //修复重定位
b) 接着处理调入表等,然后调用TLS回调函数和DLLMAN入口函数;
kernel32!LoadlibraryA
->kernel32!LoadLibraryExA
->kernel32!LoadLibraryExW
->ntdll!LdrLoadDll
->ntdll!LdrpLoadDll
->ntdll!LdrpMapDll
->ntdll!LdrpWalkImportDescriptor //处理导入表等
->LdrpRunInitializeRoutines //调用DLLMAN
->LdrpCallTlsInitializers
->LdrpCallInitRoutine
总结为如下流程:
这里为了降低耦合,没有用系统的memset
和memcpy
,自己用inline实现的。
手动将以imagebase
为基准的va
重定向到目标imagebase
的va
。
用LoadLibraryA
和GetProcAddress
实现,考虑到shellcode,不能直接调用,应该通过传入函数指针调用。
另外还要考虑OFT
中会出现用序号的情况,x86
和x64
判断表中不同,用sizeof(size_t)
区分。
前三步都完成后可以来通过DllMain来引导了。
这部分我没有找到有TLS的DLL,所以没法进一步测试了。这部分代码直接借鉴的MemoryModule的相关函数。
首先需要修改exe的区段头,在后面增加一个区段。这里要特别注意区段的对齐,之后还要修正SizeOfImage
。
这部分内容和winpe_memLoadLibrary
函数实现的方式类似,只不过要用汇编来写shellcode
,引导完成后跳转到原来exe的oep
。 关键地址可以先留空,在注入时候填入对位置。对于相应的函数的shellcode,由win_injectmemdll_shellcodestub.py
读取对应的libpe32.dll
函数,填入对应的全局变量。下面代码以x86为例:
由于大部分都用的size_t
或void*
等与cpu字长相关的变量,大部分代码不用修改就能编译。
其余的差异部分,可以用sizeof(size_t)>4
区分,或者_WIN64
宏。如下所示
上面的代码我们可以获取kernel32
的基址了,之后可以自己通过扫描export表
来查找对应的导出函数了。
这里注意有个坑点,有的导出表项会forward到其他dll上,如kernel32!InitializeSListHead -> NTDLL!RtlInitializeSListHead
,详见crashing-kernel32-initializeslisthead。通过DirRVA < FuncRVA < DirRVA + ExportSize
来判断是否forward。
此处为了找到LoadLibraryA
和GetProcAddress
函数,不考虑forward情况,否则会引入递归问题。
本项目是我实现不加壳vfs
(即通过hook nt函数将文件和文件夹等读取重定向到zip文件中)的衍生产物,采取的是尽量单头文件法和内联函数减小耦合,方便集成到代码中的做法。与其他的MemoryModule
最大的区别是支持从shellcode
引导DLL。由于以前我有了自己写压缩壳的经验,整体上处理起来还算是顺利。强迫症,感觉好多时间都花在了怎么统一化命名api和代码风格规范上了。至于实现内存加载Resource
方面,暂时不考虑实现,汉化游戏一般也用不到这方面内容。
另外,这里还有个坑卡了我好长时间,就是x64
的堆栈必须要0x10
对齐(即调用函数时要sub rsp, 0x28
预留空间与对齐),才能在movaps
指令上不报错。之前一直不知道这条指令需要对齐,一直以为是少了哪些初始化,走偏了好久。特别感谢@YeLikERs指出了这一点,同时在PEB
,LDR
相关内容上帮助了很多。
经测试兼容性还算不错,windows xp
, windows 7
, windows 10
, windows 11
测试example文件都通过了,甚至我连linux
上的wine
也测试了(即用我汉化的游戏测试shellcode引导附加到exe区段上的DLL)。最后,附上几张测试图:
const char
*
dllpath
=
"test.dll"
;
size_t mempesize
=
0
;
void
*
memdll
=
NULL;
/
/
load the pe
file
in
memory
and
align it to memory align
void
*
mempe
=
winpe_memload_file(dllpath, &mempesize, TRUE);
/
/
memory loadlibrary
memdll
=
winpe_memLoadLibrary(mempe);
winpe_memFreeLibrary(memdll);
/
/
memory loadlibrary at specific address
size_t targetaddr
=
sizeof(size_t) >
4
?
0x140030000
:
0x90000
;
memdll
=
winpe_memLoadLibraryEx(mempe, targetaddr,
WINPE_LDFLAG_MEMALLOC, (PFN_LoadLibraryA)winpe_findloadlibrarya(),
(PFN_GetProcAddress)winpe_memGetProcAddress);
winpe_memFreeLibrary(memdll);
free(mempe);
const char
*
dllpath
=
"test.dll"
;
size_t mempesize
=
0
;
void
*
memdll
=
NULL;
/
/
load the pe
file
in
memory
and
align it to memory align
void
*
mempe
=
winpe_memload_file(dllpath, &mempesize, TRUE);
/
/
memory loadlibrary
memdll
=
winpe_memLoadLibrary(mempe);
winpe_memFreeLibrary(memdll);
/
/
memory loadlibrary at specific address
size_t targetaddr
=
sizeof(size_t) >
4
?
0x140030000
:
0x90000
;
memdll
=
winpe_memLoadLibraryEx(mempe, targetaddr,
WINPE_LDFLAG_MEMALLOC, (PFN_LoadLibraryA)winpe_findloadlibrarya(),
(PFN_GetProcAddress)winpe_memGetProcAddress);
winpe_memFreeLibrary(memdll);
free(mempe);
win_injectmemdll.exe exepath dllpath [outpath]
win_injectmemdll.exe exepath dllpath [outpath]
EXPORTS
winpe_appendsecth
winpe_findgetprocaddress
winpe_findkernel32
winpe_findloadlibrarya
winpe_findspace
winpe_findmodulea
winpe_imagebaseval
winpe_imagesizeval
winpe_memFreeLibrary
winpe_memFreeLibraryEx
winpe_memGetProcAddress
winpe_memLoadLibrary
winpe_memLoadLibraryEx
winpe_membindiat
winpe_membindtls
winpe_memfindexp
winpe_memfindiat
winpe_memforwardexp
winpe_memload
winpe_memload_file
winpe_memreloc
winpe_noaslr
winpe_oepval
winpe_overlayload_file
winpe_overlayoffset
EXPORTS
winpe_appendsecth
winpe_findgetprocaddress
winpe_findkernel32
winpe_findloadlibrarya
winpe_findspace
winpe_findmodulea
winpe_imagebaseval
winpe_imagesizeval
winpe_memFreeLibrary
winpe_memFreeLibraryEx
winpe_memGetProcAddress
winpe_memLoadLibrary
winpe_memLoadLibraryEx
winpe_membindiat
winpe_membindtls
winpe_memfindexp
winpe_memfindiat
winpe_memforwardexp
winpe_memload
winpe_memload_file
winpe_memreloc
winpe_noaslr
winpe_oepval
winpe_overlayload_file
winpe_overlayoffset
def
inject_shellcodestubs(srcpath, libwinpepath, targetpath):
pedll
=
lief.parse(libwinpepath)
pedll_oph
=
pedll.optional_header
if
pedll_oph.magic
=
=
lief.PE.PE_TYPE.PE32_PLUS:
oepinit_code
=
gen_oepinit_code64()
pass
elif
pedll_oph.magic
=
=
lief.PE.PE_TYPE.PE32:
oepinit_code
=
gen_oepinit_code32()
pass
else
:
print
(
"error invalid pe magic!"
, pedll_oph.magic)
return
FUNC_SIZE
=
0x400
codes
=
{
"winpe_memreloc"
:
0
,
"winpe_membindiat"
:
0
,
"winpe_membindtls"
:
0
,
"winpe_findloadlibrarya"
:
0
,
"winpe_findgetprocaddress"
:
0
}
for
k
in
codes.keys():
func
=
next
(
filter
(
lambda
e : e.name
=
=
k,
pedll.exported_functions))
codes[k]
=
pedll.get_content_from_virtual_address(
func.address, FUNC_SIZE)
codes[
'winpe_oepinit'
]
=
oepinit_code
with
open
(srcpath,
"rb"
) as fp:
srctext
=
fp.read().decode(
'utf8'
)
for
k, v
in
codes.items():
k
=
k.replace(
"winpe_"
, "")
_codetext
=
","
.join([
hex
(x)
for
x
in
v])
srctext
=
re.sub(
"g_"
+
k
+
r
"_code(.+?)(\{0x90\})"
,
"g_"
+
k
+
r
"_code\1{"
+
_codetext
+
"}"
, srctext)
with
open
(targetpath,
"wb"
) as fp:
fp.write(srctext.encode(
'utf8'
))
def
inject_shellcodestubs(srcpath, libwinpepath, targetpath):
pedll
=
lief.parse(libwinpepath)
pedll_oph
=
pedll.optional_header
if
pedll_oph.magic
=
=
lief.PE.PE_TYPE.PE32_PLUS:
oepinit_code
=
gen_oepinit_code64()
pass
elif
pedll_oph.magic
=
=
lief.PE.PE_TYPE.PE32:
oepinit_code
=
gen_oepinit_code32()
pass
else
:
print
(
"error invalid pe magic!"
, pedll_oph.magic)
return
FUNC_SIZE
=
0x400
codes
=
{
"winpe_memreloc"
:
0
,
"winpe_membindiat"
:
0
,
"winpe_membindtls"
:
0
,
"winpe_findloadlibrarya"
:
0
,
"winpe_findgetprocaddress"
:
0
}
for
k
in
codes.keys():
func
=
next
(
filter
(
lambda
e : e.name
=
=
k,
pedll.exported_functions))
codes[k]
=
pedll.get_content_from_virtual_address(
func.address, FUNC_SIZE)
codes[
'winpe_oepinit'
]
=
oepinit_code
with
open
(srcpath,
"rb"
) as fp:
srctext
=
fp.read().decode(
'utf8'
)
for
k, v
in
codes.items():
k
=
k.replace(
"winpe_"
, "")
_codetext
=
","
.join([
hex
(x)
for
x
in
v])
srctext
=
re.sub(
"g_"
+
k
+
r
"_code(.+?)(\{0x90\})"
,
"g_"
+
k
+
r
"_code\1{"
+
_codetext
+
"}"
, srctext)
with
open
(targetpath,
"wb"
) as fp:
fp.write(srctext.encode(
'utf8'
))
inline size_t STDCALL winpe_memload(
const void
*
rawpe, size_t rawsize,
void
*
mempe, size_t memsize,
bool_t same_align)
{
/
/
load rawpe to memalign
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)rawpe;
PIMAGE_NT_HEADERS pNtHeader
=
(PIMAGE_NT_HEADERS)
((void
*
)rawpe
+
pDosHeader
-
>e_lfanew);
PIMAGE_FILE_HEADER pFileHeader
=
&pNtHeader
-
>FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader
=
&pNtHeader
-
>OptionalHeader;
PIMAGE_SECTION_HEADER pSectHeader
=
(PIMAGE_SECTION_HEADER)
((void
*
)pOptHeader
+
pFileHeader
-
>SizeOfOptionalHeader);
WORD sectNum
=
pFileHeader
-
>NumberOfSections;
size_t imagesize
=
pOptHeader
-
>SizeOfImage;
if
(!mempe)
return
imagesize;
else
if
(memsize!
=
0
&& memsize<imagesize)
return
0
;
_inl_memset(mempe,
0
, imagesize);
_inl_memcpy(mempe, rawpe, pOptHeader
-
>SizeOfHeaders);
for
(WORD i
=
0
;i<sectNum;i
+
+
)
{
_inl_memcpy(mempe
+
pSectHeader[i].VirtualAddress,
rawpe
+
pSectHeader[i].PointerToRawData,
pSectHeader[i].SizeOfRawData);
}
/
/
adjust
all
to mem align
if
(same_align)
{
pDosHeader
=
(PIMAGE_DOS_HEADER)mempe;
pNtHeader
=
(PIMAGE_NT_HEADERS)((void
*
)mempe
+
pDosHeader
-
>e_lfanew);
pFileHeader
=
&pNtHeader
-
>FileHeader;
pOptHeader
=
&pNtHeader
-
>OptionalHeader;
pSectHeader
=
(PIMAGE_SECTION_HEADER)
((void
*
)pOptHeader
+
pFileHeader
-
>SizeOfOptionalHeader);
sectNum
=
pFileHeader
-
>NumberOfSections;
pOptHeader
-
>FileAlignment
=
pOptHeader
-
>SectionAlignment;
for
(WORD i
=
0
;i<sectNum;i
+
+
)
{
pSectHeader[i].PointerToRawData
=
pSectHeader[i].VirtualAddress;
}
}
return
imagesize;
}
inline size_t STDCALL winpe_memload(
const void
*
rawpe, size_t rawsize,
void
*
mempe, size_t memsize,
bool_t same_align)
{
/
/
load rawpe to memalign
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)rawpe;
PIMAGE_NT_HEADERS pNtHeader
=
(PIMAGE_NT_HEADERS)
((void
*
)rawpe
+
pDosHeader
-
>e_lfanew);
PIMAGE_FILE_HEADER pFileHeader
=
&pNtHeader
-
>FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader
=
&pNtHeader
-
>OptionalHeader;
PIMAGE_SECTION_HEADER pSectHeader
=
(PIMAGE_SECTION_HEADER)
((void
*
)pOptHeader
+
pFileHeader
-
>SizeOfOptionalHeader);
WORD sectNum
=
pFileHeader
-
>NumberOfSections;
size_t imagesize
=
pOptHeader
-
>SizeOfImage;
if
(!mempe)
return
imagesize;
else
if
(memsize!
=
0
&& memsize<imagesize)
return
0
;
_inl_memset(mempe,
0
, imagesize);
_inl_memcpy(mempe, rawpe, pOptHeader
-
>SizeOfHeaders);
for
(WORD i
=
0
;i<sectNum;i
+
+
)
{
_inl_memcpy(mempe
+
pSectHeader[i].VirtualAddress,
rawpe
+
pSectHeader[i].PointerToRawData,
pSectHeader[i].SizeOfRawData);
}
/
/
adjust
all
to mem align
if
(same_align)
{
pDosHeader
=
(PIMAGE_DOS_HEADER)mempe;
pNtHeader
=
(PIMAGE_NT_HEADERS)((void
*
)mempe
+
pDosHeader
-
>e_lfanew);
pFileHeader
=
&pNtHeader
-
>FileHeader;
pOptHeader
=
&pNtHeader
-
>OptionalHeader;
pSectHeader
=
(PIMAGE_SECTION_HEADER)
((void
*
)pOptHeader
+
pFileHeader
-
>SizeOfOptionalHeader);
sectNum
=
pFileHeader
-
>NumberOfSections;
pOptHeader
-
>FileAlignment
=
pOptHeader
-
>SectionAlignment;
for
(WORD i
=
0
;i<sectNum;i
+
+
)
{
pSectHeader[i].PointerToRawData
=
pSectHeader[i].VirtualAddress;
}
}
return
imagesize;
}
inline size_t STDCALL winpe_memreloc(
void
*
mempe, size_t newimagebase)
{
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;
PIMAGE_DATA_DIRECTORY pDataDirectory
=
pOptHeader
-
>DataDirectory;
PIMAGE_DATA_DIRECTORY pRelocEntry
=
&pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
DWORD reloc_count
=
0
;
DWORD reloc_offset
=
0
;
int64_t shift
=
(int64_t)newimagebase
-
(int64_t)pOptHeader
-
>ImageBase;
while
(reloc_offset < pRelocEntry
-
>Size)
{
PIMAGE_BASE_RELOCATION pBaseReloc
=
(PIMAGE_BASE_RELOCATION)
((void
*
)mempe
+
pRelocEntry
-
>VirtualAddress
+
reloc_offset);
PRELOCOFFSET pRelocOffset
=
(PRELOCOFFSET)((void
*
)pBaseReloc
+
sizeof(IMAGE_BASE_RELOCATION));
/
/
RELOCOFFSET block num
DWORD item_num
=
(pBaseReloc
-
>SizeOfBlock
-
sizeof(IMAGE_BASE_RELOCATION))
/
sizeof(RELOCOFFSET);
for
(size_t i
=
0
; i < item_num; i
+
+
)
{
if
(!pRelocOffset[i].
type
&&
!pRelocOffset[i].offset)
continue
;
DWORD targetoffset
=
pBaseReloc
-
>VirtualAddress
+
pRelocOffset[i].offset;
size_t
*
paddr
=
(size_t
*
)((void
*
)mempe
+
targetoffset);
size_t relocaddr
=
(size_t)((int64_t)
*
paddr
+
shift);
*
paddr
=
relocaddr;
}
reloc_offset
+
=
sizeof(IMAGE_BASE_RELOCATION)
+
sizeof(RELOCOFFSET)
*
item_num;
reloc_count
+
=
item_num;
}
pOptHeader
-
>ImageBase
=
newimagebase;
return
reloc_count;
}
inline size_t STDCALL winpe_memreloc(
void
*
mempe, size_t newimagebase)
{
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;
PIMAGE_DATA_DIRECTORY pDataDirectory
=
pOptHeader
-
>DataDirectory;
PIMAGE_DATA_DIRECTORY pRelocEntry
=
&pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
DWORD reloc_count
=
0
;
DWORD reloc_offset
=
0
;
int64_t shift
=
(int64_t)newimagebase
-
(int64_t)pOptHeader
-
>ImageBase;
while
(reloc_offset < pRelocEntry
-
>Size)
{
PIMAGE_BASE_RELOCATION pBaseReloc
=
(PIMAGE_BASE_RELOCATION)
((void
*
)mempe
+
pRelocEntry
-
>VirtualAddress
+
reloc_offset);
PRELOCOFFSET pRelocOffset
=
(PRELOCOFFSET)((void
*
)pBaseReloc
+
sizeof(IMAGE_BASE_RELOCATION));
/
/
RELOCOFFSET block num
DWORD item_num
=
(pBaseReloc
-
>SizeOfBlock
-
sizeof(IMAGE_BASE_RELOCATION))
/
sizeof(RELOCOFFSET);
for
(size_t i
=
0
; i < item_num; i
+
+
)
{
if
(!pRelocOffset[i].
type
&&
!pRelocOffset[i].offset)
continue
;
DWORD targetoffset
=
pBaseReloc
-
>VirtualAddress
+
pRelocOffset[i].offset;
size_t
*
paddr
=
(size_t
*
)((void
*
)mempe
+
targetoffset);
size_t relocaddr
=
(size_t)((int64_t)
*
paddr
+
shift);
*
paddr
=
relocaddr;
}
reloc_offset
+
=
sizeof(IMAGE_BASE_RELOCATION)
+
sizeof(RELOCOFFSET)
*
item_num;
reloc_count
+
=
item_num;
}
pOptHeader
-
>ImageBase
=
newimagebase;
return
reloc_count;
}
WINPEDEF WINPE_EXPORT
inline size_t STDCALL winpe_membindiat(void
*
mempe,
PFN_LoadLibraryA pfnLoadLibraryA,
PFN_GetProcAddress pfnGetProcAddress)
{
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;
PIMAGE_DATA_DIRECTORY pDataDirectory
=
pOptHeader
-
>DataDirectory;
PIMAGE_DATA_DIRECTORY pImpEntry
=
&pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor
=
(PIMAGE_IMPORT_DESCRIPTOR)(mempe
+
pImpEntry
-
>VirtualAddress);
PIMAGE_THUNK_DATA pFtThunk
=
NULL;
PIMAGE_THUNK_DATA pOftThunk
=
NULL;
LPCSTR pDllName
=
NULL;
PIMAGE_IMPORT_BY_NAME pImpByName
=
NULL;
size_t funcva
=
0
;
char
*
funcname
=
NULL;
/
/
origin GetProcAddress will crash at InitializeSListHead
if
(!pfnLoadLibraryA) pfnLoadLibraryA
=
(PFN_LoadLibraryA)winpe_findloadlibrarya();
if
(!pfnGetProcAddress) pfnGetProcAddress
=
(PFN_GetProcAddress)winpe_findgetprocaddress();
DWORD iat_count
=
0
;
for
(; pImpDescriptor
-
>Name; pImpDescriptor
+
+
)
{
pDllName
=
(LPCSTR)(mempe
+
pImpDescriptor
-
>Name);
pFtThunk
=
(PIMAGE_THUNK_DATA)
(mempe
+
pImpDescriptor
-
>FirstThunk);
pOftThunk
=
(PIMAGE_THUNK_DATA)
(mempe
+
pImpDescriptor
-
>OriginalFirstThunk);
size_t dllbase
=
(size_t)pfnLoadLibraryA(pDllName);
if
(!dllbase)
return
0
;
for
(
int
j
=
0
; pFtThunk[j].u1.Function
&& pOftThunk[j].u1.Function; j
+
+
)
{
size_t _addr
=
(size_t)(mempe
+
pOftThunk[j].u1.AddressOfData);
if
(sizeof(size_t)>
4
)
/
/
x64
{
if
((_addr>>
63
)
=
=
1
)
{
funcname
=
(char
*
)(_addr &
0xffff
);
}
else
{
pImpByName
=
(PIMAGE_IMPORT_BY_NAME)_addr;
funcname
=
pImpByName
-
>Name;
}
}
else
{
if
(((size_t)pImpByName>>
31
)
=
=
1
)
{
funcname
=
(char
*
)(_addr &
0xffff
);
}
else
{
pImpByName
=
(PIMAGE_IMPORT_BY_NAME)_addr;
funcname
=
pImpByName
-
>Name;
}
}
funcva
=
(size_t)pfnGetProcAddress(
(HMODULE)dllbase, funcname);
if
(!funcva)
continue
;
pFtThunk[j].u1.Function
=
funcva;
assert
(funcva
=
=
(size_t)GetProcAddress(
(HMODULE)dllbase, funcname));
iat_count
+
+
;
}
}
return
iat_count;
}
WINPEDEF WINPE_EXPORT
inline size_t STDCALL winpe_membindiat(void
*
mempe,
PFN_LoadLibraryA pfnLoadLibraryA,
PFN_GetProcAddress pfnGetProcAddress)
{
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;
PIMAGE_DATA_DIRECTORY pDataDirectory
=
pOptHeader
-
>DataDirectory;
PIMAGE_DATA_DIRECTORY pImpEntry
=
&pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor
=
(PIMAGE_IMPORT_DESCRIPTOR)(mempe
+
pImpEntry
-
>VirtualAddress);
PIMAGE_THUNK_DATA pFtThunk
=
NULL;
PIMAGE_THUNK_DATA pOftThunk
=
NULL;
LPCSTR pDllName
=
NULL;
PIMAGE_IMPORT_BY_NAME pImpByName
=
NULL;
size_t funcva
=
0
;
char
*
funcname
=
NULL;
/
/
origin GetProcAddress will crash at InitializeSListHead
if
(!pfnLoadLibraryA) pfnLoadLibraryA
=
(PFN_LoadLibraryA)winpe_findloadlibrarya();
if
(!pfnGetProcAddress) pfnGetProcAddress
=
(PFN_GetProcAddress)winpe_findgetprocaddress();
DWORD iat_count
=
0
;
for
(; pImpDescriptor
-
>Name; pImpDescriptor
+
+
)
{
pDllName
=
(LPCSTR)(mempe
+
pImpDescriptor
-
>Name);
pFtThunk
=
(PIMAGE_THUNK_DATA)
(mempe
+
pImpDescriptor
-
>FirstThunk);
pOftThunk
=
(PIMAGE_THUNK_DATA)
(mempe
+
pImpDescriptor
-
>OriginalFirstThunk);
size_t dllbase
=
(size_t)pfnLoadLibraryA(pDllName);
if
(!dllbase)
return
0
;
for
(
int
j
=
0
; pFtThunk[j].u1.Function
&& pOftThunk[j].u1.Function; j
+
+
)
{
size_t _addr
=
(size_t)(mempe
+
pOftThunk[j].u1.AddressOfData);
if
(sizeof(size_t)>
4
)
/
/
x64
{
if
((_addr>>
63
)
=
=
1
)
{
funcname
=
(char
*
)(_addr &
0xffff
);
}
else
{
pImpByName
=
(PIMAGE_IMPORT_BY_NAME)_addr;
funcname
=
pImpByName
-
>Name;
}
}
else
{
if
(((size_t)pImpByName>>
31
)
=
=
1
)
{
funcname
=
(char
*
)(_addr &
0xffff
);
}
else
{
pImpByName
=
(PIMAGE_IMPORT_BY_NAME)_addr;
funcname
=
pImpByName
-
>Name;
}
}
funcva
=
(size_t)pfnGetProcAddress(
(HMODULE)dllbase, funcname);
if
(!funcva)
continue
;
pFtThunk[j].u1.Function
=
funcva;
assert
(funcva
=
=
(size_t)GetProcAddress(
(HMODULE)dllbase, funcname));
iat_count
+
+
;
}
}
return
iat_count;
}
/
/
initial memory module
if
(!winpe_memreloc((void
*
)imagebase, imagebase))
return
NULL;
if
(!winpe_membindiat((void
*
)imagebase,
pfnLoadLibraryA, pfnGetProcAddress))
return
NULL;
winpe_membindtls(mempe, DLL_PROCESS_ATTACH);
PFN_DllMain pfnDllMain
=
(PFN_DllMain)
(imagebase
+
winpe_oepval((void
*
)imagebase,
0
));
pfnDllMain((HINSTANCE)imagebase, DLL_PROCESS_ATTACH, NULL);
return
(void
*
)imagebase;
/
/
initial memory module
if
(!winpe_memreloc((void
*
)imagebase, imagebase))
return
NULL;
if
(!winpe_membindiat((void
*
)imagebase,
pfnLoadLibraryA, pfnGetProcAddress))
return
NULL;
winpe_membindtls(mempe, DLL_PROCESS_ATTACH);
PFN_DllMain pfnDllMain
=
(PFN_DllMain)
(imagebase
+
winpe_oepval((void
*
)imagebase,
0
));
pfnDllMain((HINSTANCE)imagebase, DLL_PROCESS_ATTACH, NULL);
return
(void
*
)imagebase;
inline size_t STDCALL winpe_membindtls(void
*
mempe, DWORD resaon)
{
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;
PIMAGE_DATA_DIRECTORY pDataDirectory
=
pOptHeader
-
>DataDirectory;
PIMAGE_DATA_DIRECTORY pTlsDirectory
=
&pDataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if
(!pTlsDirectory
-
>VirtualAddress)
return
0
;
size_t tls_count
=
0
;
PIMAGE_TLS_DIRECTORY pTlsEntry
=
(PIMAGE_TLS_DIRECTORY)
(mempe
+
pTlsDirectory
-
>VirtualAddress);
PIMAGE_TLS_CALLBACK
*
tlscb
=
(PIMAGE_TLS_CALLBACK
*
)
pTlsEntry
-
>AddressOfCallBacks;
if
(tlscb)
{
while
(
*
tlscb)
{
(
*
tlscb)(mempe, reason, NULL);
tlscb
+
+
;
tls_count
+
+
;
}
}
return
tls_count;
}
inline size_t STDCALL winpe_membindtls(void
*
mempe, DWORD resaon)
{
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)mempe;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!