要在 C 程序中运行任意组装的十六进制指令,通常需要将数据转换为函数指针,然后调用这样的指针。
常见用法
int main(){
void (*ret)() = (void(*)())code;
ret();
return 0;
}
但是,我也遇到了另一种实现相同任务的方法
问题案例
int main() {
(*(void (*)()) code);
return 0;
}
有人可以帮忙解释一下:
当在没有实际调用第二种情况的脚本中的十六进制代码的情况下难以在 GDB 等调试器中跟踪十六进制指令代码时,就会出现问题。
编辑
测试的程序是用 gcc 编译的,并带有以下选项: -fno-stack-protector -z exexcstack
机器测试和 gcc 版本:
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
第二段代码不起作用。未使用的 deref 是空操作。它相当于一个空函数。如果你想避免变量使用((void (*)())code)()
.
例子:
extern char *code;
void run()
{
void (*ret)() = (void(*)())code;
ret();
}
void run0()
{
(*(void (*)()) code);
}
void empty()
{
}
void novar()
{
((void (*)())code)();
}
示例的反汇编 (x86_64):
ex.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <run>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # f <run+0xf>
f: 48 89 45 f8 mov %rax,-0x8(%rbp)
13: 48 8b 55 f8 mov -0x8(%rbp),%rdx
17: b8 00 00 00 00 mov $0x0,%eax
1c: ff d2 callq *%rdx
1e: 90 nop
1f: c9 leaveq
20: c3 retq
0000000000000021 <run0>:
21: 55 push %rbp
22: 48 89 e5 mov %rsp,%rbp
25: 90 nop
26: 5d pop %rbp
27: c3 retq
0000000000000028 <empty>:
28: 55 push %rbp
29: 48 89 e5 mov %rsp,%rbp
2c: 90 nop
2d: 5d pop %rbp
2e: c3 retq
000000000000002f <novar>:
2f: 55 push %rbp
30: 48 89 e5 mov %rsp,%rbp
33: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 3a <novar+0xb>
3a: 48 89 c2 mov %rax,%rdx
3d: b8 00 00 00 00 mov $0x0,%eax
42: ff d2 callq *%rdx
44: 90 nop
45: 5d pop %rbp
46: c3 retq
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句