正式工做以后打算着手作一些逆向方面的研究,听前辈们的建议,必须先把汇编学会,因而我用第一个月把《汇编语言》(第三版-王爽著)看了一遍,可是人的记忆力是有限的,因此打算以博客的形式再回忆一遍,相信经过这种形式,能让本身对知识理解的更加模块化和具体化,也方便本身往后复习,同时也方便了看到这篇博客的同道中人。编程
汇编语言在整个计算机编程语言中的地位能够说是没什么用,不多有人会直接拿汇编语言去写项目,若是这么干的话,不得麻烦死(可是不排除确实有这种需求的时候的作法)。更多时候汇编语言的使用场景是在反编译别人的二进制代码以后,对汇编代码的逻辑还原,而且对于计算机系统总体的理解,我相信没有什么比学习汇编语言更快、更好。编程语言
寄存器:用于存放cpu的数据信息,共14个,分别是:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW。模块化
字节、字和双字:1双字(DWROD)=2字(WORD)=4字节(byte)。1字节(byte)=8位(bit),好比,寄存器ax是16位寄存器,在内部能够在分为ah和al,分别表明高8位和低8位。oop
内存访问:通常利用寄存器ds,es,ss才能够间接访问内存,好比要访问2000:0200位置的数据,并将该位置的数据传送入ax,应该这样:学习
mov ax,2000h mov ds,ax mov si,200h mov ax,ds:[si]
assume cs:code stack segment db 128 dup (0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,128 ;目前栈顶在ss:sp处(即stack:128),也就是上面定义的stack中的128字节 mov ax,'a' push ax ;将'a'入栈,栈顶在ss:sp处(即stack:126) push ax pop bx ;出栈,将数据保存在bx中 mov ax,4c00h int 21h code ends end start
ZF:是否为0 PF:1的个数是否为偶数 SF:是否为负数 有符号整数,只看结果是否是大于7,也就是首位是否是0 CF:是否存在进位或借位(无符号整数) 直接进行无符号运算,首位进位就置1 OF:是否存在溢出(有符号整数) 16位cpu,有符号溢出范围79H(127),-80H(128) DF:方向标志位,与movsb配合使用
数据传送指令: mov:数据传送 示例:mov ax,bx 说明:将bx中的数据传送到ax中,由于使用的是ax和bx,因此数据的长度是16位,下面的例子都相同,若是有操做数据中有寄存器,那么按照寄存器的数据长度计算 push:入栈 示例:push ax 解释:将ax的数据入栈,传送到ss:sp栈顶处 pop:出栈 示例:pop ax 解释:将ss:sp位置的数据出栈,传送入ax中 pushf:全部标志位入栈 示例:pushf 解释:标志位入栈,防止后面的操做对标志位产生影响的一般作法 popf:标志位出栈 示例:popf 解释:标志位出栈,用于还原入栈的标志位 xchg:交换,目前没用到
算数运算指令 add:加法 示例:add ax,2 解释:将ax中的数据加2,即ax+0002h sub:减法 示例:sub ax,2 解释:将ax中的数据减2,即ax-0002h adc:加法(带符号位) 示例:adc ax,2 ;CF=1 解释:将ax中的数据加3,即ax+0002h+1h sbb:减法(带符号位) 示例:sbb ax,2 ;CF=1 解释:将ax中的数据减3,即ax-0002h-1h inc:自增 示例:inc si 解释:将si中的数据加1,经常使用在循环或条件转移中 dec:自减 示例:dec ax 解释:将ax中的数据减1 cmp:比较 示例:cmp ax,0 解释:至关于减法,ax-0,只不过不影响寄存器的值,而只影响标志寄存器,由于条件转移指令是依据标志寄存器的指令,因此cmp常与条件转移指令配合使用进行条件转移 mul:乘法 示例:mul bx或mul bl 解释:分为两种状况: 1. 指令参数是8位寄存器如bl时,乘数1默认放在al寄存器中,另外一个乘数2放在8位寄存器如bl中,结果存在ax中 2. 指令参数是16位寄存器如bx时,乘数1默认放在ax寄存器中,另外一个乘数2是指定的16位寄存器如bx中的数据,结果的高16位存在dx,低16位存在ax中 div:除法 示例:div bx或div bl 解释:一样分为两种状况: 1. 指令参数是8位寄存器时,被除数(除法前面那个数。。。)则为16位,默认存放于ax中,除数则是存放于指定8位寄存器如bl中,结果为:al存储商,ah存储余数 2. 指令参数是16位寄存器时,被除数则为32位,默认存放于ax和dx中,dx存高16位,ax存低16位,除数存放于指定16位寄存器如bx中,结果:ax存储商,dx存储余数 aaa:目前没有用到
逻辑指令 and:逻辑与 示例:and al,11011111b 解释:示例中结果是将al中第6位置为0,其余位保持不变,经常使用与简化运算如,将小写字母转化为大写字母,只须要将字母与11011111作逻辑与运算便可实现 or:逻辑或 示例:or al,00100000 解释:示例中结果是将al中第6位置为1,其余位保持不变,一样也能实现将大写字母转化为小写字母的简化运算,须要将字母与00100000作逻辑或运算便可实现 not:逻辑非,不经常使用 示例: 解释: xor:逻辑异或,目前不经常使用 示例: 解释: test:不经常使用 shl:逻辑左移 示例:shl al,1或mov cl,3;shl al,cl 解释:逻辑左移的意思就是左移后,移出的数据存放在标志寄存器CF中,而最低位用0补齐,也分为两种状况: 1. 左移1位:直接shl al,1便可 2. 左移超过1位:须要先将欲移动的位数据存入cl中,再经过左移cl个位的数据来实现 shr:逻辑右移 示例:shr al,1或move cl,2;shr al,cl 解释:逻辑右移与逻辑左移相似,这里就很少讲了,一样也是两种状况 sal sar rol ror rcl rcr
转移指令 无条件转移指令 jmp:无条件转移指令 示例:jmp short s;s:inc ax 解释:jmp转移指令能够实现段内短转移、段内近转移和段间转移这三种基本需求 1. 段内短转移:只对IP寄存器修改,修改范围为-128~127,也就是说向前最多转移+127个字节,向后最多转移-128个字节 2. 段内近转移:与短转移基本相同,不过是16位的位移,即修改IP的范围是-32768~32767 3. 远转移(段间转移):能够转移到指定的内存处,上面的两个转移只是在同一个段中的转移,是根据位移定位的转移方式,而远转移能够指定转移的目的地址 条件转移指令 jcxz:若是cx寄存器的值为0,则转移到指定标号 示例:mov cx,0;jcxz s 解释:若是条件知足cx寄存器的值为0,则转移到指定的标号处,经常使用的场景是:遍历一个以'0'字符结尾的字符串,根据这个0判断字符串是否到末尾的简单实现方式 je:若是cmp得差结果等于0,则转移到指定标号 示例:mov bx,3;cmp bx,3;je s 解释:将会转移到s处 jb:若是cmp的差结果小于0,则转移到指定标号 示例:mov bx,3;cmp bx,4;jb s 解释:将会转移到s处 ja:若是cmp的差结果大于0,则转移到指定标号 示例:mov bx,3;cmp bx,2;ja s 解释:将会转移到s处 jnb:若是cmp的差结果不小于0,则转移到指定标号 示例:mov bx,3;cmp bx,3;jnb s 解释:将会转移到s处 jna:若是cmp的差的记过不大于0,则转移到指定标号 示例:mov bx,3;cmp bx,3;jna s 解释:将会转移到s处 循环指令 loop:汇编语言中的循环语句 示例:mov cx,10;loop s 解释:将s程序段循环执行10次(循环次数由cx的值指定) 过程 call:调用子程序,常与ret成对使用 示例:call s;s:ret 解释:转移到子程序,相似于转移指令,但至关于执行了 push IP jmp near s这两条指令,记录了转移的位置,可使用ret返回此IP的位置 ret:在子程序中同于返回call的指令处,常与call成对使用,而且是近转移 示例:call s;s:ret 解释:从子程序跳出,至关于执行了 pop IP,程序执行的下一条语句就是原来call的IP的地址,从而实现了近转移 retf:在子程序中同于返回call的指令处,常与call成对使用,而且是远转移 示例:call s;s:retf 解释:从子程序跳出,至关于执行了 pop IP pop CS程序执行的下一条语句就是原来call的IP的地址,从而实现了远转移 中断 int:系统中断 示例:mov ax,4c00h;int 21h 解释:BIOS和DOS都提供了一些默认的中断进程,用于持续检测中断码,若是接受到中断码,则会在TF=1的状况下在下一条指令去执行可屏蔽中断进程,咱们也能够自定义中断进程去替代系统的中断进程。示例中的中断是去执行21号中断的ah=4c的子程序,子程序为退出当前DOS iret:与int配合使用,在子程序中返回,与ret,retf相似
处理机控制指令 cld:设置DF为0(即正向拷贝) 示例:cld;rep movsb 解释:设置标志寄存器DF为0,即设置拷贝的方向为正向 std:这是DF为1(即反向拷贝) 示例:std;rep movsb 解释:设置标志寄存器DF为1,即设置拷贝的方向为反向 cli:设置TF标志位为1 示例:cli 解释:设置TF为1后,当接受到可屏蔽中断时,会在下一条指令执行中断 sti:设置TF标志位为0 示例:sti 解释:设置TF为0后,当接受到可屏蔽中断时,会忽略中断继续执行当前程序直至结束 nop:添加一个占位的一字节数据 示例:funcend:nop 解释:经常使用来记录子程序的段结束的位置,好比offset funcend就能够获取func结束位置的偏移地址 clc cmc stc hlt wait esc lock
串处理指令 movsb:复制字符串 示例:rep movsb 解释:能够正向或反向复制指定为的字符串到目标地址,参数必须将ds:si源地址、es:di目的地址、cx长度、标志DF指定,而后调用rep movsb movsw 示例: 解释: cmps scas lods stos 配合使用: rep repe repne
mov ax,0 能够用sub ax,ax替代,并且后者2字节,前者3字节 当16进制数,首位数字为英文,则须要在前面加上0,好比:0A432H 在汇编程序中,mov al,[0]指令与debug程序不一样,汇编编译器会将它解释为mov al,0 DOS和合法程序都不会使用0:200~0:2ff这段256字节的空间 直接DEBUG显示的CS就是当前程序段的字节长度 为何mov 4c00h;int 21h长度为5字节 暂存数据的时候,通常用栈 bp寄存器默认使用ss做为段寄存器 没有寄存器名存在的状况下指定内存单元的长度:mov word/byte ptr [bx],1 push/pop只对字操做 在10.1节,ret和retf的示例中,在执行命令以前,为何都要mov bx,0 mul乘法,与div除法原理类似,都分为8位和16位的计算 16位cpu,有符号溢出范围79H(127),-80H(128) DF:方向标志位,与movsb配合使用 adc指令的意义:进行大数的加法或减法 inc和loop不影响cf位 cmp指令只会影响标志位 CF能说明操做符的大小 SF=1并不能说明运算的结果的正负,由于可能发生溢出 但SF和OF同时能够说明正负 SF=1,OF=1:(ah)<(bh) SF=1,OF=0:(ah)>(bh) SF=0,OF=1:(ah)<(bh) SF=0,OF=0:(ah)>=(bh) cld和std分别设置DF为0(正向)和1(反向) Debug中的标志位对应关系 flag:1--0 OF:OV,NV SF:NG,PL ZF:ZR,NZ PF:PE,PO CF:CY,NC DF:DN,UP loop执行分两步 cx-- cx不等于0,转移 中断过程 取得中断类型吗N pushf,将标志寄存器入栈保存 TF=0,IF=0 push cs push ip (IP)=4*N,(CS)=4*N+2 动态获取到一段代码的长度,能够设置一个nop字节,获取长度只须要: mov cx,offset do0end-offset do0 do0: mov xx,xxx mov 4c00h int 21h do0end:nop jmp short s占2字节内存 设置栈顶的ss和sp之间不会响应任何中断,因此在实验二的时候,执行mov ss,0后,mov ax,0执行了,只是debug不能将它中断显示 通常在中断例程中还存在子程序,通常经过ah来指定 若是将字符串后的0写成字符'0',则利用jcxz没法跳转 在进行逻辑移位shl或shr时,移位大于1,必须用cl保存位移数,并将最后一次移出的保存到CF中 在CMOS RAM中,端口为70h(地址端口)和71h(数据端口)存储时间信息的单元分别为:秒:0分:2时:4日:7月:8年:9,都占一个字节 在PC中,外中断可分为可屏蔽中断和不可屏蔽中断 可屏蔽中断在IF=1时,cpu会在执行完当前指令后响应中断,IF=0则不响应此中断 不可屏蔽中断是cpu必须响应的中断,通常不会使用 设置IF:sti,设置IF=1; cli,设置IF=0,IF=0不会执行屏蔽中断 通码:按下键盘的一个键产生的扫描码;断码:松开一个键产生的扫描码, 断码=通码+80h 都被送到60h端口 扫描码一个字节中,通码的第7位为0,断码第7位为1 地址标号和数据标号 地址标号,只能在代码段使用 数据标号,不只表示内存单元的地址,还表示内存单元的长度,与地址标号不一样是标号后无符号“:” 直接定址表:能够经过依据数据,直接计算出所要找的元素的位置的表 键盘缓冲区的字单元中,高位字节存储扫描码,低位字节存储ASCII码。 int 16h用于从键盘缓冲区读取字符,ah存储扫描码(高位),al存储字符(低位)