C 更改a';呼叫';内存中的地址?
这适用于64位x86英特尔处理器 在GDB中,我可以看到:C 更改a';呼叫';内存中的地址?,c,assembly,x86,gdb,stack,C,Assembly,X86,Gdb,Stack,这适用于64位x86英特尔处理器 在GDB中,我可以看到: 0x400500 <main+50>: call 0x400100 <somefunc> 0x400500:调用0x400100 然而,当我检查0x400500处的内存时,我看不到对“0x400100”的任何引用,也看不到附近寄存器中有任何明显的内容 它如何“知道”在哪里打电话。这似乎很简单,但我还没有找到答案 我正在尝试调用,例如,具有上述函数参数的系统,但只能有限地访问内存。请注意,这只是为了好玩,是挑战
0x400500 <main+50>: call 0x400100 <somefunc>
0x400500:调用0x400100
然而,当我检查0x400500处的内存时,我看不到对“0x400100”的任何引用,也看不到附近寄存器中有任何明显的内容
它如何“知道”在哪里打电话。这似乎很简单,但我还没有找到答案
我正在尝试调用,例如,具有上述函数参数的系统,但只能有限地访问内存。请注意,这只是为了好玩,是挑战练习的一部分
它如何“知道”在哪里打电话
要调用的地址是调用后指令的偏移量
例如:
int foo() { return 42; }
int main() { return foo(); }
gcc -g t.c
gdb -q ./a.out
(gdb) disas/r main
Dump of assembler code for function main:
0x00000000004004f8 <+0>: 55 push %rbp
0x00000000004004f9 <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004004fc <+4>: b8 00 00 00 00 mov $0x0,%eax
0x0000000000400501 <+9>: e8 e7 ff ff ff callq 0x4004ed <foo>
0x0000000000400506 <+14>: 5d pop %rbp
0x0000000000400507 <+15>: c3 retq
End of assembler dump.
(gdb) p &foo
$1 = (int (*)()) 0x4004ed <foo>
(gdb) p/x 0x4004ed - 0x0000000000400506
$2 = 0xffffffe7
intfoo(){return 42;}
int main(){return foo();}
gcc-g t.c
gdb-q./a.out
(gdb)disas/r干管
主功能的汇编程序代码转储:
0x00000000004004f8:55推送%rbp
0x00000000004004f9:48 89 e5 mov%rsp,%rbp
0x000000000004004FC:b8 00 mov$0x0,%eax
0x0000000000400501:e8 e7 ff ff ff callq 0x4004ed
0x0000000000400506:5d pop%rbp
0x0000000000400507:c3 retq
汇编程序转储结束。
(gdb)宝富
$1=(整数(*)()0x4004ed
(gdb)p/x 0x4004ed-0x0000000000400506
$2=0xFFFFFF7
注意
e7 ff ff
字节,它们是callq
的一部分。这是偏移量,用小尾端字母拼写。普通调用指令编码为调用rel32
,具有相对位移而不是绝对位移。一如既往,检查以了解指令是如何编码的
要使GDB的内置反汇编包含原始机器代码字节,请使用disas/r
。(不确定如何在layout asm
/layout reg
中为asm窗口获取该行为)objdump
默认包括机器代码(十六进制)。我在my.bashrc中使用别名disas='objdump-drwC-Mintel'
在GDB中,您不需要修改机器指令中编码的相对位移:您可以将
stepi
放入调用中,然后使用jump*0x1234567
GDB命令在其他地方继续执行或设置$pc=0x1234567
以更改EIP/RIP,而无需执行“继续”
看
所以你让call指令推送一个返回地址并跳转,然后跳转到其他地方,假装你一开始就跳转到了那里。只有在调用
的原始目标可访问的情况下,这才可能起作用;我不确定x86是否只是因为将RIP设置为不可执行内存而出现故障,或者只有在尝试运行第一条指令时才会出现故障。32b还是64b?为什么不发布,在0x400500
中存储了哪些字节?在32b模式下,call$
被组装到e8 fb ff ff
,call
操作码是e8
,接下来的4个字节是与eip
相对的32位偏移量(地址计算时指向下一条指令,即偏移量为-5,以便在无限循环中对自身进行调用
). 从您的反汇编猜测操作码可能是e8 fb ff
.64位,抱歉。将更新问题。打印出呼叫发生的地址,例如0xfffe66e8。不确定您发布了什么,但我在那里没有看到机器代码(e8
call opcode),这就是您想要实现的地址?或者调用
所在的位置?无论如何,从汇编程序的快速测试来看,即使在64b模式下,调用imm32
的计算方法与32b相同,即当前rip
的32位有符号偏移量(该偏移量超出调用
,即+5)。啊,要更改调用地址,我需要更改针对eip的偏移量。这是有道理的,但在GDB中不容易发现。谢谢。现在粘贴正确的输出。谢谢您的回答。关于调用后的跳转,我不确定是否要看程序,但这取决于跳转指令是否可用,对吗?我只能更改8个字节。当它试图在非可执行内存中运行第一条指令时,它是SIGSEGVs。@GhostSparkles:不,我说的是用调试器修改程序状态,而不是修改指令。在断点/单步停止时,您可以直接将RIP
设置为您想要的任何内容。