C - 如何 (*(void (*)()) 代码); 运行 在没有任何调用的 C 程序中
C - how does (*(void (*)()) code); run in a C program without any invocation
To 运行 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 [=11=]x10,%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 [=11=]x0,%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 [=11=]x0,%eax
42: ff d2 callq *%rdx
44: 90 nop
45: 5d pop %rbp
46: c3 retq
To 运行 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 [=11=]x10,%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 [=11=]x0,%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 [=11=]x0,%eax
42: ff d2 callq *%rdx
44: 90 nop
45: 5d pop %rbp
46: c3 retq