OD汇编指令 |
|
NOP |
无操作 |
PUSH |
将数据压如堆栈中 |
POP |
出栈(与PUSH相反) |
PUSHAD |
所有通用寄存器的内容按一定顺序压入到堆栈中,相当于 ’PUSH EAX,PUSH ECX,PUSH EDX,PUSH EBX,PUSH ESP,PUSH EBP,PUSH ESI, PUSH EDI’ |
POPAD |
该指令与PUSHAD正好相反,它从堆栈中取值,并将它们放到相应的寄存器中,等价于 “POP EDI,POP ESI,POP ESP,POP ESP,POP EBX,POP EDX,POP ECX,POP EAX” |
MOV |
该指令将第二个操作数赋值给第一个操作数 MOV EAX, EBX 释:EBX值赋值给EAX MOVSX (带符号扩展的传送指令) 第二个操作数可能是一个寄存器也可能是一个内存单元,第一个操作数的位数比第二个操作数多,第二个操作数的符号位填充第一个操作数剩余部分 MOVZX (带0扩展的传送指令) 类似于MOVSX,但是这种情况下剩余的部分不根据操作数的正负来进行填充,剩余的部分总是被填充为0 |
LEA |
(取地址指令) 类似于MOV指令, 但是第一个操作数是一个通用寄存器,并且第二个操作数是一个内存单元。 当计算的时候要依赖于之前的结果的话,那么这个指令就非常有用 |
XCHG |
交换 寄存器/内存单元 和 寄存器 |
OD数学指令 |
|
INC |
执行增加,如果是INC指令的话,就加1 |
DEC |
执行减少,如果是DEC指令的话,就减1 |
ADD |
ADD指令有两个操作数,相加后的结果存放到第一个操作数中,ADD EAX,1等价于INC EAX |
ADC |
(带进位的加法) 两个操作数的和加上进位标志的值,结果存放到第一个操作数中 |
SUB |
这个指令与ADD刚好相反,它将第一个操作数减去第二个操作数的值存放到第一个操作数中 |
SBB |
该指令跟ADC正好相反,它计算两个操作数的差值,并且还要减去进位标志,结果存放到第一个操作数中 |
MUL |
(无符号数的乘法)有两种乘法: 第一种只有一个操作数,另一个操作数是EAX,结果存放到EDX:EAX中,比如: MUL ECX 第二种有两个操作数,两个操作数相乘,结果存放于EDX:EAX中,比如: MUL DWORD PTR DS:[405000] |
IMUL |
(有符号数的乘法) IMUL指令用法类似于MUL,例如:IMUL ECX 该指令将有有符号数ECX乘以EAX,结果存放到EDX:EAX中注:1.除了上面一条指令外,IMUL还允许使用多个操作数,这是与MUL不同的地方2.尽管在默认情况下是使用EAX和EDX寄存器,但是我们还可以指定其他的数据源以及目标多达三个操作数;例: 0FAF55E8 IMUL EDX, DWORD PTR [EBP-18] EDX x [EBP-18] -> EDX |
DIV&&IDIV |
无符号除法/有符号除法; 这两个指令反别与MUL和IMUL相反DIV只有一个操作数,该操作数必须是无符号数,结果存放到EDX:EAX中如果是一个操作数的话,那么它和DIV类似,只不过操作数是有符号的,结果依然保存在EDX:EAX中。IDIV两个操作数的情况,第一个操作数除以第二个操作数,结果存放到第一个操作数中。三个操作数的情况,第二个操作数除以第三个操作数,结果存放到第一个操作数中 |
XADD |
(交换并相加) 这个指令其实就是XCHG和ADD两个简单指令的组合 |
NEG |
该指令的目的是将操作数的符号取反,即如果我们有一个32位的16进制数,用NEG操作以后,结果就会取反 |
逻辑指令 |
逻辑指令有两个操作数,两操作数按位运算,并将结果存放到第一个操作数中 |
AND |
只有两个二进制位都为1的时候结果才为1,其他情况,结果都为0;例: AND ECX,EAX 将ECX设置为0001200,EAX设置为3500,1200二进制为01001000000000;3500二进制为11010100000000;两个0取0。对每一位重复此过程,当两位都为1的时候才取1,这两个数中只有一次,两位都是1的情况,按下F7键,我们将看到ECX的值为1000。相当于二进制的01000000000000 |
OR |
该指令与AND的不同之处在于,两位中只要有一位为1,结果就取1; |
XOR |
该指令运算,当两位不同时取1,相同时取0 |
NOT |
该指令是简单的按位取反 |
比较和条件跳转 |
|
CMP CMP EAX, ECX |
该指令是比较两个操作数,实际上,它相当于SUB指令,但是相减的结构并不保存到第一个操作数中。只是根据相减的结果来改变零标志位的,当两个操作数相等的时候,零标志位置1;根据标志的值来决定跳转还是不跳转。 最简单的例子就是配合JZ指令,如果Z标志被置为1,就跳转,否则,就不跳转 |
TEST |
(逻辑比较) TEST EAX,EAX 该指令在一定程序上和CMP指令时类似的,两个数值进行与操作,结果不保存,但是会改变相应标志位(比如说,SF,ZF,PF标志位),程序可以根据结果来决定是否跳转到相应的分支 |
JUMPS |
所有的跳转指令都会指向程序将会跳转到的地址。具体如下: |
|
JMP – 跳转 |
|
JE, JZ – 结果为零则跳转 |
|
JNE, JNZ – 结果不为零则跳转 |
|
JS – 结果为负则跳转 |
|
JNS – 结果不为负则跳转 |
|
JP, JPE – 结果中1的个数为偶数则跳转 |
|
JNP, JNPE – 结果为1的个数为奇数则跳转 |
|
JO – 结果溢出了则跳转 |
|
JNO – 结果没有溢出则跳转 |
|
JB, JNAE – 小于则跳转 (无符号数) |
|
JNB, JAE – 大于等于则跳转 (无符号数) |
|
JBE, JNA – 小于等于则跳转 (无符号数) |
|
JNBE, JA – 大于则跳转(无符号数) |
|
JL, JNGE – 小于则跳转 (有符号数) |
|
JNL, JGE – 大于等于则跳转 (有符号数) |
|
JLE, JNG – 小于等于则跳转 (有符号数) |
|
JNLE, JG – 大于则跳转(有符号数) |
JMP |
这是一个无条件跳转指令,即总是跳转到指定的地址 |
JE或者JZ |
若相等则跳;如果零标志位Z不为0则跳转,即,要求操作的结果为零 |
JNE或JNZ |
若不等则跳转;如果零标志位Z为0则跳转,即,要求操作的结果非零 |
JS |
JS EAX,ECX当比较的结果为负时将跳转,即,就是EAX小于ECX则跳转 |
JNS |
JNS EAX,ECX这个跳转指令与JS刚好相反。当零标志位S为0的时候跳转,也就是说EAX大于ECX的时候跳转 |
JP或JPE |
这个跳转指令是当奇偶标志位P置1的时候才会发生,也就是比较的结果中1的个数要是偶数才会跳转 |
JNP 或JNPE |
这条指令刚好与上一条指令刚好相反,当奇偶标志位P为0的时候跳转。即结果中1的个数为奇数的时候 |
JO |
当发生溢出时,即溢出标志位O置1的时候跳转 |
JNO |
跟上一条指令相反,这里是当溢出标志位O为0时跳转,即溢出没有发生时 |
JB |
第一个操作数小于第二个操作数的时候跳转 |
JNB |
和JB指令相反,这个指令是当进位/借位标志位为0的时候跳转,也就是说,结果为正的时候跳转也就是说第二个第一个操作数大于第二个操作数的时候跳转 |
JBE |
JBE EXA,ECX这个指令是小于或者等于的时候跳转,这是判断两个标志位的,当进位/借位标志位置1或者零标志位Z置1的时候将发生跳转,也就是说,EAX要小于或者等于ECX才会发生跳转 |
JNBE |
这个指令跟JBE刚好相反,当进位/借位标志位C与零标志位Z都为0时候才会发生跳转, |
JL |
这个指令当小于的时候跳转,但是与前面的JB稍微有点不同。这个指令时根据符号标志位S来决定是否跳转; JB比较两个数的时候,将它们两个都看做是正数,即认为它们是无符号数,但是JL指令要考虑符号,这就是这两条指令的主要区别 |
CALL |
是指将转移到指定的子程序处,它的操作数就是给定的地址;例: Call 401362 表示将转移到地址401362处,将调用401362处的子程序,一旦子程序调用完毕就返回到Call指令的下一条语句处,在这种情况下,完成401362的子程序调用以后,则会返回到40124A地址处 |
RET(RETN) |
返回到指定位置,当我们执行到ret指令的时候,栈顶存放的一般是子程序的返回地址; 也就是说ret指令是子程序的结束,也就是说,如果我们call跟进的话,那么ret就能返回到call指令的下一条语句处。当然RET指令不止适用于子程序返回,例如: PUSH 401256 RET 这里将401256压入堆栈。下面的ret指令会将401256当做子程序的返回地址,其实它并不是返回地址,但是执行ret指令后我们依然可以转移到401256地址处。这段代码和JMP 401256指令的功能是一样的 |
循环指令 |
为了实现循环可以使用前面介绍过一些指令。例如,你可以将任意通用寄存器指定为计数器(通常ECX作为计数器使用),你可以将其初始化为需要循环的次数,然后执行循环体,接着计数器递减1,判断计数器是否为0,如果计数器不为0继续重复前面的过程,如果计数器为0,就不继续循环了,而直接执行下面的代码。代码如下: XOR ECX,ECX MOV ECX,15h 将计数器初始化为循环次数15h。接下来就是循环体了: Label: DEC ECX 该计数器每次递减1。其实就是循环体了,循环体里面可以是任意指令。最后,你需要添加一个判断计数器是否为0的指令以及条件跳转指令。 CMP ECX,0 JNE Label |
LOOP |
LOOP指令可以帮我们完成前面例子中的事情 - 将计数器ECX的值减1,判断ECX的值是否为0,如果为0就跳转到指定的地址 -将像前面的例子一样。(可惜的是,大多数现代的处理器中该指令的效率不如前面模拟的例子。) 在DEC ECX指令上单击鼠标右键选择-Binary-Fill with NOPS。对TEST ECX,ECX和JNZ 401007两条指令也进行同样的操作。这三条指令用一条LOOP 401007指令就可以替代 |
LOOPZ LOOPE |
重复循环,直到零标志位Z置1 |
LOOPNZ LOOPNE |
重复循环,直到零标志位Z清0此外,LOOPZ,LOOPNZ指令还将检查零标志位Z是否为0。只有计数器的值和零标志Z同时满足条件时才循环。 |
串操作 |
|
MOVS MOVSD |
该指令是从一个地址向另一个地址复制数据。源地址保存在ESI寄存器中;目的地址保存在EDI寄存器中;例如:MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]这里我们用ESI来保存源地址,EDI来保存目的地址请注意1.ESI,EDI拷贝的方向,拷贝的方向取决于方向标志位D2.MOVS指令不能将数据拷贝到没有写入权限的内存单元中,强制写入的话会引发异常 |
REP |
该指令可做为前面介绍的一些指令的前缀,尤其是MOVS指令。该前缀表示当前指令需要执行的次数ECX。每次循环计数器ECX的值递减1,和前面介绍的循环一样因此,REP MOVS不一定拷贝是4个字节,它拷贝的大小为 每次拷贝的大小 * ECX, 源指针ESI和目的指针EDI每次递增4或者递减4(递增或递减取决于方向标志位D)。 |
LODS |
LODS DWORD PTR DS:[ESI]该指令从源地址(像之前一样,ESI)拷贝数据到EAX中 |
STOS |
该指令是将EAX的值拷贝到EDI指向的内存单元中 |
CMPS |
该指令比较ESI和EDI指向内存单元的内容 |
OD快捷键 |
|
Ctrl+F2 |
重启程序,即重新启动被调试程序。 |
Alt+F2 |
关闭,即关闭被调试程序。 |
F3 |
弹出“打开32位.EXE文件”对话框[Open 32 bit .EXE file],您可以选择可执行文件,并可以输入运行参数。 |
Alt+F5 |
让OllyDbg总在最前面。 |
F7 |
单步步入到下一条命令,如果当前命令是一个函数[Call],则会停在这个函数体的第一条命令上。 |
Shift+F7 |
与F7相同,但是如果被调试程序发生异常而中止,调试器会首先尝试步入被调试程序指定的异常处理。 |
Ctrl+F7 |
自动步入,在所有的函数调用中一条一条地执行命令(就像您按住F7键不放一样,只是更快一些)。 |
F8 |
单步步过到下一条命令。如果当前命令是一个函数,则一次执行完这个函数(除非这个函数内部包含断点,或发生了异常)。 |
Shift+F8 |
与F8相同,但是如果被调试程序发生异常而中止,调试器会首先尝试步过被调试程序指定的异常处理 |
Ctrl+F8 |
自动步过,一条一条的执行命令,但并不进入函数调用内部(就像您按住F8键不放一样,只是更快一些)。 |
F9 |
让程序继续执行. |
Shift+F9 |
与F9相同,但是如果被调试程序发生异常而中止,调试器会首先尝试执行被调试程序指定的异常处理。 |
Ctrl+F9 |
执行直到返回,跟踪程序直到遇到返回,在此期间不进入子函数也不更新CPU数据。 |
Alt+F9 |
执行直到返回到用户代码段,跟踪程序直到指令所属于的模块不在系统目录中,在此期间不进入子函数也不更新CPU数据。 |
Ctrl+F11 |
Run跟踪步入,一条一条执行命令,进入每个子函数调用,并把寄存器的信息加入到Run跟踪的存储数据中。 |
F12 |
停止程序执行,同时暂停被调试程序的所有线程。请不要手动恢复线程运行,最好使用继续执行快捷键或菜单选项(像 F9)。 |
Ctrl+F12 |
Run跟踪 步过,一条一条执行命令,但是不进入子函数调用,,并把寄存器的信息加入到Run跟踪的存储数据中。 |
Alt+B |
显示断点窗口。在这个窗口中,您可以编辑、删除、或跟进到断点处。 |
Alt+C |
显示CPU窗口。 |
Alt+E |
显示模块列表[list of modules]。 |
Alt+K |
显示调用栈[Call stack]窗口。 |
Alt+L |
显示日志窗口。 |
Alt+M |
显示内存窗口。 |
Alt+O |
显示选项对话框[Options dialog] |
Ctrl+P |
显示补丁窗口。 |
Ctrl+T |
打开 暂停 Run跟踪 对话框 |
Alt+X |
关闭 OllyDbg。 |
大多数窗口都支持以下的键盘命令: |
|
Alt+F3 |
关闭当前窗口。 |
Ctrl+F4 |
关闭当前窗口。 |
F5 |
最大化当前窗口或将当前窗口大小改为正常化。 |
F6 |
切换到下一个窗口。 |
Shift+F6 |
切换到前一个窗口。 |
F10 |
打开与当前窗口或面板相关的快捷菜单。 左方向键 显示窗口左方一个字节宽度的内容。 |
Ctrl+左方向键 |
显示窗口左方一栏的内容。 |
Ctrl+右方向键 |
显示窗口右方一栏的内容 |
回车键 |
将选中的命令添加到命令历史[command history]中,如果当前命令是一个跳转、函数或者是转换表的一个部分,则进入到目的地址。 |
退格键 |
移除选中部分的自动分析信息。如果分析器将代码误识别为数据,这个快捷键就非常有用。 |
Alt+退格键 |
撤消所选部分的修改,以备份数据的相应内容替换所选部分。仅当备份数据存在且与所选部分不同时可用。 |
Ctrl+F1 |
如果API帮助文件已经选择,将打开与首个选择行内的符号名相关联的帮助主题。 |
F2 |
在首个选择的命令上开关INT3 断点[Breakpoint],也可以双击该行第二列。 |
Shift+F2 |
在首个选择命令设置条件断点。 |