关于逆向工程
逆向工程(Reverse Engineering,简称RE)
代码逆向工程(Reverse Code Engineering,简称RCE)
逆向分析法
- 静态分析法
- 在不执行代码文件的情形下,对代码进行静态分析的一种方法。
- 动态分析法
- 在程序文件的执行过程中对代码进行动态分析
Hex Editor是一个简单易用的工具,使用它可以轻松地把二进制文件转换为十六进制文件。

“打补丁”与“破解”
对应用程序文件或进程内存内容的更改被称为“打补丁”(Patch),“破解”(Crack)与其含义类似
逆向分析Hello World!程序
OllyDbg: http://www.ollydbg.de
OllyDbg是一种强大的Win32调试工具

入口点
EP是Windows可执行文件(EXE、DLL、SYS等)的代码入口点,是执行应用程序时最先执行的代码的起始位置,它依赖于CPU。
调试器停止的地点即为HelloWorld.exe执行的起始地址,它是一段EP (EntryPoint,入口点)代码。
地址:进程的虚拟内存地址(Virtual Address, VA)
指令:IA32 (或x86) CPU指令
反汇编代码:将OP code转换为便于查看的汇编指令
注释:调试器添加的注释(根据选项不同,显示的注释略有不同)
OllyDbg基本指令
1 | F2: 设置断点/取消断点 |
设置“大本营”的四种方法
1.Goto命令
执行Go to(Ctrl+G)命令

2.设置断点
在OllyDbg菜单栏中依次选择View-Breakpoints选项(快捷键(ALT+B)),打开Breakpoints对话框,列出代码中设置的断点

在断点列表中双击某个断点会直接跳转到相应位置。
3.注释
按键盘上的“;”键可以在指定地址处添加注释,还可以通过查找命令找到它。
在鼠标右键菜单中依次选择Search for-User defined comment,这样就能看到用户输入的所有注释

双击相应注释,光标将自动定位到相应位置。
4.标签
单击鼠标右键,依次选择Search forlUser defined labels菜单即可打开User defined labels窗口,该窗口列出了用户设置的标签
在User defined labels窗口中双击某个标签,光标即移动到相应位置。


快速查找指定代码的四种方法
1.代码执行法
2.字符串检索法
鼠标右键菜单-Search for-All referenced text strings

双击字符串,光标定位到使用该字符串的指令处
VC++中, static字符串会被默认保存为Unicode码形式, static字符串是指在程序内部被硬编码(Hard Coding)的字符串。
API检索法(1):在调用代码中设置断点
鼠标右键菜单-Search for-All intermodular calls

双击它,光标即定位到调用它的地址处
API检索法(2):在API代码中设置断点
鼠标右键菜单-Search for-Name in all calls
在OllyDbg菜单栏中依次选择View-Memory菜单(快捷键Alt+M),打开内存映射窗口。内存映射窗口中显示了一部分HelloWorld.exe进程内存。在图底部的方框中可以看到,USER32库被加载到了内存。

使用OllyDbg中的Name in all modules命令可以列出被加载的DLL文件中提供的所有API。使用Name in all modules命令打开All names窗口,单击Name栏目按名称排序,通过键盘敲出MessageBoxW后,光标会自动定位到MessageBoxW上

双击MessageBoxW函数后就会显示其代码,它实现于USER32.dll库中

模块中的地址和本程序的地址是完全不同的。
修改字符串的两种方法
1.直接修改字符串缓冲区
在Dump窗口中按Ctrl+G快捷键执行Go to命令,在弹出窗口中输入地址进入字符串缓冲区。然后使用鼠标选中地址处的字符串,按Ctrl+E快捷键打开编辑窗口

注意:
若新字符串长度大于原有字符串,执行覆盖操作时可能损坏字符串后面的数据,所以一定要小心。特别是字符串后面有非常重要的数据时,覆盖操作导致数据损坏就会引发程序内存引用错误。
新字符串的长度不应比原字符串长。
保存更改到可执行文件
选中更改后的“Hello Reversing”字符串,单击鼠标右键,在弹出的菜单中选择Copy to executable file菜单

在弹出的Hex窗口中单击鼠标右键,选择Save file菜单,在Save file as对话框中输人文件名“Hello Reversing.exe”后保存为.exe可执行文件。
2.在其他内存区域新建字符串并传递给消息函数




小端序标记法
字节序

字节型: 大小端的字节顺序都是一样的。
大端:低地址放数据的高位
小端:高地址放数据的低位
OD中查看小端序

IA-32寄存器基本讲解
什么是CPU寄存器
寄存器是CPU内部用来存放数据的一些小型存储区域
基本程序运行寄存器
通用寄存器( General Purpose Registers, 32位, 8个)
段寄存器( Segment Registers, 16位, 6个)
程序状态与控制寄存器( Program Status and Control Registers, 32位, 1个)
指令指针寄存器(Instruction Pointer, 32位, 1个)


EAX:(0~31)32位
AX:(0~15)EAX的低16位
AH:(8~15)AX的高8位
AL:(0-7)AX的低8位
循环命令(LOOP)中,ECX用来循环计数(loop count),每执行一次循环,ECX都会减1。EAX一般用在函数返回值中,所有Win32API函数都会先把返回值保存到EAX再返回。
Win32 API函数在内部会使用ECX与EDX
EBP:(SS段中栈内数据指针)扩展基址指针寄存器
ESI:(字符串操作源指针)源变址寄存器
EDI:(字符串操作目标指针)目的变址寄存器
ESP:(SS段中栈指针)栈指针寄存器
ESP指示栈区域的栈顶地址
EBP表示栈区域的基地址,函数被调用时保存ESP的值,函数返回时再把值返回ESP,保证栈不会崩溃,这称为栈帧技术。
ESI和EDI与特定指令(LODS、STOS、REP、MOVS等)一起使用,主要用于内存复制。
段寄存器
段内存记录在SDT(Segment Descriptor Table,段描述符表)
段寄存器就持有这些SDT的索引(index)。
段寄存器有6各个:CS 、SS、DS、ES、FS、GS 每个寄存器大小为16位,2个字节。
每个段寄存器指向的段描述符(Segment Descriptor)与虚拟内存结合,形成一个线性地址(Linear Address),借助分页技术,线性地址最终被转换为实际的物理地址(Physical Address)。
CS: Code Segment,代码段寄存器
SS: Stack Segment,栈段寄存器
DS: Data Segment,数据段寄存器
ES: Extra (Data) Segment,附加(数据)段寄存器
FS: Data Segment,数据段寄存器
GS: Data Segment,数据段寄存器

程序调试中会经常用到FS寄存器,它用于计算SEH(Structured Exception Handler,结构化异常处理机制)、TEB(Thread Environment Block,线程环境块)、PEB(Process Environment Block,进程环境块)等地址
程序状态与控制寄存器
EFLAGS:Flag Register,标志寄存器
其大小为4个字节(32位)
EFLAGS寄存器的每位都有意义,每位的值或为1或为0,代表On/Off或True/False。
ZF(Zero Flag,零标志)
OF(Overflow Flag,溢出标志)
CF(Carry Flag,进位标志)

ZF
若运算结果为0,则其值为1(True),否则其值为0(False)。
OF
有符号整数(signed integer)溢出时, OF值被置为1。此外, MSB (Most Significant Bit,
最高有效位)改变时,其值也被设为1。
CF
无符号整数(unsigned integer)溢出时,其值也被置为1。
指令指针寄存器
EIP:Instruction Pointer,指令指针寄存器
程序运行时,CPU会读取EIP中一条指令的地址,传送指令到指令缓冲区后,EIP寄存器的值自动增加,增加的大小即是读取指令的字节大小。
不能直接修改EIP的值,只能通过其他指令间接修改
栈
(1)暂时保存函数内的局部变量。
(2)调用函数时传递参数。
(3)保存函数返回后的地址。
栈其实是一种数据结构,它按照FILO(First In Last Out,后进先出)的原则存储数据。

栈顶指针(ESP)初始状态指向栈底端。
执行PUSH命令将数据压入栈时,栈顶指针就会上移到栈顶端。
执行POP命令从栈中弹出数据时,若栈为空,则栈顶指针重新移动到栈底端。
栈是一种由高地址向低地址扩展的数据结构
栈是逆向扩展的
从栈中弹出数据后,ESP随之向下移动。
向栈压入数据时,栈顶指针减小,向低地址移动;从栈中弹出数据时,栈顶指针增
加,向高地址移动。
汇编指令

函数参数压入栈时是从最后一个参数开始压入的。
