【发布时间】:2019-02-10 01:20:14
【问题描述】:
我正在开发一个 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 应该做什么无关。
为了帮助您,新部分中添加的代码位于文件 stub.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";
并用一些基本的数学代替它,它工作正常。
我的问题是:如何在不破坏可执行文件的情况下使用外部函数?
【问题讨论】:
-
您正在调用运行时的函数,链接器将它们绑定到您的存根,但不幸的是,这些函数位于加密部分... ;-)
-
@frankie 如果我不加密该部分,问题仍然存在。
-
我认为这是因为您添加的部分已被操纵,并将位于错误的地址。无论如何,请考虑公共运行时及其库将始终绑定在您将加密的标准文本部分中。要工作,你的存根必须是一个完整的独立程序,不调用主程序。您可以考虑在存根的任何运行时库中都没有相关的 OS 函数的静态链接,但无论如何您都需要一些包装器代码。重点是避免调用绑定在加密部分中的函数。也意味着您不能使用流或标准 I/O。
-
我忘了告诉你,即使使用静态链接的直接操作系统调用,您也将使用位于 PE 中的跳转表。确保没有加密 IAT(导入地址表),否则您会遇到同样的问题。
标签: c++ c portable-executable