第一次写壳,如有错误,感谢指点~
编写一个加壳器项目、一个动态链接库项目,将动态链接库的.text
、.data
、.rdata
区段合并为一个区段
1.1为了方便调试,进行如下设置
设置 .exe
(加壳器) 和 .dll
(stub) 文件的输出路径为同一路径
项目属性 -> 常规 -> 输出目录
设置工作目录为刚才的输出路径
项目属性 -> 调试 -> 工作目录
1.2STUB 区域代码的重定位问题
起初代码是放在了 dll
中,需要重定位的内容,是以 dll
实际加载基址设置的,现在我们将dll
中的三个区段合并之后放到原程序后面了,那么涉及到重定位的问题:首先了解一下一个虚拟地址的组成:
VA = ImageBase + 区段首地址 + 区段偏移
在加壳器中,首先打开需要被加壳的程序,读取需要加壳的程序的PE文件到内存中
新建一个动态链接库项目,作为壳代码使用
在加壳器中,打开动态链接库生成的dll
文件,以便后面获取合并区段中的壳代码
打开完dll
和需要加壳的exe
后,对exe
的PE结构操作:新增一个区段,将dll
中合并后的.text
区段拷贝到新区段中
AlignmentToSize
函数:根据大小以及对齐粒度,获取对齐后的大小
拷贝完成之后,将程序的OEP
设置为壳代码的OEP
(也就是刚刚拷贝过来的区段),并且备份原程序的OEP
设置完OEP
,开始对区段加密,加密的实现很简单,就是获取需要加密的区段首地址和大小,循环加密。加密算法这里就使用简单的异或。
加密完之后,对原程序的.text区段压缩,压缩的原理如下图,此处仅压缩了.text
区段
压缩实现之后的大小变化:因为只是压缩了一个.text
区段所以压缩率并不高,只是少了600KB
左右
我们先看一下程序从编译到运行之间的流程
编译:将单个的 .c
或 .cpp
编译成中间文件 (.obj
),在VS
下,这个过程由 cl.exe
程序完成。
链接:将编译出的.obj
中间文件、系统的启动文件和用到的库文件链接成一个可执行文件 (.exe
)。VS
下由 link.exe
程序完成
装载:将一个可执行文件映射到虚拟地址空间并执行,由操作系统完成。在装载的过程中,完了让程序正常被执行,会有下列几个步骤:
判断是否开启重定位,如果开启了,将 PE 文件加载到指定位置,并且修复目标PE 文件的重定位。
遍历导入表,加载使用到的所有模块到内存,修复模块相关的信息,并根据导入表中的函数名称,填充所有的IAT
地址项。
查看当前是否存在TLS
回调函数,如果存在,则传入进程创建事件,依次调用 所有的TLS
回调函数。
以PE
文件中的AddressOfEntryPoint
为起始位置,创建线程并运行。
我们的IAT
加密是在壳代码中完成的,但是为了能让壳代码顺利接管到IAT
表,需要在令程序在装载的时候不填充IAT
表
一个程序如果有TLS
会在程序运行之前就调用TLS
里面的回调函数,由于我们运行的是加壳后的程序,原程序的代码段已经被加密,直接运行TLS
肯定不行,我们需要手动处理TLS
,在原程序中备份TLS
以及TLS
的回调函数数组,然后在壳代码中,程序解密后运行前,自己手动遍历TLS
回调函数,手动循环调用一次,然后在恢复TLS
。
重定位是一个比较麻烦的问题,还需要考虑到随机基址的问题。
首先,dll
合并后的.text
区段由于ImageBase
和区段RVA
改变了,需要先修复dll
的.text
区段的重定位项
随机基址的问题:由于有了随机基址,即使我们上面修复了重定位项,程序也不能正常运行,我们可以替换原程序的重定位表,让原程序帮我们修复壳代码的重定位项,当程序装载之后,壳代码的重定位项已经修复为随机基址之后的地址了,我们就可以在壳代码中修复原程序的重定位表,壳代码修复原程序的重定位项需要使用到原程序的重定位表,因此,还需要备份一下原程序的重定位表地址。
那如何替换原程序的重定位表呢?新建一个区段,这个区段用于存放DLL
的重定位表,然后备份原程序的重定位表后,将原程序的重定位表指向新建的区段。完成重定位表的替换。
添加区段的函数:
拷贝dll
的.text
区段到被加壳程序的.pack
区段
壳代码其实就是动态链接库中合并后的.text
区段,在2.1
中有提到过
其实也是和加壳器是一一对应的,理解了加壳器的代码,壳代码也就好理解了
由于壳代码在运行的时候,原程序还没有运行起来,并且我们对IAT
进行了加密,因此,在壳代码中不能直接调用函数,需要手动获取函数地址。
一旦有了GetProcAddress
这个函数和Kerler32
基址,我们就可以调用所有函数了,获取到LoadLibraryExA
之后,就可以加载其他模块,获取其他模块的函数了。(因为不管是Kernel32
还是KernelBase
都存在这个导出函数,所以不使用LoadLibraryA
)
此处为壳子添加了一个密码弹框,需要输入正确的密码后才能运行壳代码,其实也并没什么作用,就是手动获取API
调用了SDK
的函数,创建窗口以及消息处理的函数。
运行加壳后的程序会弹出对话框:
在加壳器中我们对原程序进行了压缩,那么在壳代码中就要对原程序解压,解压很简单,就是将压缩后的数据解压后放回该数据的原来的位置(参考2.6
的图)
与加壳器中的加密同理
在加壳器中,我们对导出表进行了清零操作,目的就是为了不让系统去修复导入表,而令我们的壳代码来修复导入表并加密IAT
。而加密IAT
的原理如下:
就是为每一个IAT
都申请一个堆空间,然后在堆空间中填入解密IAT
的代码以及加密后的IAT
地址,将原来的IAT
替换为堆空间的地址,这样,只要程序使用到IAT
,就会执行堆空间的代码,动态解密IAT
。下面的图片是为了便于理解画的简化版,并没有加密IAT
。
由于加壳器中的设置,程序装载的时候,系统帮我们修复了壳代码的重定位,但是原程序的重定位并没有修复,需要我们自己手动修复
这里处理的TLS
并不是完美处理的。但是也能实现TLS
的处理,就是循环调用TLS
的回调函数,将数据目录表的TLS
恢复。
反调试有很多很多种方法,这里就是简单的意思一下。遍历所有线程的TEB+0xF24
的反调试方法目前还有BUG,暂时没有完成实现。若有大佬能指点一二,感激不尽~
原程序的解压、解密、IAT加密
都已经操作完成了,跳回原程序执行。
关于混淆和花指令在这里并没有做太深入的探究。
最后,非常感谢15PB万老师的课上讲解、以及顿老师的课后辅导~
/
/
1.
将 DLL 设置为 Release 版本进行编译、小、内联了一些函数
/
/
2.
C\C
+
+
-
> 代码生成
-
> GS安全检查
-
> 禁用 (取消一些库函数的调用)
/
/
3.
C\C
+
+
-
> 所有选项
-
> 运行库
-
> MT (取消一些库函数的调用)
/
/
4.
合并区段,并设置属性为可读可写可执行(
0xE00000E0
)
/
/
1.
将 DLL 设置为 Release 版本进行编译、小、内联了一些函数
/
/
2.
C\C
+
+
-
> 代码生成
-
> GS安全检查
-
> 禁用 (取消一些库函数的调用)
/
/
3.
C\C
+
+
-
> 所有选项
-
> 运行库
-
> MT (取消一些库函数的调用)
/
/
4.
合并区段,并设置属性为可读可写可执行(
0xE00000E0
)
/
/
打开、读取、判断文件
VOID Pack::OpenPeFile(LPCSTR Path) {
HANDLE hFile
=
CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
print
(
"打开文件失败"
);
/
/
自己封装的判断函数
PeSize
=
GetFileSize(hFile, NULL);
PeBase
=
(DWORD)malloc(PeSize);
DWORD ReadSize
=
0
;
ReadFile(hFile, (LPVOID)PeBase, PeSize, &ReadSize, NULL);
if
(pDosHead(PeBase)
-
>e_magic!
=
0x5A4D
)
print
(
"不是有效的PE文件"
);
else
if
(pNtHead(PeBase)
-
>Signature !
=
0x4550
)
print
(
"不是有效的PE文件"
);
CloseHandle(hFile);
}
/
/
打开、读取、判断文件
VOID Pack::OpenPeFile(LPCSTR Path) {
HANDLE hFile
=
CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
print
(
"打开文件失败"
);
/
/
自己封装的判断函数
PeSize
=
GetFileSize(hFile, NULL);
PeBase
=
(DWORD)malloc(PeSize);
DWORD ReadSize
=
0
;
ReadFile(hFile, (LPVOID)PeBase, PeSize, &ReadSize, NULL);
if
(pDosHead(PeBase)
-
>e_magic!
=
0x5A4D
)
print
(
"不是有效的PE文件"
);
else
if
(pNtHead(PeBase)
-
>Signature !
=
0x4550
)
print
(
"不是有效的PE文件"
);
CloseHandle(hFile);
}
/
/
对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
/
/
去除所有导出函数和导出变量的名称粉碎
extern
"C"
{
__declspec(dllexport) SHARE ShareData;
/
/
导出变量,用于壳代码与加壳器之间的通讯
__declspec(dllexport) __declspec(naked) void start()
/
/
导出函数地址,将会作为新的OEP
{
_asm{
mov eax, fs:[
0x30
]
mov eax, [eax
+
0x8
]
/
/
获取当前进程gImageBase
mov gImageBase, eax
}
GetFunAdd();
/
/
获取GetProcAddress
GetApi();
/
/
获取API
CallShllFun();
/
/
密码弹窗
UnCompression(ShareData);
/
/
解压
DecSection();
/
/
解密代码段
DecIat(ShareData);
/
/
加密IAT
FixReloca(ShareData);
/
/
修复重定位
CallTls(ShareData);
/
/
处理TLS
Debugging();
/
/
反调试
__asm
{
mov eax, gImageBase
/
/
获取当前进程gImageBase
mov ebx, ShareData.DestOEP
/
/
获取原程序的OEP
add eax,ebx
jmp eax
}
}
}
/
/
对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
/
/
去除所有导出函数和导出变量的名称粉碎
extern
"C"
{
__declspec(dllexport) SHARE ShareData;
/
/
导出变量,用于壳代码与加壳器之间的通讯
__declspec(dllexport) __declspec(naked) void start()
/
/
导出函数地址,将会作为新的OEP
{
_asm{
mov eax, fs:[
0x30
]
mov eax, [eax
+
0x8
]
/
/
获取当前进程gImageBase
mov gImageBase, eax
}
GetFunAdd();
/
/
获取GetProcAddress
GetApi();
/
/
获取API
CallShllFun();
/
/
密码弹窗
UnCompression(ShareData);
/
/
解压
DecSection();
/
/
解密代码段
DecIat(ShareData);
/
/
加密IAT
FixReloca(ShareData);
/
/
修复重定位
CallTls(ShareData);
/
/
处理TLS
Debugging();
/
/
反调试
__asm
{
mov eax, gImageBase
/
/
获取当前进程gImageBase
mov ebx, ShareData.DestOEP
/
/
获取原程序的OEP
add eax,ebx
jmp eax
}
}
}
/
/
打开 壳代码的DLL 文件,获取基址
VOID Pack::OpenDllFile(LPCSTR Path) {
/
/
加载模块到内存中,并且不调用DllMain
DllBase
=
(DWORD)LoadLibraryEx(Path, NULL, DONT_RESOLVE_DLL_REFERENCES);
/
/
获取导出函数StartOfsset地址
StartOfsset
=
(DWORD)GetProcAddress((HMODULE)DllBase,
"start"
);
if
(!StartOfsset)
print
(
"获取DLLMain的导出函数失败"
);
StartOfsset
=
StartOfsset
-
DllBase
-
(DWORD)GetSecHeadAddr(DllBase, DllSecName)
-
>VirtualAddress;
/
/
获取导出变量通讯结构体,加壳器需要使用到
pShareData
=
(SHARE
*
)GetProcAddress((HMODULE)DllBase,
"ShareData"
);
}
/
/
打开 壳代码的DLL 文件,获取基址
VOID Pack::OpenDllFile(LPCSTR Path) {
/
/
加载模块到内存中,并且不调用DllMain
DllBase
=
(DWORD)LoadLibraryEx(Path, NULL, DONT_RESOLVE_DLL_REFERENCES);
/
/
获取导出函数StartOfsset地址
StartOfsset
=
(DWORD)GetProcAddress((HMODULE)DllBase,
"start"
);
if
(!StartOfsset)
print
(
"获取DLLMain的导出函数失败"
);
StartOfsset
=
StartOfsset
-
DllBase
-
(DWORD)GetSecHeadAddr(DllBase, DllSecName)
-
>VirtualAddress;
/
/
获取导出变量通讯结构体,加壳器需要使用到
pShareData
=
(SHARE
*
)GetProcAddress((HMODULE)DllBase,
"ShareData"
);
}
/
/
添加并拷贝一个新区段
VOID Pack::CopySection(LPCSTR DestName) {
if
(strlen(DestName) >
7
)
print
(
"新区段名称太长"
);
/
/
获取需要添加的区段
auto pLastSection
=
IMAGE_FIRST_SECTION(pNtHead(PeBase))
+
(pFileHead(PeBase)
-
>NumberOfSections
-
1
);
auto pNewSection
=
pLastSection
+
1
;
/
/
获取区段头的首地址
auto SrcAddr
=
GetSecHeadAddr(DllBase, DllSecName);
/
/
拷贝区段头
memcpy(pNewSection, SrcAddr, sizeof(IMAGE_SECTION_HEADER));
/
/
修改属性
pNewSection
-
>VirtualAddress
=
pLastSection
-
>VirtualAddress
+
AlignmentToSize(pLastSection
-
>Misc.VirtualSize, pOptionHead(PeBase)
-
>SectionAlignment);
pNewSection
-
>PointerToRawData
=
pLastSection
-
>PointerToRawData
+
AlignmentToSize(pLastSection
-
>SizeOfRawData, pOptionHead(PeBase)
-
>FileAlignment);
/
/
Name
memcpy(pNewSection
-
>Name, DestName, strlen(DestName));
/
/
NumberOfSections
pFileHead(PeBase)
-
>NumberOfSections
+
=
1
;
/
/
SizeOfImage大小
pOptionHead(PeBase)
-
>SizeOfImage
+
=
AlignmentToSize(pNewSection
-
>Misc.VirtualSize, pOptionHead(PeBase)
-
>SectionAlignment);
/
/
从新分配空间,将新区段添加到堆空间中
PeSize
=
pNewSection
-
>SizeOfRawData
+
pNewSection
-
>PointerToRawData;
PeBase
=
(DWORD)realloc((VOID
*
)PeBase, PeSize);
return
;
}
/
/
添加并拷贝一个新区段
VOID Pack::CopySection(LPCSTR DestName) {
if
(strlen(DestName) >
7
)
print
(
"新区段名称太长"
);
/
/
获取需要添加的区段
auto pLastSection
=
IMAGE_FIRST_SECTION(pNtHead(PeBase))
+
(pFileHead(PeBase)
-
>NumberOfSections
-
1
);
auto pNewSection
=
pLastSection
+
1
;
/
/
获取区段头的首地址
auto SrcAddr
=
GetSecHeadAddr(DllBase, DllSecName);
/
/
拷贝区段头
memcpy(pNewSection, SrcAddr, sizeof(IMAGE_SECTION_HEADER));
/
/
修改属性
pNewSection
-
>VirtualAddress
=
pLastSection
-
>VirtualAddress
+
AlignmentToSize(pLastSection
-
>Misc.VirtualSize, pOptionHead(PeBase)
-
>SectionAlignment);
pNewSection
-
>PointerToRawData
=
pLastSection
-
>PointerToRawData
+
AlignmentToSize(pLastSection
-
>SizeOfRawData, pOptionHead(PeBase)
-
>FileAlignment);
/
/
Name
memcpy(pNewSection
-
>Name, DestName, strlen(DestName));
/
/
NumberOfSections
pFileHead(PeBase)
-
>NumberOfSections
+
=
1
;
/
/
SizeOfImage大小
pOptionHead(PeBase)
-
>SizeOfImage
+
=
AlignmentToSize(pNewSection
-
>Misc.VirtualSize, pOptionHead(PeBase)
-
>SectionAlignment);
/
/
从新分配空间,将新区段添加到堆空间中
PeSize
=
pNewSection
-
>SizeOfRawData
+
pNewSection
-
>PointerToRawData;
PeBase
=
(DWORD)realloc((VOID
*
)PeBase, PeSize);
return
;
}
/
/
根据大小以及对齐粒度获取对齐大小
DWORD Pack::AlignmentToSize(DWORD Size, DWORD Algmt) {
return
(Size
/
Algmt)?(((Size
/
Algmt)
+
1
)
*
Algmt):Algmt;
}
/
/
根据大小以及对齐粒度获取对齐大小
DWORD Pack::AlignmentToSize(DWORD Size, DWORD Algmt) {
return
(Size
/
Algmt)?(((Size
/
Algmt)
+
1
)
*
Algmt):Algmt;
}
/
/
设置OEP
VOID Pack::SetOep() {
/
/
在重定位之前,保存原程序OEP
pShareData
-
>DestOEP
=
pOptionHead(PeBase)
-
>AddressOfEntryPoint;
/
/
设置OEP为壳代码OEP
pOptionHead(PeBase)
-
>AddressOfEntryPoint
=
StartOfsset
+
GetSecHeadAddr(PeBase,
".pack"
)
-
>VirtualAddress;
}
/
/
设置OEP
VOID Pack::SetOep() {
/
/
在重定位之前,保存原程序OEP
pShareData
-
>DestOEP
=
pOptionHead(PeBase)
-
>AddressOfEntryPoint;
/
/
设置OEP为壳代码OEP
pOptionHead(PeBase)
-
>AddressOfEntryPoint
=
StartOfsset
+
GetSecHeadAddr(PeBase,
".pack"
)
-
>VirtualAddress;
}
/
/
加密区段
VOID Pack::Encryption(CHAR
*
SectionName) {
/
/
找到需要加密的区段
auto SectionHead
=
GetSecHeadAddr(PeBase, SectionName);
/
/
加密的大小和加密起始地址
DWORD Size
=
SectionHead
-
>Misc.VirtualSize;
CHAR
*
Address
=
(CHAR
*
)(SectionHead
-
>PointerToRawData
+
PeBase);
for
(size_t i
=
0
; i < Size; i
+
+
){
*
Address ^
=
0x15
;
Address
+
+
;
}
}
/
/
加密区段
VOID Pack::Encryption(CHAR
*
SectionName) {
/
/
找到需要加密的区段
auto SectionHead
=
GetSecHeadAddr(PeBase, SectionName);
/
/
加密的大小和加密起始地址
DWORD Size
=
SectionHead
-
>Misc.VirtualSize;
CHAR
*
Address
=
(CHAR
*
)(SectionHead
-
>PointerToRawData
+
PeBase);
for
(size_t i
=
0
; i < Size; i
+
+
){
*
Address ^
=
0x15
;
Address
+
+
;
}
}
/
/
压缩
VOID Pack::Compression()
{
int
SecTextSize
=
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData;
pShareData
-
>SizeOfRawData
=
SecTextSize;
char
*
TextSecData
=
(char
*
)(GetSecHeadAddr(PeBase,
".text"
)
-
>PointerToRawData
+
PeBase);
/
/
被压缩的数据,Packed保存压缩数据的空间,WorkMem为完成压缩需要使用的空间
char
*
Packed
=
(char
*
)malloc(aP_max_packed_size(SecTextSize));
char
*
WorkMem
=
(char
*
)malloc(aP_workmem_size(SecTextSize));
/
/
压缩后的大小
int
OutSize
=
aPsafe_pack(TextSecData, Packed, SecTextSize, WorkMem, NULL, NULL);
/
/
对齐后的大小
int
AlignSize
=
OutSize
%
0x200
=
=
0
? OutSize : (OutSize
/
0x200
+
1
)
*
0x200
;
/
/
新空间大小
DWORD NewFileSize
=
PeSize
-
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData
+
AlignSize;
/
/
申请新的空间大小 文件大小
-
区段在文件中的大小
+
压缩后的大小(不对齐)
DWORD NewFileBase
=
(DWORD)malloc(NewFileSize);
/
/
TextSecData之前的数据
DWORD PreText
=
GetSecHeadAddr(PeBase,
".text"
)
-
>PointerToRawData
-
1
;
/
/
拷贝TextSecData段之前的数据
memcpy((LPVOID)NewFileBase, (LPVOID)PeBase, PreText);
/
/
拷贝压缩部分的数据
memcpy((LPVOID)(NewFileBase
+
PreText
+
1
), Packed, OutSize);
/
/
拷贝TextSecData段后面的数据
LPVOID DestAddr
=
(LPVOID)(NewFileBase
+
PreText
+
AlignSize
+
1
);
DWORD TextSecSize
=
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData;
DWORD TextSecPointRaw
=
GetSecHeadAddr(PeBase,
".text"
)
-
>PointerToRawData;
LPVOID SrcAddr
=
(LPVOID)(PeBase
+
TextSecSize
+
TextSecPointRaw);
DWORD LastSize
=
NewFileSize
-
PreText
-
AlignSize;
memcpy(DestAddr, SrcAddr, LastSize);
/
/
free(&FileBase);
PeBase
=
NewFileBase;
/
/
free((void
*
)NewFileBase);
NewFileBase
=
NULL;
/
/
1.
获取到目标模块的区段表
auto Sections
=
IMAGE_FIRST_SECTION(pNtHead(PeBase));
/
/
2.
使用文件头中的区段数量遍历区段表
WORD Count
=
pFileHead(PeBase)
-
>NumberOfSections;
BOOL
bChangeFoa
=
FALSE;
for
(WORD i
=
0
; i < Count;
+
+
i)
{
if
(bChangeFoa) {
Sections[i].PointerToRawData
=
Sections[i].PointerToRawData
-
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData
+
AlignSize;
}
/
/
3.
.text区段之前的区段不改变,操作.text区段之后的区段
if
(!memcmp(Sections[i].Name,
".text"
,
7
)) {
bChangeFoa
=
TRUE;
}
}
pShareData
-
>TextCompressSize
=
OutSize;
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData
=
AlignSize;
pShareData
-
>TextRVA
=
GetSecHeadAddr(PeBase,
".text"
)
-
>VirtualAddress;
PeSize
=
NewFileSize;
}
/
/
压缩
VOID Pack::Compression()
{
int
SecTextSize
=
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData;
pShareData
-
>SizeOfRawData
=
SecTextSize;
char
*
TextSecData
=
(char
*
)(GetSecHeadAddr(PeBase,
".text"
)
-
>PointerToRawData
+
PeBase);
/
/
被压缩的数据,Packed保存压缩数据的空间,WorkMem为完成压缩需要使用的空间
char
*
Packed
=
(char
*
)malloc(aP_max_packed_size(SecTextSize));
char
*
WorkMem
=
(char
*
)malloc(aP_workmem_size(SecTextSize));
/
/
压缩后的大小
int
OutSize
=
aPsafe_pack(TextSecData, Packed, SecTextSize, WorkMem, NULL, NULL);
/
/
对齐后的大小
int
AlignSize
=
OutSize
%
0x200
=
=
0
? OutSize : (OutSize
/
0x200
+
1
)
*
0x200
;
/
/
新空间大小
DWORD NewFileSize
=
PeSize
-
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData
+
AlignSize;
/
/
申请新的空间大小 文件大小
-
区段在文件中的大小
+
压缩后的大小(不对齐)
DWORD NewFileBase
=
(DWORD)malloc(NewFileSize);
/
/
TextSecData之前的数据
DWORD PreText
=
GetSecHeadAddr(PeBase,
".text"
)
-
>PointerToRawData
-
1
;
/
/
拷贝TextSecData段之前的数据
memcpy((LPVOID)NewFileBase, (LPVOID)PeBase, PreText);
/
/
拷贝压缩部分的数据
memcpy((LPVOID)(NewFileBase
+
PreText
+
1
), Packed, OutSize);
/
/
拷贝TextSecData段后面的数据
LPVOID DestAddr
=
(LPVOID)(NewFileBase
+
PreText
+
AlignSize
+
1
);
DWORD TextSecSize
=
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData;
DWORD TextSecPointRaw
=
GetSecHeadAddr(PeBase,
".text"
)
-
>PointerToRawData;
LPVOID SrcAddr
=
(LPVOID)(PeBase
+
TextSecSize
+
TextSecPointRaw);
DWORD LastSize
=
NewFileSize
-
PreText
-
AlignSize;
memcpy(DestAddr, SrcAddr, LastSize);
/
/
free(&FileBase);
PeBase
=
NewFileBase;
/
/
free((void
*
)NewFileBase);
NewFileBase
=
NULL;
/
/
1.
获取到目标模块的区段表
auto Sections
=
IMAGE_FIRST_SECTION(pNtHead(PeBase));
/
/
2.
使用文件头中的区段数量遍历区段表
WORD Count
=
pFileHead(PeBase)
-
>NumberOfSections;
BOOL
bChangeFoa
=
FALSE;
for
(WORD i
=
0
; i < Count;
+
+
i)
{
if
(bChangeFoa) {
Sections[i].PointerToRawData
=
Sections[i].PointerToRawData
-
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData
+
AlignSize;
}
/
/
3.
.text区段之前的区段不改变,操作.text区段之后的区段
if
(!memcmp(Sections[i].Name,
".text"
,
7
)) {
bChangeFoa
=
TRUE;
}
}
pShareData
-
>TextCompressSize
=
OutSize;
GetSecHeadAddr(PeBase,
".text"
)
-
>SizeOfRawData
=
AlignSize;
pShareData
-
>TextRVA
=
GetSecHeadAddr(PeBase,
".text"
)
-
>VirtualAddress;
PeSize
=
NewFileSize;
}
/
/
令壳代码接管IAT表
VOID Pack::SetIatTo0() {
/
/
在重定位之前设置
pShareData
-
>ImpTableVA
=
pOptionHead(PeBase)
-
>DataDirectory[
1
].VirtualAddress;
/
/
备份原导入表RVA
pOptionHead(PeBase)
-
>DataDirectory[
1
].VirtualAddress
=
0
;
/
/
清零
pOptionHead(PeBase)
-
>DataDirectory[
12
].VirtualAddress
=
0
;
/
/
第[
12
]项也是导入表,也需要清零
}
/
/
令壳代码接管IAT表
VOID Pack::SetIatTo0() {
/
/
在重定位之前设置
pShareData
-
>ImpTableVA
=
pOptionHead(PeBase)
-
>DataDirectory[
1
].VirtualAddress;
/
/
备份原导入表RVA
pOptionHead(PeBase)
-
>DataDirectory[
1
].VirtualAddress
=
0
;
/
/
清零
pOptionHead(PeBase)
-
>DataDirectory[
12
].VirtualAddress
=
0
;
/
/
第[
12
]项也是导入表,也需要清零
}
/
/
备份TLS后清空TLS
VOID Pack::SetTls() {
pShareData
-
>TlsVirtualAddress
=
pOptionHead(PeBase)
-
>DataDirectory[
9
].VirtualAddress;
/
/
如果存在TLS表
if
(pShareData
-
>TlsVirtualAddress) {
pOptionHead(PeBase)
-
>DataDirectory[
9
].VirtualAddress
=
0
;
DWORD TlsFoa
=
RvaToOffset(PeBase, pShareData
-
>TlsVirtualAddress);
auto TlsTable
=
(PIMAGE_TLS_DIRECTORY)(TlsFoa
+
PeBase);
/
/
备份TLS的回调函数
pShareData
-
>TlsCallBackTableVa
=
TlsTable
-
>AddressOfCallBacks;
}
}
/
/
备份TLS后清空TLS
VOID Pack::SetTls() {
pShareData
-
>TlsVirtualAddress
=
pOptionHead(PeBase)
-
>DataDirectory[
9
].VirtualAddress;
/
/
如果存在TLS表
if
(pShareData
-
>TlsVirtualAddress) {
pOptionHead(PeBase)
-
>DataDirectory[
9
].VirtualAddress
=
0
;
DWORD TlsFoa
=
RvaToOffset(PeBase, pShareData
-
>TlsVirtualAddress);
auto TlsTable
=
(PIMAGE_TLS_DIRECTORY)(TlsFoa
+
PeBase);
/
/
备份TLS的回调函数
pShareData
-
>TlsCallBackTableVa
=
TlsTable
-
>AddressOfCallBacks;
}
}
/
/
对壳代码进行重定位
VOID Pack::FixReloc(){
DWORD OldImageBase
=
pOptionHead(DllBase)
-
>ImageBase;
DWORD NewImageBase
=
pOptionHead(PeBase)
-
>ImageBase;
DWORD OldSectionBase
=
GetSecHeadAddr(DllBase,
".text"
)
-
>VirtualAddress;
DWORD NewSectionBase
=
GetSecHeadAddr(PeBase,
".pack"
)
-
>VirtualAddress;
auto Relocs
=
(PIMAGE_BASE_RELOCATION)(DllBase
+
pOptionHead(DllBase)
-
>DataDirectory[
5
].VirtualAddress);
/
/
遍历重定位表
while
(Relocs
-
>SizeOfBlock) {
DWORD OldProtect
=
0
;
VirtualProtect((LPVOID)(DllBase
+
Relocs
-
>VirtualAddress),
0x1000
, PAGE_READWRITE, &OldProtect);
TypeOffset
*
items
=
(TypeOffset
*
)(Relocs
+
1
);
/
/
重定位项数量
int
count
=
(Relocs
-
>SizeOfBlock
-
8
)
/
2
;
/
/
遍历并修复重定位项
for
(
int
i
=
0
; i < count;
+
+
i) {
if
(items[i].
Type
=
=
3
) {
DWORD
*
item
=
(DWORD
*
)(pOptionHead(DllBase)
-
>ImageBase
+
Relocs
-
>VirtualAddress
+
items[i].Offset);
*
item
=
*
item
-
OldImageBase
-
OldSectionBase
+
NewImageBase
+
NewSectionBase;
}
}
VirtualProtect((LPVOID)(DllBase
+
Relocs
-
>VirtualAddress),
0x1000
, OldProtect, &OldProtect);
Relocs
=
(PIMAGE_BASE_RELOCATION)(Relocs
-
>SizeOfBlock
+
(DWORD)Relocs);
}
/
/
关闭源程序的随机基址
/
/
pOptionHead(PeBase)
-
>DllCharacteristics &
=
~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
}
/
/
对壳代码进行重定位
VOID Pack::FixReloc(){
DWORD OldImageBase
=
pOptionHead(DllBase)
-
>ImageBase;
DWORD NewImageBase
=
pOptionHead(PeBase)
-
>ImageBase;
DWORD OldSectionBase
=
GetSecHeadAddr(DllBase,
".text"
)
-
>VirtualAddress;
DWORD NewSectionBase
=
GetSecHeadAddr(PeBase,
".pack"
)
-
>VirtualAddress;
auto Relocs
=
(PIMAGE_BASE_RELOCATION)(DllBase
+
pOptionHead(DllBase)
-
>DataDirectory[
5
].VirtualAddress);
/
/
遍历重定位表
while
(Relocs
-
>SizeOfBlock) {
DWORD OldProtect
=
0
;
VirtualProtect((LPVOID)(DllBase
+
Relocs
-
>VirtualAddress),
0x1000
, PAGE_READWRITE, &OldProtect);
TypeOffset
*
items
=
(TypeOffset
*
)(Relocs
+
1
);
/
/
重定位项数量
int
count
=
(Relocs
-
>SizeOfBlock
-
8
)
/
2
;
/
/
遍历并修复重定位项
for
(
int
i
=
0
; i < count;
+
+
i) {
if
(items[i].
Type
=
=
3
) {
DWORD
*
item
=
(DWORD
*
)(pOptionHead(DllBase)
-
>ImageBase
+
Relocs
-
>VirtualAddress
+
items[i].Offset);
*
item
=
*
item
-
OldImageBase
-
OldSectionBase
+
NewImageBase
+
NewSectionBase;
}
}
VirtualProtect((LPVOID)(DllBase
+
Relocs
-
>VirtualAddress),
0x1000
, OldProtect, &OldProtect);
Relocs
=
(PIMAGE_BASE_RELOCATION)(Relocs
-
>SizeOfBlock
+
(DWORD)Relocs);
}
/
/
关闭源程序的随机基址
/
/
pOptionHead(PeBase)
-
>DllCharacteristics &
=
~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
}
/
/
备份并替换重定位表
VOID Pack::SetReloc() {
/
/
1.
备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,将dll的重定位表替换到原程序的重定位表
/
/
2.
在壳代码中,系统会帮我们修复壳代码的重定位,待原程序解密之后,在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位
DWORD DllImageBase
=
pOptionHead(DllBase)
-
>ImageBase;
/
/
备份原重定位表
pShareData
-
>dwRelocRva
=
pOptionHead(PeBase)
-
>DataDirectory[
5
].VirtualAddress;
pShareData
-
>dwRelocSize
=
pOptionHead(PeBase)
-
>DataDirectory[
5
].Size;
pShareData
-
>OldImageBase
=
pOptionHead(PeBase)
-
>ImageBase;
/
/
Dll重定位表
auto DllBaseReloc
=
(PIMAGE_BASE_RELOCATION)(pOptionHead(DllBase)
-
>DataDirectory[
5
].VirtualAddress
+
DllImageBase);
DWORD DllRelocaSize
=
pOptionHead(DllBase)
-
>DataDirectory[
5
].Size;
/
/
新增区段
AddSection(
".mysec"
, DllRelocaSize);
auto NewSecHed
=
GetSecHeadAddr(PeBase,
".mysec"
);
auto OldSecHed
=
GetSecHeadAddr(DllBase,
".text"
);
auto PackSecHed
=
GetSecHeadAddr(PeBase,
".pack"
);
auto NewRelocaSection
=
(PIMAGE_BASE_RELOCATION)(NewSecHed
-
>PointerToRawData
+
PeBase);
DWORD OldSectionAddr
=
(DWORD)(OldSecHed
-
>VirtualAddress
+
DllBase);
memcpy((DWORD
*
)NewRelocaSection, (DWORD
*
)(DllBaseReloc), DllRelocaSize);
while
(NewRelocaSection
-
>VirtualAddress){
/
/
新的内存页起始RVA
=
原RVA
-
原段基址
+
.pack段基址
NewRelocaSection
-
>VirtualAddress
=
NewRelocaSection
-
>VirtualAddress
-
(OldSectionAddr
-
DllBase)
+
PackSecHed
-
>VirtualAddress;
NewRelocaSection
=
(PIMAGE_BASE_RELOCATION)(NewRelocaSection
-
>SizeOfBlock
+
(DWORD)NewRelocaSection);
}
/
/
替换原程序重定位表
pOptionHead(PeBase)
-
>DataDirectory[
5
].VirtualAddress
=
NewSecHed
-
>VirtualAddress;
pOptionHead(PeBase)
-
>DataDirectory[
5
].Size
=
DllRelocaSize;
}
/
/
备份并替换重定位表
VOID Pack::SetReloc() {
/
/
1.
备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,将dll的重定位表替换到原程序的重定位表
/
/
2.
在壳代码中,系统会帮我们修复壳代码的重定位,待原程序解密之后,在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位
DWORD DllImageBase
=
pOptionHead(DllBase)
-
>ImageBase;
/
/
备份原重定位表
pShareData
-
>dwRelocRva
=
pOptionHead(PeBase)
-
>DataDirectory[
5
].VirtualAddress;
pShareData
-
>dwRelocSize
=
pOptionHead(PeBase)
-
>DataDirectory[
5
].Size;
pShareData
-
>OldImageBase
=
pOptionHead(PeBase)
-
>ImageBase;
/
/
Dll重定位表
auto DllBaseReloc
=
(PIMAGE_BASE_RELOCATION)(pOptionHead(DllBase)
-
>DataDirectory[
5
].VirtualAddress
+
DllImageBase);
DWORD DllRelocaSize
=
pOptionHead(DllBase)
-
>DataDirectory[
5
].Size;
/
/
新增区段
AddSection(
".mysec"
, DllRelocaSize);
auto NewSecHed
=
GetSecHeadAddr(PeBase,
".mysec"
);
auto OldSecHed
=
GetSecHeadAddr(DllBase,
".text"
);
auto PackSecHed
=
GetSecHeadAddr(PeBase,
".pack"
);
auto NewRelocaSection
=
(PIMAGE_BASE_RELOCATION)(NewSecHed
-
>PointerToRawData
+
PeBase);
DWORD OldSectionAddr
=
(DWORD)(OldSecHed
-
>VirtualAddress
+
DllBase);
memcpy((DWORD
*
)NewRelocaSection, (DWORD
*
)(DllBaseReloc), DllRelocaSize);
while
(NewRelocaSection
-
>VirtualAddress){
/
/
新的内存页起始RVA
=
原RVA
-
原段基址
+
.pack段基址
NewRelocaSection
-
>VirtualAddress
=
NewRelocaSection
-
>VirtualAddress
-
(OldSectionAddr
-
DllBase)
+
PackSecHed
-
>VirtualAddress;
NewRelocaSection
=
(PIMAGE_BASE_RELOCATION)(NewRelocaSection
-
>SizeOfBlock
+
(DWORD)NewRelocaSection);
}
/
/
替换原程序重定位表
pOptionHead(PeBase)
-
>DataDirectory[
5
].VirtualAddress
=
NewSecHed
-
>VirtualAddress;
pOptionHead(PeBase)
-
>DataDirectory[
5
].Size
=
DllRelocaSize;
}
/
/
添加一个新区段
VOID Pack::AddSection(LPCSTR Name, DWORD Size) {
PIMAGE_DOS_HEADER pDos
=
pDosHead(PeBase);
PIMAGE_NT_HEADERS pNt
=
pNtHead(PeBase);
/
/
获取需要添加的区段
PIMAGE_SECTION_HEADER pLastSection
=
(IMAGE_FIRST_SECTION(pNt))
+
(pNt
-
>FileHeader.NumberOfSections
-
1
);
PIMAGE_SECTION_HEADER pNewSection
=
pLastSection
+
1
;
/
/
Name
memcpy(pNewSection
-
>Name, Name,
7
);
/
/
VirtualSize
pNewSection
-
>Misc.VirtualSize
=
AlignmentToSize(Size, pNt
-
>OptionalHeader.SectionAlignment);
/
/
VirtualAddress
=
最后一个区段的 VirtualAddress
+
最后一个区段内存大小
pNewSection
-
>VirtualAddress
=
pLastSection
-
>VirtualAddress
+
AlignmentToSize(pLastSection
-
>Misc.VirtualSize, pNt
-
>OptionalHeader.SectionAlignment);
/
/
SizeOfRawData
pNewSection
-
>SizeOfRawData
=
AlignmentToSize(Size, pNt
-
>OptionalHeader.FileAlignment);
/
/
PointerToRawData
=
最后一个区段的 PointerToRawData
+
最后一个区段文件大小
pNewSection
-
>PointerToRawData
=
pLastSection
-
>PointerToRawData
+
AlignmentToSize(pLastSection
-
>SizeOfRawData, pNt
-
>OptionalHeader.FileAlignment);
/
/
Characteristics
pNewSection
-
>Characteristics
=
0xE00000E0
;
/
/
NumberOfSections
pNt
-
>FileHeader.NumberOfSections
+
=
1
;
/
/
SizeOfImage大小
pNt
-
>OptionalHeader.SizeOfImage
+
=
AlignmentToSize(pNewSection
-
>Misc.VirtualSize, pNt
-
>OptionalHeader.SectionAlignment);
/
/
从新分配空间,将新区段添加到堆空间中
PeSize
=
pNewSection
-
>SizeOfRawData
+
pNewSection
-
>PointerToRawData;
PeBase
=
(DWORD)realloc((VOID
*
)PeBase, PeSize);
pNewSection
=
GetSecHeadAddr(PeBase, Name);
memset((DWORD
*
)(pNewSection
-
>PointerToRawData
+
PeBase),
0
, pNewSection
-
>SizeOfRawData);
return
;
}
/
/
添加一个新区段
VOID Pack::AddSection(LPCSTR Name, DWORD Size) {
PIMAGE_DOS_HEADER pDos
=
pDosHead(PeBase);
PIMAGE_NT_HEADERS pNt
=
pNtHead(PeBase);
/
/
获取需要添加的区段
PIMAGE_SECTION_HEADER pLastSection
=
(IMAGE_FIRST_SECTION(pNt))
+
(pNt
-
>FileHeader.NumberOfSections
-
1
);
PIMAGE_SECTION_HEADER pNewSection
=
pLastSection
+
1
;
/
/
Name
memcpy(pNewSection
-
>Name, Name,
7
);
/
/
VirtualSize
pNewSection
-
>Misc.VirtualSize
=
AlignmentToSize(Size, pNt
-
>OptionalHeader.SectionAlignment);
/
/
VirtualAddress
=
最后一个区段的 VirtualAddress
+
最后一个区段内存大小
pNewSection
-
>VirtualAddress
=
pLastSection
-
>VirtualAddress
+
AlignmentToSize(pLastSection
-
>Misc.VirtualSize, pNt
-
>OptionalHeader.SectionAlignment);
/
/
SizeOfRawData
pNewSection
-
>SizeOfRawData
=
AlignmentToSize(Size, pNt
-
>OptionalHeader.FileAlignment);
/
/
PointerToRawData
=
最后一个区段的 PointerToRawData
+
最后一个区段文件大小
pNewSection
-
>PointerToRawData
=
pLastSection
-
>PointerToRawData
+
AlignmentToSize(pLastSection
-
>SizeOfRawData, pNt
-
>OptionalHeader.FileAlignment);
/
/
Characteristics
pNewSection
-
>Characteristics
=
0xE00000E0
;
/
/
NumberOfSections
pNt
-
>FileHeader.NumberOfSections
+
=
1
;
/
/
SizeOfImage大小
pNt
-
>OptionalHeader.SizeOfImage
+
=
AlignmentToSize(pNewSection
-
>Misc.VirtualSize, pNt
-
>OptionalHeader.SectionAlignment);
/
/
从新分配空间,将新区段添加到堆空间中
PeSize
=
pNewSection
-
>SizeOfRawData
+
pNewSection
-
>PointerToRawData;
PeBase
=
(DWORD)realloc((VOID
*
)PeBase, PeSize);
pNewSection
=
GetSecHeadAddr(PeBase, Name);
memset((DWORD
*
)(pNewSection
-
>PointerToRawData
+
PeBase),
0
, pNewSection
-
>SizeOfRawData);
return
;
}
/
/
拷贝区段数据
VOID Pack::CopySecData(CHAR
*
DestName) {
/
/
.text的地址
CHAR
*
Src
=
(CHAR
*
)(GetSecHeadAddr(DllBase,
".text"
)
-
>VirtualAddress
+
DllBase);
/
/
.pack的地址
CHAR
*
Dest
=
(CHAR
*
)(GetSecHeadAddr(PeBase, DestName)
-
>PointerToRawData
+
PeBase);
memcpy(Dest, Src, GetSecHeadAddr(DllBase,
".text"
)
-
>Misc.VirtualSize);
return
;
}
/
/
拷贝区段数据
VOID Pack::CopySecData(CHAR
*
DestName) {
/
/
.text的地址
CHAR
*
Src
=
(CHAR
*
)(GetSecHeadAddr(DllBase,
".text"
)
-
>VirtualAddress
+
DllBase);
/
/
.pack的地址
CHAR
*
Dest
=
(CHAR
*
)(GetSecHeadAddr(PeBase, DestName)
-
>PointerToRawData
+
PeBase);
memcpy(Dest, Src, GetSecHeadAddr(DllBase,
".text"
)
-
>Misc.VirtualSize);
return
;
}
/
/
将新文件写入磁盘
VOID Pack::WriteToFile(LPCSTR Path) {
HANDLE hFile
=
CreateFile(Path, GENERIC_WRITE,
0
, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD WriteSize
=
0
;
DWORD Ret
=
WriteFile(hFile, (LPVOID)PeBase, PeSize, &WriteSize, NULL);
if
(!Ret)
print
(
"写入文件失败"
);
CloseHandle(hFile);
return
;
}
/
/
将新文件写入磁盘
VOID Pack::WriteToFile(LPCSTR Path) {
HANDLE hFile
=
CreateFile(Path, GENERIC_WRITE,
0
, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD WriteSize
=
0
;
DWORD Ret
=
WriteFile(hFile, (LPVOID)PeBase, PeSize, &WriteSize, NULL);
if
(!Ret)
print
(
"写入文件失败"
);
CloseHandle(hFile);
return
;
}
/
/
对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
/
/
去除所有导出函数和导出变量的名称粉碎
extern
"C"
{
__declspec(dllexport) SHARE ShareData;
/
/
导出变量,用于壳代码与加壳器之间的通讯
__declspec(dllexport) __declspec(naked) void start()
/
/
导出函数地址,将会作为新的OEP
{
_asm{
mov eax, fs:[
0x30
]
mov eax, [eax
+
0x8
]
/
/
获取当前进程gImageBase
mov gImageBase, eax
}
GetFunAdd();
/
/
获取GetProcAddress
GetApi();
/
/
获取API
CallShllFun();
/
/
密码弹窗
UnCompression(ShareData);
/
/
解压
DecSection();
/
/
解密代码段
DecIat(ShareData);
/
/
加密IAT
FixReloca(ShareData);
/
/
修复重定位
CallTls(ShareData);
/
/
处理TLS
Debugging();
/
/
反调试
__asm
{
mov eax, gImageBase
/
/
获取当前进程gImageBase
mov ebx, ShareData.DestOEP
/
/
获取原程序的OEP
add eax,ebx
jmp eax
}
}
}
/
/
对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
/
/
去除所有导出函数和导出变量的名称粉碎
extern
"C"
{
__declspec(dllexport) SHARE ShareData;
/
/
导出变量,用于壳代码与加壳器之间的通讯
__declspec(dllexport) __declspec(naked) void start()
/
/
导出函数地址,将会作为新的OEP
{
_asm{
mov eax, fs:[
0x30
]
mov eax, [eax
+
0x8
]
/
/
获取当前进程gImageBase
mov gImageBase, eax
}
GetFunAdd();
/
/
获取GetProcAddress
GetApi();
/
/
获取API
CallShllFun();
/
/
密码弹窗
UnCompression(ShareData);
/
/
解压
DecSection();
/
/
解密代码段
DecIat(ShareData);
/
/
加密IAT
FixReloca(ShareData);
/
/
修复重定位
CallTls(ShareData);
/
/
处理TLS
Debugging();
/
/
反调试
__asm
{
mov eax, gImageBase
/
/
获取当前进程gImageBase
mov ebx, ShareData.DestOEP
/
/
获取原程序的OEP
add eax,ebx
jmp eax
}
}
}
/
/
定义GetProcAddress函数指针
typedef FARPROC(WINAPI
*
MYGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
MYGetProcAddress MyGetProcAddress
=
0
;
void GetFunAdd() {
DWORD Ent;
DWORD Eot;
DWORD Eat;
CHAR Buff[]
=
{
'G'
,
'e'
,
't'
,
'P'
,
'r'
,
'o'
,
'c'
,
'A'
,
'd'
,
'd'
,
'r'
,
'e'
,
's'
,
's'
,
'\0'
};
__asm
{
pushad
mov eax,fs:[
0x30
]
mov eax,[eax
+
0xc
]
mov eax,[eax
+
0x1c
]
/
/
第一个模块
mov eax,[eax]
/
/
kernel模块
mov eax,[eax
+
0x8
]
/
/
kernel基址
mov gKernelBase,eax
mov edx,[eax
+
0x3c
]
add edx,eax
mov edx,[edx
+
0x78
]
add edx,eax
/
/
导出表
mov ebx,[edx
+
0x1c
]
add ebx,eax
mov Eat,ebx
/
/
地址表
mov ebx,[edx
+
0x20
]
add ebx,eax
mov Ent,ebx
/
/
名称表
mov ebx,[edx
+
0x24
]
add ebx,eax
mov Eot,ebx
/
/
序号表
xor ebx, ebx
jmp tag_FristCmp
tag_CmpFunNameLoop:
inc ebx
tag_FristCmp:
mov esi, Ent
mov esi, [ebx
*
0x4
+
esi]
/
/
遍历名称表
lea esi, [esi
+
eax]
/
/
函数名称VA
lea edi, dword ptr Buff
/
/
GetProAddress字符串地址
mov ecx,
0xE
/
/
GetProAddress长度
cld
/
/
清除方向位
repe cmpsb
/
/
循环比较字符
jne tag_cmpFunNameLoop
mov esi,Eot
xor edi, edi
mov di, [ebx
*
2
+
esi]
/
/
序号
/
/
使用序号在地址表中找到函数地址
mov edx, Eat
mov esi, [edx
+
edi
*
4
]
/
/
得到函数地址RVA
lea eax, [esi
+
eax]
/
/
函数地址
mov MyGetProcAddress,eax
/
/
保存函数地址到函数指针
popad
}
}
/
/
定义GetProcAddress函数指针
typedef FARPROC(WINAPI
*
MYGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
MYGetProcAddress MyGetProcAddress
=
0
;
void GetFunAdd() {
DWORD Ent;
DWORD Eot;
DWORD Eat;
CHAR Buff[]
=
{
'G'
,
'e'
,
't'
,
'P'
,
'r'
,
'o'
,
'c'
,
'A'
,
'd'
,
'd'
,
'r'
,
'e'
,
's'
,
's'
,
'\0'
};
__asm
{
pushad
mov eax,fs:[
0x30
]
mov eax,[eax
+
0xc
]
mov eax,[eax
+
0x1c
]
/
/
第一个模块
mov eax,[eax]
/
/
kernel模块
mov eax,[eax
+
0x8
]
/
/
kernel基址
mov gKernelBase,eax
mov edx,[eax
+
0x3c
]
add edx,eax
mov edx,[edx
+
0x78
]
add edx,eax
/
/
导出表
mov ebx,[edx
+
0x1c
]
add ebx,eax
mov Eat,ebx
/
/
地址表
mov ebx,[edx
+
0x20
]
add ebx,eax
mov Ent,ebx
/
/
名称表
mov ebx,[edx
+
0x24
]
add ebx,eax
mov Eot,ebx
/
/
序号表
xor ebx, ebx
jmp tag_FristCmp
tag_CmpFunNameLoop:
inc ebx
tag_FristCmp:
mov esi, Ent
mov esi, [ebx
*
0x4
+
esi]
/
/
遍历名称表
lea esi, [esi
+
eax]
/
/
函数名称VA
lea edi, dword ptr Buff
/
/
GetProAddress字符串地址
mov ecx,
0xE
/
/
GetProAddress长度
cld
/
/
清除方向位
repe cmpsb
/
/
循环比较字符
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-1-4 15:59
被三一米田编辑
,原因: