OD 按下F2断点/关闭断点
跳到被调用的地方的下一条语句

按下回车会鼠标右键选择反汇编窗口中跟随
定位到指定API函数的地方


按下Ctrl + G 或 鼠标右键选择转到->表达式
或者输入命令 bp api函数名

查看所有断点


按下 ALT + B 或 鼠标点击菜单栏 查看->断点
将OD添加到鼠标右键菜单栏


OD断点历史记录文件夹

c或c++内联汇编
1 | // 001_MOV.cpp : 定义控制台应用程序的入口点。 |
MOV指令
aaa=0x889977;
MOV DWORD PTR DS:[0x403018],0x889977
dword 双字 就是四个字节 ptr pointer缩写 即指针 []里的数据是一个地址值
dd指令
查看数据的指令
dd 地址
dd 0x403018 == dd 403018
知识点:
函数与CALL
关闭C/C++优化
单步步过
单步步入
一、函数与CALL
1 | int add(int a,int b) |
二、关闭C/C++优化
项目配置属性—> C/C++ —>优化—>禁用/Od
三、单步步入:(进CALL)
F9(运行): 如果断下后,要继续让程序运行起来,可以用快捷键
F7(单步步入):按下后执行下一条指令。如果有CALL则进入。
四、单步步过:(不进CALL)
F8(单步步过):按下后执行下一条指令。不会进入子函数CALL里边,子函数CALL也被当成一条指令。
这两个单步执行操作的主要区别在于:如果当前的命令是一个子函数,按,将会进入子函数,并停在子函数的第一条命令上;而按,将会一次运行完这个子函数。如果您单步步过的子函数中含有断点或其他调试事件,执行将会被暂停
知识点:
立即寻址
寄存器寻址
寄存器间接寻址
直接寻址方式
直接寻址方式
寄存器相对寻址
一、了解指令常用寻址方式
寻址方式就是寻找操作数或操作数地址的方式。
寄存器是中央处理器内的组成部分。寄存器是一组容量有限的高速存贮部件,它们可用来暂存指令、数据和位址。(DWORD)
1 | MOV EAX,0x1234 //立即寻址 |
二、理解寻址
上边的名字看起来很多,总结起来也就2种方式:
带[]与不带[]
1、不带括号的 有立即数与寄存器
2、带括号的就是指针,从地址里边取值出来。
1 | MOV EAX,0x1234 //立即寻址 eax=0x1234; |
三、对调位置
1 | MOV EAX,0x1234 //立即数不能出现在MOV指令左边。如: MOV 0x1234,EAX 这是错的写法 |
四、代码测试
int *da=a;//int a[0x10]={0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xd,0xe};
//提示 在命令栏中用 dd 地址表达式 可以以DWORD 4字节格式显示指定地址的数据
1 | __asm |
1 | //下边指令,前边是寄存器相对寻址,后边是立即寻址 |
dd命令
1 | dd eax + 2 * 8 |
定位到指定地址


知识点:
加法汇编指令ADD
一、加法指令 ADD(Addition) 格式
格式: ADD A,B //A=A+B;
功能: 两数相加
- OPRD1为任一通用寄存器或存储器操作数,可以是任意一个通用寄存器,而且还可以是任意一个存储器操作数.
OPRD2为立即数,也可以是任意一个通用寄存器操作数.立即数只能用于源操作数B.
- A和B均为寄存器是允许的,一个为寄存器而另一个为存储器也是允许的, 但不允许两个都是存储器操作数.
//也就是说A与B不能同时是指针 如: add [eax],[ebx] 这类情况是错的
例子:
第三课中的add函数里 有如下2句代码
1 | 00401003 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; a |
二、ADD指令测试
1 | int _tmain(int argc, _TCHAR* argv[]) |
OD按下-号可以返回上一步
知识点:
十六进制
字节,字,双字
汇编中的内存单元长度修饰
add [ebx],0x111 //00401048 |. 8003 11 ADD BYTE PTR DS:[EBX],11 ; i=i+11
一、十六进制
十六进制同我们日常中的十进制表示法不一样。它由0-9,A-F,组成。与10进制的对应关系是: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; //十进制 A
F+1=10; //十六进制
99+1=100;//十进制 0x64
FF+1=100;//十六进制 11616=256 //0xBDA=111616+13*16+10
十六进制一般会加上前缀0x 汇编中也可以加上h后缀
//想一想 十六进制中
0x0F+2=0x11 0xF9+1=0xFA 0x10+1=0x11 0x18+8=0x20 8+9=0x11
二、字节,字,双字
字节 (1字节):BYTE类型 ( unsigned char) 0-255 表示成16进制0–0xFF
字 (2字节):WORD类型 (unsigned short) 0-65535, 表示成16进制0–0xFFFF
双字 (4字节):DWORD类型(unsigned long) 0-4294967295 表示成16进制0–0xFFFFFFFF
四字(8字节) QWORD 类型 (unsigned long long ) 64 位整数,Q 代表四(字)
三、汇编中的内存单元长度修饰
1、自动加上修饰前缀规律
后面是寄存器会自动加上前缀修饰符
1 | int pb=3; |
2、必须手动添加内存单元长度修饰的情况
前边是存储器,后边是常量的情况,需要手动添加长度修饰
1 | add [ebx],0x111 //特殊... 因为编译器不知道具体长度,会默认为 字节长度 |
知识点:
寄存器EAX
寄存器AX
寄存器AH
寄存器AL
一、EAX与AX,AH,AL关系图
EAX,EBX,ECX,EDX都有低16位和低8位,高8位寄存器
ESP,EBP,ESI,EDI只有低16位寄存器例如 SP,BP,SI,DI,而没有低8位和高8位
数据查看命令
dd 查看DWORD内存
dw 查看WORD内存
db 查看BYTE内存

一格表示一字节

二、代码测试
1、OD命令栏 ?号指令 (用计显示表达式的值)
? ax 查看ax的值
? eax 查看eax的值
? al 查看al的值
? ah查看ah的值


1 |
|
知识点:
MOVSX符号扩展传送
MOVZX零扩展传送
一、MOVSX与MOVZX格式
MOVSX 操作数A ,操作数B
MOVZX 操作数A ,操作数B
相同点:操作数B 空间必须小于 操作数A
1、格式与MOV基本相同
2、能完成小存储单元向大存储单元的数据传送 比如 movsx eax,bx movzx ebx,ax movsx eax,bx
正确语法:
1 | MOVSX EAX,AX |
错误写法:
1 | MOVSX EAX,EAX //第二个操作数内存等于第一个操作数 |
MOVSX,MOVZX 与MOV指令区别:
1、MOVSX,MOVZX的操作数B所占空间必须小于操作数A.
2、MOV指令是原值传送,不会改动。而MOVSX与MOVZX有可能会改动
MOVSX与MOVZX的区别:
1、MOVSX将用操作数B的符号位扩展填充操作数A的余下空间,如果是负数则符号位为1,如果是正数则和MOVZX功能相同
2、MOVZX将用0来扩展填充操作数A的余下空间。
操作数A

操作数B

二、代码测试
1 | int i=0x888; |
判断有符号十六进制是正数还是负数
char 0-FF //FF/2
DWORD 0-0xFFF 8F8F
最高为大于等于8的是负数,1至7是正数
OD按下F4键可以运行到鼠标指定的指令,前提是程序必须会经过这条指令
知识点:
LEA指令
&与LEA
OD里修改汇编代码 在指定的指令位置按下空格键或
一、LEA指令格式
有效地址传送指令 LEA
格式: LEA 操作数A, 操作数B
功能: 将操作数B的有效地址传送到指定的的某个寄存器,操作数A必须是寄存器。(32位系统上就是32位寄存器)
不能两个操作数都是内存操作的
1 | 错误写法 |
二、C++代码测试
1 | int i; |
三、OD里修改汇编代码
按下空格后 直接输入汇编代码

四、汇编代码测试
1 | int i=0: |
知识点:
OD调试
命令栏指令
一、OD调试
重新开始:Ctrl+F2
转到地址:CTRL+G
断点切换: F2
断点窗口: Alt+B
运行 : F9
暂停 : F12
单步步过: F8 //遇到CALL跳过
单步步入: F7 //遇到CALL进入
运行到选定位置 :F4 //这个主菜单上没有,右键菜单-断点-F4
反汇编窗口中跟随 :回车键enter
跟随: 回车键enter //进入某个地址
执行到返回 CTRL + F9
右键菜单–转到
+号:转到下一步 //Plus
-号:转到上一步 //Minus
*号:转到当前指令地址 //EIP
寄存器窗口:
二、命令栏指令
bp 下断点
bc 清除断点
dd 以双字方式显示数据
dw 以字方式显示数据
db 以字节方式显示数据
? 计算表达式的值
知识点:
汇编减法指令sub
初识标志位
标志寄存器PSW
ZF(零标志)
一、标志寄存器PSW
标志寄存器PSW(程序状态字寄存器PSW)
标志寄存器PSW是一个16为的寄存器。它反映了CPU运算的状态特征并且存放某些控制标志。8086使用了16位中的9位,包括6个状态标志位和3个控制标志位。

CF(进位标志位):当执行一个加法(减法)运算时,最高位产生进位(或借位)时,CF为1,否则为0。
ZF零标志位:若当前的运算结果为零,则ZF为1,否则为0。
SF符号标志位:该标志位与运算结果的最高位相同。即运算结果为负,则SF为1,否则为0。
OF溢出标志位:若运算结果超出机器能够表示的范围称为溢出,此时OF为1,否则为0。判断是否溢出的方法是:进行二进制运算时,最高位的进位值与次高位的进位值进行异或运算,若运算结果为1则表示溢出OF=1,否则OF=0
PF奇偶标志:当运算结果的最低16位中含1的个数为偶数则PF=1否则PF=0
AF辅助进位标志:一个加法(减法)运算结果的低4位向高4位有进位(或借位)时则AF=1否则AF=0
另外还有三个控制标志位用来控制CPU的操作,可以由程序进行置位和复位。
TF跟踪标志:该标志位为方面程序调试而设置。若TF=1,8086/8088CPU处于单步工作方式,即在每条指令执行结束后,产生中断。
IF中断标志位:该标志位用来控制CPU是否响应可屏蔽中断。若IF=1则允许中断,否则禁止中断。
DF方向标志:该标志位用来控制串处理指令的处理方向。若DF=1则串处理过程中地址自动递减,否则自动递增。
OD里能查看到除IF标志外的 8个标志位

二、SUB指令
减法指令SUB (SUBtract)
格式: SUB A,B //A=A-B;
功能: 两个操作数的相减,即从A中减去B,其结果放在A中.
SUB指令会影响标志位
如果SUB EAX,EBX 等于0的话,ZF标志位会置为1,说明两数相等
知识点:
比较指令CMP
条件跳转指令JZ
ZF(零标志)
CMP 和JZ 指令
比较指令CMP
格式: CMP A,B // A-B;
功能: 两个操作数的相减,即从A中减去B,其结果会影响标志位, 对标志位的影响与SUB指令相同。本条指令主要是用于配合条件转移指令使用。如JZ ZF=0时,跳转
条件转移指令 JE/JZ
格式: JE/JZ标号 //等于跳转
功能: ZF=1,转到指定地址执行
说明:
-
指令JE与JZ等价,它们是根据标志位ZF进行转移的指令
-
JE,JZ均为一条指令的两种助记符表示方法
1 | printf("begin\n"); |