您的位置:首页 > 编程语言

《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.10-1.12)

2016-12-19 08:45 567 查看

1.10. 关于返回结果

x86中通常用EAX保存返回结果。如果是byte或char类型,用EAX的低位AL。如果是float,用FPU寄存器ST(0)。在ARM中,结果用R0寄存器返回。

1.10.1. 使用返回void函数的结果

因为所有函数都有push eax call exit。所以如果返回值是void,就不会返回任何值。EAX中就会有随机值。

在一个例子中,源代码中没有返回指令。汇编代码中没有push eax但有leave,所以此时EAX中是一些随机的值。我们可以发现返回值为14。这个14取决于调用函数之前的EAX值。

1.10.2. 如果不使用返回结果?

printf()有返回结果,但一般不使用。

其实关键在于,不要让此前没有使用的返回值影响后面的执行(EAX中保留值)。

1.10.3. 返回一个结构

如果需要返回超过一个寄存器能保存的长度的东西(比如结构),就要使用指针。如果返回的是结构,那么就需要用一个指针指向它。

在例子中,指向结构的是$T3853。

整个函数就是修改结构中各变量的值,通过访问它们存放的地址。

1.11. 指针

指针通常用来返回多个值。

1.11.1. 全局变量例子

因为是全局变量,所以不需要返回值。这里使用指针修改全局变量的值。

main函数一开始就会把两个全局变量product和sum的地址入栈,然后f1()就可以调用了。两个全局变量是在数据段分配的。product存在地址00873388,sum存在地址00873384。由于是未初始化的,载入内存之前是放在BSS,载入之后初始化为0,放在.data段。

使用Ollydbg可以看到两个地址的值在函数f1调用后就变化了。

1.11.2. 局部变量例子

f1的代码没有改变,main的代码改变了。不是直接push offset了,而是需要间接访问地址。其他感觉也没啥区别。

1.11.3. 结论

f1可以在内存的任何地址返回指针。C++也是一样的。

1.12. GOTO操作

GOTO被看作anti-pattern。其实很简单,反汇编的时候就是用一个JMP指令实现了这个功能。给了一个直接修改二进制代码patch然后到达skip me输出的例子。

1.12.1. 死代码

没有执行的printf()也叫做死代码。如果开了优化的话,编译器就会把这部分代码省略。不过有趣的是在MSVC2012例子中,skip me字符串并没有被省去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: