《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.14)
2016-12-19 08:55
453 查看
1.14. switch()/case/default
1.14.1. case数量较少
x86
未优化MSVC
case数量较少时,相当于数个if/else语句结合。光看汇编代码很难判断源代码是什么。优化后的MSVC
一些优化很有趣:把a的值放在EAX中,用它减去0,用来检查a是否为0。如果ZF设置了(减法结果为0),则JE触发。接下来会分别减1、减2,即分别与1,2比较。另一点是,调用printf()不是用CALL,而是用JMP。字符串指针放在a变量(某个内存地址),这段代码只是手动设置栈内容然后跳转。实际上是为了速度而优化。
OllyDbg
可以识别case语句。ARM:优化Keil(ARM模式)
也是按if实现的。出现了比较多的ADRcc指令,在特定条件下加载字符串地址到R0,下一条Bxx跳转到某个位置,进行函数调用。ARM:优化Keil(Thumb模式)
没有后缀形式,所以与x86差不多。ARM64:未优化GCC
用w0保存输入而不是x0,因为是int类型。用ADRP/ADD将字符串指针参数传给puts()。
ARM64:优化的GCC
用CBZ代替了复杂的指令,如果w0是0就跳转。直接跳转到puts()。MIPS
jr $t9 跳转到puts()LW指令后常有nop,因为load delay slot。
结论:
少量case的switch()与if/else基本没有区别。1.14.2. 大量cases
如果case较多,则用大量JE/JNE指令是不合适的。下面给出了一个5个case的例子。
x86
非优化的MSVC
如果a大于4,直接跳到$LN1@f(错误信息)。如果a小于等于4,把a乘以4,再与LN11@f地址相加,即用一个jmpDWORDPTRLN11@f[ecx*4]。
比如a=2,2*4=8,LN11@ftable+8就是LN4@f,就会跳转到$LN4@f的位置执行。
存在一个跳转或分支表。
npad指令,用来对齐标签到4byte,64位的是16byte。
OllyDbg
input先放到EAX,比较是否大于4,若小于等于,则放到ECX进行ECX*4+address跳转。非优化GCC
唯一的区别是,乘以4这个操作用左移2位替代。然后从ds:off_804855c[eax]取地址跳转。然后JMP EAX。
ARM:优化的Keil(ARM模式)
ARM模式所有指令都是4bytes。ADDCC PC, PC, R0, LSL#2
先用R0左移2位即R0*4,然后加上PC再赋值给PC,即PC<-PC+R0*4。
本来PC值是180,则跳到180+R0*4。注意ADDCC指令位置是178,但执行时PC+2。这实际上是间接取址。
ARM:优化Keil(Thumb模式)
也是用跳转表实现。BL _ARM_common_switch8_thumb
LR作为指向跳转表的指针。
MIPS
逻辑是一样的,利用跳转表。结论:
MOV REG, input CMP REG, 4 JA default SHL REG, 2 MOV REG, jump_table[REG] JMP REG case 1: xxx JMP exit … case 5: xxx JMP exit default: … exit … jump_table dd case 1 dd case 2 dd case 3 dd case 4 dd case 5
跳转指令:
JMP jump_table[REG*4]
1.14.3. 一个块中有很多case
值不连续,而且多个case对应一个代码块。MSVC
有两个表,LN10@f指向a值与某个值的对应,是一个索引。LN11@f是指向代码块的指针。GCC
只用了一个指针表。ARM64:优化GCC
把第一个序号列为1。也是用两个表实现的映射。1.14.4 Fall-through
如果有一个块不加break,用类似if/else实现,只要把代码块按顺序放置即可,然后不加jmp。ARM64
其实逻辑是一样的。练习
把call_printf放在最后,一条语句就够了。call_printf add esp, 4 jmp SHORT $LN9@f
这一段重复了五次。
相关文章推荐
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.7)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.18)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.8-1.9)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.4)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.15-1.17)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.10-1.12)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.1-1.3)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.5-1.6)
- 逆向基础8:循环结构-Reverse Engineering for Beginners
- 设计模式笔记:单例模式(C++代码)
- 创建型模式之 工厂、简单工厂、抽象工厂 简单图析和代码分析 笔记
- 论文笔记 TIE: Principled Reverse Engineering of Types in Binary Programs
- 工作笔记:单例模式的作用好处和代码
- 《大话设计模式》之--第1章 代码无错就是优?----简单工厂模式
- 通用代码学习笔记--单例模式
- 大话设计模式 第1章 代码无错就是优? 简单工厂模式
- Java 基础一些代码练习笔记(策略模式)
- 大话设计模式-第1章代码无错就是优?-简单的工厂模式
- Reverse engineering NAND Flash for fun and profit
- 【笔记】Eclipse and Java for Total Beginners—007