我是汇编语言的新手,但我仍然不了解大多数说明。
我正在尝试向C程序中添加一些asm行(只是为了好玩,玩它)以修改函数的返回地址。
C代码看起来像
int my_function()
{
int my_number = 1;
__asm__ ("nop");
__asm__ ("nop");
return my_number;
}
int main(int argc, char *argv[])
{
//declarations
...lots of stuff
int my_number = my_function();
do_something;
...lots of stuff
do_other_thing;
... lots of stuff (46 bits in assembler)
return 0;
}
所以,我想做的是在my_function
上一次修改堆栈中的返回地址,因此,返回时,它到达do_other_thing
而不是do_something
< / p>
为了使它变得美观和动态,我不想对返回地址进行硬编码,因此我想添加这46位。我也知道寄信人地址在EBP + 4
中。我已经在x32dgb
中进行了手动测试,并且可以正常工作。
我想我将不得不:
到目前为止,我已经理解了,但是不确定如何将其编码为ASM语句...
你能帮我吗?
答案 0 :(得分:4)
我正在尝试向C程序中添加一些asm行(只是为了好玩,玩它)以修改函数的返回地址。
不要。
对于用C编写的代码;编译器拥有堆栈,编译器生成适合其自身及其优化的函数启动代码,编译器生成适合其自身启动代码的退出代码。任何对堆栈布局进行任何假设的内联程序集都是“易碎的”-任何地方的微小更改(甚至只是更改无害的局部变量,更改编译器命令行arg或将编译器更新到下一个版本)都可能并最终将导致堆栈布局上的差异会破坏内联汇编。实际上,实际情况远比这糟得多-编译器可以并且将生成同一“ C函数”的多个不同版本(并将某些版本内联到其他函数中,以避免函数调用等开销),因此最终试图(并保证会失败)处理多个完全不同的堆栈布局的同一行内联汇编;即使您确实成功返回了其他地方,也无法可靠地避免函数返回后搞砸了一切。
另一个问题是,一开始几乎没有理智的理由要这样做。即使您在完全控制堆栈布局的情况下编写汇编语言(并且不能在无法控制堆栈布局的情况下用内联汇编语言编写C)。
本质上;对于试图学习汇编的人来说,花大量时间对他们花费时间学习更为重要(这不是“脆弱”的,也不是没有用的)。这就像学习如何双手站立时驾驶汽车(使用加速器/制动踏板上的脸,而看不见周围的东西)一样。
答案 1 :(得分:1)
使用内联汇编似乎很危险,正如@Brendan 提到的:
<块引用>对于用 C 编写的代码;编译器拥有堆栈,编译器生成适合自身及其优化的函数启动代码,并且编译器生成适合其自身启动代码的退出代码。任何对堆栈布局做出任何假设的内联程序集都是“脆弱的”...
但是假设“返回地址位于当前函数的堆栈帧的正上方”,也许您可以尝试这样的事情:
void foo(void)
{
uintptr_t *p_return_address = __builtin_frame_address(0) + sizeof(size_t);
*p_return_address = /* the new return address */;
}
然而,如果 foo
由于修改了返回地址而没有返回给它的调用者,那么调用者的结尾将永远不会被执行,进而导致许多其他令人讨厌的问题,例如堆栈溢出。所以,这仍然是一件非常危险的事情。
答案 2 :(得分:-1)
请注意C中的编纂和符号
如@ zx489所述,尝试类似的操作:
__asm__(".intel_syntax prefix");
__asm__("add dword ptr [%ebp + 4], 46");
可能有效...