在ShellCode中调用功能

Calling functions inside shellcode

本文关键字:功能 调用 ShellCode      更新时间:2023-10-16

我想编译小double(...)作为x64 shellCode。我已经有一个工作程序来生成用于简单数学操作(例如a + b / a)的编码程序集,其中ab是该功能的double参数。

生成的代码被加载到可执行的mmap缓冲区中,可以稍后调用。

我有以下问题:我想在生成的shellCode内调用math.h函数,例如sinexp等。由于所有call Opcodes都以某种方式使用32位地址或相对跳跃,因此我无法轻易使用这些说明。因此,我试图以这种方式实现自己的call -Instruction:

lea rax, [rip+0x0] ;load instruction pointer into rax
add rax, <offset-to-return-to>
push rax
moveabs rax, <adress-of-function> ;load the function pointer to rax
jmp rax

这是我生成以下说明的代码:

//lea rax, [rip+0x0]
insertAll(code,std::list<uint8_t>{ 0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00 });
//add rax, <offset-to-return-to>
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC0, <offset-to-return-to>});
//push rax
code.push_back(0x50);
//moveabs rax, address-of-function
uint8_t reg = 0; //rax
uint8_t rexWPrefix = 0x48 + (reg > 8);
uint8_t opCode = 0xB8 + (reg % 8);
insertAll(code,std::list<uint8_t>{ rexWPrefix, opCode });
code.insert(code.end(),reinterpret_cast<uint8_t*>(&fabs),reinterpret_cast<uint8_t*>(&fabs) + 8);
//jmp rax
insertAll(code,std::list<uint8_t>{ 0xFF, 0xE0 });

不幸的是,以这种方式调用函数不起作用,程序会以SIGSEGV错误崩溃。我的汇编代码或指令编码有问题吗?<offset-to-return-to>应该有什么值,让函数返回正确的位置?

免责声明:我知道,这不是处理动态代码的最佳方法...我只能编译动态库,然后加载dlsym。这只是学习组装/壳架的一种有趣方法,不应太认真地对待:)

我发现了三个错误。jmp指令不是绝对的,而是AFAIK RIP-依赖。我使用push + ret作为替代方案,因为ret跳到堆栈上的绝对地址。

此外,我不知道呼叫者必须在堆栈上保留4*8字节的阴影空间是必不可少的。详细信息可以在这里找到。

最后,将功能指针插入指令代码的代码是错误的。我不小心插入了功能代码的前8个字节,而不是指针的值:

code.insert(code.end(),reinterpret_cast<uint8_t*>(&fabs),reinterpret_cast<uint8_t*>(&fabs) + 8);

这是完成的工作代码:

//add rsp,0x20  --> shadow space of 4*8 bytes
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC4, 0x20 } );
//lea rax, [rip+0x0]
insertAll(code,std::list<uint8_t>{ 0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00 });
//add rax, 18
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC0, 18 });
//push rax
code.push_back(0x50);
//moveabs rax, address-of-function
uint8_t reg = 0; //rax
uint8_t rexWPrefix = 0x48 + (reg > 8);
uint8_t opCode = 0xB8 + (reg % 8);
insertAll(code,std::list<uint8_t>{ rexWPrefix, opCode });
void* address = reinterpret_cast<void*>(&my_abs);
code.insert(code.end(),reinterpret_cast<uint8_t*>(&address),reinterpret_cast<uint8_t*>(&address) + sizeof(address));
//push rax
code.push_back(0x50);
//retq
code.push_back(0xC3);
//sub rsp,0x20  --> shadow space of 4*8 bytes
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xEC, 0x20 } );