WIN32汇编与反汇编
环境:VS2010 + WIN7 64
一、全局变量赋值的汇编形式
1.OllyDbg简介
是汇编级的调试器,我们用的VS是源码级的。
反汇编窗口:显示被调试程序的反汇编代码(地址栏、HEX数据栏、汇编指令栏、注释栏)
寄存器窗口:显示当前所选线程的CPU寄存器的内容
信息窗口: 显示反汇编窗口中选中的第一个命令的参数及一些跳转目标地址、字符串等
数据窗口: 显示内存或文件的内容。
堆栈窗口: 显示当前线程的堆栈
2.调试方式
方式1:用OD调试器直接打开
方式2:附加到已经打开进程
3. 定位地址
Ctrl + G 输入WIN32 API函数名(如:MessageBoxW,MessageBoxA)
4. 断点
方式1:直接在选中的行上按下 F2这样就在当前指令所在地址下一个断点
方式2:bp 指令地址(如果地址是一条指令的中间,那么会出错)
5.PDB文件
全称为"程序数据库"文件。存储了被编译文件的调试信息,大多数场景是调试应用程序
OllyDbg调试器可以读取.pdb文件
6.调试中我们经常要用到的快捷键:
F2:设置断点
F8: 单步步过
F7: 单步步入
F4: 运行到选定位置
F9: 运行
CTRL + F9 执行到返回
ALT + F9 执行到用户代码
7.C++代码内嵌汇编
内嵌汇编: __asm mov aaa,0x778899
二、函数调用的反汇编形式
1、函数与CALL(OD分析代码将函数(子程序)分块)
C/C++函数调用翻译成汇编相当于call(子程序调用)
2、关闭C/C++优化
项目属性配置 -> C/C++ ->优化 -> 禁用/Od
int add (int a, int b)
{
return a+b;
}
优化的:
0134100E C705 18303401 3300000 mov dword ptr [aaa], 33
未被优化的:
01271021 |. 6A 22 push 22 ; /b = 34.
01271023 |. 6A 11 push 11 ; |a = 17.
01271025 |. E8 D6FFFFFF call add ; \add
add函数
00381000 /$ 55 push ebp
00381001 |. 8BEC mov ebp, esp
00381003 |. 8B45 08 mov eax, dword ptr [a]
00381006 |. 0345 0C add eax, dword ptr [b]
00381009 |. 5D pop ebp
0038100A \. C3 ret
3、单步步入:(进入call)
F7(单步步入):按下后执行下一条指令。如果有call则进入call执行
4、单步步过:(不进入call)
F8(单步步过):按下后执行下一条指令。不会进入子函数call里面,
子函数call也被当成一条指令执行
三、加法预算反汇编
分析见代码
012D1012 |. C745 FC 00000000 mov dword ptr [local.1], 0 ; int i = 0;
012D1019 |. 8B45 FC mov eax, dword ptr [local.1] ; eax=i=0
012D101C |. 83C0 64 add eax, 64 ; eax=eax+100=0+100=100=0x64
012D101F |. 8945 FC mov dword ptr [local.1], eax ; i=eax=100=0x64
012D1022 |. 8B4D FC mov ecx, dword ptr [local.1] ; ecx=i=100=0x64
012D1025 |. 81C1 22020000 add ecx, 222 ; ecx=ecx+0x222=0x64+0x222=0x286
012D102B |. 894D FC mov dword ptr [local.1], ecx ; i=ecx=0x286
四、进制与内存单元长度修饰
add [ebx],0x333 01251046 |. 8003 33 add byte ptr [ebx], 33
1.十六进制
十六进制同我们日常的十进制表示法不一样。它由0-9,A-F组成。
与十进制的对应关系是:0-9对应0-9; A-F对应10-15
十进制元素(0,1,2,3,4,5,6,7,8,9)
十六进制元素(0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)
9 + 1 = 10; //十进制
F + 1 = 10; //十六进制
99 + 1 = 100; //十进制 0x64
FF + 1 = 100; //十六进制 1*16^2 + 0*16^1 + 0*16^0 = 256 //0xBDA = 11*16^2 + 13*16 + 10*16^0
十六进制一般会加上前缀0x,汇编中也可以加上h后缀
2、字节,字,双字
字节 (1字节): BYTE类型 (unsigned char) 0-255 表示成十六进制0-0xFF
字 (2字节): WORD类型 (unsigned short) 0-65535 表示成十六进制0-0xFFFF
双字 (4字节) : DWORD类型 (unsigned int) 0-4294967295 表示成十六进制0-0xFFFFFFFF
五、32位通用寄存器
EAX AX AH AL
32 16 8 8
同样的还有:
EBX BX BH BL
ECX CX CH CL
EDX DX DH DL
OD命令行看内存: dd (data dword) dw(data word) db(data byte)
OD命令行看寄存器:? eax / ? ax / ? al
六、MOVSX和MOVZX
MOVSX 符号扩展传送
MOVZX 零扩展传送
1、MOVSX与MOVZX
MOVSX 操作数A,操作数B
MOVZX 操作数A,操作数B
相同点:操作数B所在空间必须小于操作数A
(1)格式与MOV基本相同
(2)能完成小存储单元向大的存储单元的数据传送
比如:movsx eax,bx movzx ebx,ax movsx eax,bx
2.MOVSX,MOVZX与MOV指令区别:
(1)MOVSX,MOVZX的操作数B所占空间必须小于操作数A
(2)MOV指令是原值传送,不会改动。而MOVSX和MOVZX有可能会改动
3.MOVSX与MOVZX区别:
(1)MOVSX将用操作数B的符号位扩展填充操作数A的余下空间:
- 如果是负数则符号位为1
- 如果是正数则符号位为0,和MOVZX功能相同
(2)MOVZX将用0来扩展填充操作数A的余下空间
操作数A —— —— —— ——
操作数B 0 0 —— ——
4.十六进制的正数负数
BYTE(char) 0 - 0xFF 0xFF/2=7F 大于0x7F为负数
WORD(short) 0 - 0xFFFF 0xFFFF/2=7FFF 大于0x7FFF为负数
DOWRD(int) 0 - 0xFFFFFFFF 0xFFFFFFFF/2=7FFFFFFF 大于0x7FFFFFFF为负数
七、LEA指令
1.LEA指令格式
有效的地址传送指令LEA
格式:LEA 操作数A , 操作数B
功能:将操作数B的有效地址传送到指定的某个寄存器,操作数A必须是寄存器
(32位系统上就是32位寄存器)
八、OD使用小结
1.OD调试
重新开始:Ctrl + F2
转到地址:Ctrl + G
断点切换: F2
断点窗口:Alt + B
运行: F9
暂停: F12
单步步过: F8遇到call跳过
单步步入: F7遇到call进入
运行到选定位置:F4
反汇编窗口中跟随: 回车键enter
跟随:回车键enter 进入某个地址
2.右键菜单 - goto
+号:转到下一步
-号:转到上一步
*号:转到当前指令地址
3.命令栏指令
bp 下断点
bc 清除断点
dd 以双字方式显示数据
dw 以字方式显示数据
db 以字节方式显示数据
dc 以字符方式显示数据
? 计算表达式的值
4.OD修改汇编代码
选中汇编指令,按下空格后 直接输入汇编代码