向 PE 文件添加一个部分,将入口点更改为新部分并执行任何代码
Adding a section to a PE file, change Entry Point to the new section and execute any code
我正在开发 PE 文件加壳程序,我可以成功加密可执行文件的 .text 部分,更改其入口点并添加新部分。新添加的部分将负责解密.text 部分,然后跳转到原始入口点。
现在,我想更进一步,在新部分中执行更多代码。我几乎可以做任何我想做的事情,但是如果我调用外部函数(例如 iostream 中的 cout),修改后的可执行文件将崩溃,同时试图执行非法指令。新部分中存根的反汇编如下所示:
.newsec:0042C020 push ebp
.newsec:0042C021 mov ebp, esp
.newsec:0042C023 push offset loc_40EB50
.newsec:0042C028 mov eax, ds:dword_40E0B0
.newsec:0042C02D push eax
.newsec:0042C02E call loc_41A350
.newsec:0042C033 add esp, 8
.newsec:0042C036 pop ebp
.newsec:0042C037 retn
地址 0x42c033 处的行将跳转到 .text 部分,但那里的代码与 std::cout 应该做什么无关。
为了帮助你帮助我,新部分中添加的代码在文件存根中。h/cpp :
#pragma comment(linker, "/OPT:NOREF")
#pragma optimize( "", off )
#pragma section(".stub",read,write,execute)
__declspec(code_seg(".stub"))
void hello_test()
{
std::cout << "hello world";
}
__declspec(code_seg(".stub"))
void default_stub_start(void) {
__asm {
call hello_test
mov eax, 0x400000 //oep
jmp eax
}
}
然后,整个 .stub 部分将按原样复制到我添加到可执行文件的新部分中。编译运行顺利,但修改后的可执行文件会崩溃,正如我上面解释的那样。如果我删除行
std::cout << "hello world";
并用一些基础数学代替它,效果很好。
我的问题是:如何在不破坏可执行文件的情况下使用外部函数?
我忘记了这个问题,但实际上在问了几个月后找到了解决方案。这里的问题是必须手动 link 到外部函数,因为一旦代码被解压到内存中,它们的地址在 运行 时是未知的。
为此,应执行以下操作:
- 遍历进程环境块以迭代link已加载库的列表。
- 找到库 kernel32.dll 并遍历其导出 table,例如获取 GetProcAddress 和 LoadLibrary 的地址。
- 使用之前解析的 API 加载和解析任何其他 API。
有关更多信息,"The Rootkit Arsenal" 的第 10 章是必读内容。
我正在开发 PE 文件加壳程序,我可以成功加密可执行文件的 .text 部分,更改其入口点并添加新部分。新添加的部分将负责解密.text 部分,然后跳转到原始入口点。
现在,我想更进一步,在新部分中执行更多代码。我几乎可以做任何我想做的事情,但是如果我调用外部函数(例如 iostream 中的 cout),修改后的可执行文件将崩溃,同时试图执行非法指令。新部分中存根的反汇编如下所示:
.newsec:0042C020 push ebp
.newsec:0042C021 mov ebp, esp
.newsec:0042C023 push offset loc_40EB50
.newsec:0042C028 mov eax, ds:dword_40E0B0
.newsec:0042C02D push eax
.newsec:0042C02E call loc_41A350
.newsec:0042C033 add esp, 8
.newsec:0042C036 pop ebp
.newsec:0042C037 retn
地址 0x42c033 处的行将跳转到 .text 部分,但那里的代码与 std::cout 应该做什么无关。
为了帮助你帮助我,新部分中添加的代码在文件存根中。h/cpp :
#pragma comment(linker, "/OPT:NOREF")
#pragma optimize( "", off )
#pragma section(".stub",read,write,execute)
__declspec(code_seg(".stub"))
void hello_test()
{
std::cout << "hello world";
}
__declspec(code_seg(".stub"))
void default_stub_start(void) {
__asm {
call hello_test
mov eax, 0x400000 //oep
jmp eax
}
}
然后,整个 .stub 部分将按原样复制到我添加到可执行文件的新部分中。编译运行顺利,但修改后的可执行文件会崩溃,正如我上面解释的那样。如果我删除行
std::cout << "hello world";
并用一些基础数学代替它,效果很好。
我的问题是:如何在不破坏可执行文件的情况下使用外部函数?
我忘记了这个问题,但实际上在问了几个月后找到了解决方案。这里的问题是必须手动 link 到外部函数,因为一旦代码被解压到内存中,它们的地址在 运行 时是未知的。
为此,应执行以下操作:
- 遍历进程环境块以迭代link已加载库的列表。
- 找到库 kernel32.dll 并遍历其导出 table,例如获取 GetProcAddress 和 LoadLibrary 的地址。
- 使用之前解析的 API 加载和解析任何其他 API。
有关更多信息,"The Rootkit Arsenal" 的第 10 章是必读内容。