在ShellCode中调用功能
Calling functions inside shellcode
我想编译小double(...)
作为x64 shellCode。我已经有一个工作程序来生成用于简单数学操作(例如a + b / a
)的编码程序集,其中a
和b
是该功能的double
参数。
生成的代码被加载到可执行的mmap
缓冲区中,可以稍后调用。
我有以下问题:我想在生成的shellCode内调用math.h
函数,例如sin
,exp
等。由于所有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 } );
相关文章:
- Java等效于C Botan功能调用
- 任何操作员,功能调用和构造函数的通用持续时间表
- WriteConsole访问在功能调用中违反,而不是来自main()
- 级联功能调用
- 在递归功能中,我如何跳到堆栈上的其他功能调用
- 继承多态性功能调用
- 在Google测试框架中,如何期望函数调用或其他功能调用
- 与功能调用混乱
- LLVM插入功能调用到另一个函数中
- 是否可以将功能调用堆栈放在堆上
- 我应该如何理解此功能调用
- SVML的覆盖功能调用
- 中断功能调用与正常功能
- 功能调用不起作用,但控制台仍允许输入
- 明显琐碎的功能调用中未经手的例外
- 复制构造函数和级联功能调用
- C 如何在功能调用中从char *转换为unsigned char *
- 局部静态变量的初始化多个功能调用
- 在每个孩子C 的特定功能调用上调用父函数
- 具有无效*和无效**的灵活功能调用