《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.15-1.17)
来源:互联网 发布:电子地图绘制软件 编辑:程序博客网 时间:2024/06/03 16:24
1.15. 循环
1.15.1. 简单例子
x86
x86中的LOOP指令,检查ECX中的值,如果不为0就不断跳到标签重复执行代码。LOOP并不是很方便,一般的编译器也不会用它,所以如果在代码中出现就一定是手写的。
对于for循环中的i值,在x86中,代码的逻辑就是,每次检查EAX的值是否是i的最大值,如果是,就跳出循环,否则不断跳回代码初始位置。
GCC的实现也差不多。上述都是未优化版本。
如果我们把/0x优化标签打开,则此时i不会存在栈中了,而是使用一个单独的寄存器ESI来存放i的值。这是MSVC的版本。
如果用GCC,要用-03参数来打开优化。简直了,GCC简单粗暴,就从2到9全部执行一遍,call printing_function写了八遍。这叫做loop unwinding。如果我们把i的上限提高到100,则GCC会老老实实用上述的循环方式,其中用EBX来分配i的值。
x86: OllyDbg
用ESI来表示i控制循环。ESI最大值为9。
CMP ESI, 0AJL xxxx
x86:tracer
tracer.exe可以手动追踪。
找到PUSH ESI的地址,然后开始追踪。在该地址设置断点,tracer会打印出寄存器的状态。tracer.log
还可以生成载入IDA的文件,查看反汇编和指令执行情况。
ARM
未优化的Keil(ARM模式)
i存在R4寄存器,MOV R4, #2初始化i。
MOV R0,R4BL printing_funcion
以上两条构成循环体
CMP R4,#0xABLT loc_35c
以上两句是比较和分支
优化的Keil(Thumb模式)
差不多,去掉了一些不必要的跳转。
优化的Xcode(LLVM)(Thumb-2模式)
直接把循环展开,还把f()函数内联了,直接调用其中的printf函数,展开了8次。在比较简单函数的情况下用这个比较好。
ARM64:优化的GCC
ARM64:未优化的GCC
这两个似乎没有任何区别。
MIPS
初始化i之后,先检查i的值,再执行循环体。
有些编译器在知道循环体肯定会执行的情况下,把检查i值和循环体执行对调。
1.15.2 内存复制步骤
实际中的内存复制每次迭代复制4或8字节,使用SIMD、向量化。我们给出了一个简单的my_memcpy函数实现,每次复制一个字节。
直接的实现
x64
RDI 目标地址RSI 源地址RDX 块大小mov cl, BYTE PTR [rsi+rax]mov BYTE PTR [rdi+rax]
加载到RSI+i,存储到RDI+i
ARM64
X0 目标地址
X1 源地址
X2 块大小
X3 存放i
Thumb模式
R0 目标地址
R1 源地址
R2 块大小
ARM的ARM模式
充分利用了条件后缀指令。
LDRBCC, STRBCC, ADDCC, BCC
MIPS
新指令:LBU, Load Byte Unsigned,SB,Store Byte。
1.15.3. 结论
ARM中通常用R4表示计数器变量。(类似x86中的ECX)
add [counter], 1 相当于MOV REG, [counter]INC REGMOV [counter], REG
如果循环次数不多,用EBX=[counter]
有时编译器会调动语句块位置,用跳转连接。
1.15.4. 练习
http://challenges.re/54
http://challenges.re/55
http://challenges.re/56
打印出从1到100。
http://challenges.re/57
打印1,4,7,10一直到…
1.16. 简单的C字符串处理
1.16.1. strlen()
其实现是用while()。
const char *eos=str;while(*eos++);return(eos-str-s);
这里利用了str以\0结尾的特性
x86
未优化的MSVC
第一个MOVSX从内存中一个地址读取byte放到32位寄存器。MOV with Sign-Extended,8-31位位数字,1-8为符号补位。对于有符号数的复制非常有用。
未优化的GCC
用MOVZX代替了MOVSX。拓展部分用0填充。
可用来替换指令对xor eax, eax/mov al, […]
SETNA:if ZF==0,设置AL为1
SETNZ al,接下来几条表明如果al不为0,跳转到loc_80483F0。
优化的MSVC
EDX存放指向字符串的指针。
EDX放到EAXCL = *EAXEAX++CL==0?
如果不是就继续循环,如果是,计算eax和edx的差,再减1即字符串长度。
优化的MSVC+OllyDbg
优化的GCC
NOT把所有位取反。
ARM
32位ARM
未优化的Xcode4.6.3(LLVM)(ARM模式)
两个变量:eos, str。先把两个变量存到栈上。循环从loc_2CB8开始,eos->R0,R0+1->eos,LDRSB与x86中的MOVSX相同,从内存地址读并拓展到32位。string->R0,然后是CMP和BEQ。
优化的Xcode4.6.3(LLVM)(Thumb模式)
不一样的是不需要栈了,直接把str放在R0,eos放在R1。
LDRB.W R2, [R1], #1 先将R1加载到R2,再R1+1MVNS类似x86中NOT,所有位取反。MVNS R0, R0ADD R0, R1
这两条达到str-eos-1效果。
优化的Keil(ARM模式)
与上面的基本差不多,不过计算str-eos-1的方法发生变化。
SUBEQ R0, R1, R0SUBEQ R0, R0, #1
ARM64
优化的GCC
未优化的GCCC
MIPS
没有NOT指令,有NOR,=OR+NOT。
1.17. 替换算术指令
ADD和SUB可以互换,LEA常用于简单算术运算。
1.17.1. 乘法
使用加法实现乘法
return a*8 用了3次加法实现add eax, eax 这条指令出现三次
使用移位实现乘法
a*4 shl eax, 2 左移两位即可
ARM:LSL r0, r0, #2
GCC:SLL
使用移位、减法、加法实现乘法
即使是乘7或17也能完成(不用乘法)
x86
a*7 EAX=EAX-ECX=ECX*8-ECX=ECX*7=A*7a*28 EAX=a*7,EAX<<2=(a*7)*4=a*28a*17 EAX=EAX<<4=EAX*16=a*16 EAX=EAX+a=a*16+a=a*17
ARM中也一样,与x86实现基本相同。
Thumb模式不太一样,a*28没法优化,要用MULS。
MIPS的a*7和a*17一样,a*8=a0<<5-a0<<2=a0*32-a0*4。
64位
x64
a*7=a*8-aa*28=RID<<5-RDI*4a*17-a<<4+a
ARM64
a*7=a<<3-aa*28=a<<5-a<<2a*17=a+a<<4
Booth乘法算法
使用加法和移位替换乘法
1.17.2. 除法
使用位移实现除法
a/4 shr eax, 2
ARM中是LSR r0, r0, #2
1.17.3. 练习
http://challenges.re/59
其实就是a*7的实现。
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.15-1.17)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.1-1.3)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.4)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.5-1.6)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.7)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.8-1.9)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.10-1.12)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.13)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.14)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.18)
- 逆向基础8:循环结构-Reverse Engineering for Beginners
- tensorflow 学习笔记(1) MNIST for beginners
- Sol's Graphics for Beginners (1)
- Reverse engineering
- Data Analytics for Beginners:第三节
- 试试MNIST For ML Beginners代码
- 学习MNIST For ML Beginners笔记
- Tutorial #1 : What is Reverse Engineering
- Thrift源码分析(二)-- 协议和编解码
- 详解Dagger2
- ORB特征
- 448. [LeetCode]Find All Numbers Disappeared in an Array
- Java数据结构和算法-归并排序的递归应用
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.15-1.17)
- Oracle Hints详解
- 郝斌数据结构 47 循环队列程序演示
- ws2812/6810 RGB灯带在高通芯片上的控制
- 2016 11月 超级计算机排名
- Android个人项目 高仿微信主界面设计(上)
- Objective-c - 点语法
- block与delegate的认识
- Java IO流 讲解