最近有个课后项目为模拟加载进程实现目标进程的控制,课上老师的具体思路如下:
由于我所测试的PE文件没有重定位表,如果不能VirtualAlloc到指定的ImageBase程序便无法运行。多方查询之后,发现大致的解决思路如下:
减少壳子的外部依赖dll,即尽可能少地隐式加载dll,从而使得目标ImageBase得以保证。
问题的关键在于目标PE的ImageBase必须保证,但是操作系统能保证的只有壳子程序的ImageBase,利用这点特性,我们可以先用壳子程序先站住目标PE所需要的ImageBase,这样就能保证在加载过程中这个基址不会被其他资源占用。启动完毕后,壳子程序主动让出,之后再载入目标PE,这样就能保证目标PE的ImageBase了。
之后便可以在此处成功申请到虚拟内存了。
这种方法相对于楼主网上查的方法,壳子程序的构建难度更低,减少了程序运行时的偶然性,省去了手动GetProcAddress的步骤,在部分细节进行优化后,基本可以保证申请到目标内存。
注意,上面两张图里面,0x420000的内存已经被占用,意味着一旦PE文件的SizeOfImage超过了0x20000,便无法申请成功,楼主现在的思路是在壳子程序的屁股后面加一个空节,VirtualSize设置为目标PE的ImageSize,人为地拉长主模块的长度,这样就可以保证所申请的空间大小足够使用。
以上便是我对该问题的全部看法,如有纰漏,欢迎各位大佬指点纠正。
TCHAR g_lpszFilePath[]
=
TEXT(
"test.exe"
);
DWORD g_dwOffset
=
NULL;
TCHAR g_lpszFilePath[]
=
TEXT(
"test.exe"
);
DWORD g_dwOffset
=
NULL;
HMODULE hModule
=
GetModuleHandle(NULL);
/
/
PEFILE为楼主自定义的类,相关函数功能如其名
PEFILE
*
lpSrcFile
=
new PEFILE((LPVOID)hModule, IMAGE);
DWORD dwSize
=
lpSrcFile
-
>m_pOptionalHeader
-
>SizeOfImage;
HMODULE hModule
=
GetModuleHandle(NULL);
/
/
PEFILE为楼主自定义的类,相关函数功能如其名
PEFILE
*
lpSrcFile
=
new PEFILE((LPVOID)hModule, IMAGE);
DWORD dwSize
=
lpSrcFile
-
>m_pOptionalHeader
-
>SizeOfImage;
/
/
保存EIP偏移
__asm {
mov eax, L0
mov ebx, hModule
sub eax, ebx
mov g_dwOffset, eax
}
/
/
拷贝当前PE
LPVOID lpDesBuffer
=
VirtualAlloc(NULL, dwSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(lpDesBuffer, (LPVOID)hModule, dwSize);
/
/
重定位修复
PEFILE
*
lpNewFile
=
new PEFILE(lpDesBuffer, IMAGE);
lpNewFile
-
>FixupReloc();
/
/
计算jmp跳转的位置
DWORD dwDesAddress
=
(DWORD)lpDesBuffer
+
g_dwOffset;
__asm {
mov eax, dwDesAddress
jmp eax
nop
L0:
nop
}
/
/
保存EIP偏移
__asm {
mov eax, L0
mov ebx, hModule
sub eax, ebx
mov g_dwOffset, eax
}
/
/
拷贝当前PE
LPVOID lpDesBuffer
=
VirtualAlloc(NULL, dwSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(lpDesBuffer, (LPVOID)hModule, dwSize);
/
/
重定位修复
PEFILE
*
lpNewFile
=
new PEFILE(lpDesBuffer, IMAGE);
lpNewFile
-
>FixupReloc();
/
/
计算jmp跳转的位置
DWORD dwDesAddress
=
(DWORD)lpDesBuffer
+
g_dwOffset;
__asm {
mov eax, dwDesAddress
jmp eax
nop
L0:
nop
}
/
/
卸载当前镜像
hModule
=
LoadLibrary(TEXT(
"ntdll.dll"
));
DWORD ZwUnmapViewOfSection
=
(DWORD)GetProcAddress(hModule,
"ZwUnmapViewOfSection"
);
__asm {
push NULL
call GetModuleHandle
push eax
call GetCurrentProcess
push eax
mov eax, ZwUnmapViewOfSection
call eax
}
FreeLibrary(hModule);
/
/
卸载当前镜像
hModule
=
LoadLibrary(TEXT(
"ntdll.dll"
));
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!