汇编

来源:互联网 发布:破解路由器密码的软件 编辑:程序博客网 时间:2024/06/07 19:39

通用寄存器:AX、BX、CX、DX
(AX:16位,高8位是ah,低8位是al)
段寄存器:CS、DS、SS、ES


指令地址 = CS(段地址)* 16(即左移一位)+IP(偏移地址)
CPU读指令只认识 CS:IP,能改变CS、IP的内容的指令统称为 转移指令
jmp、jcxz、loop、ret、retf、call等

CPU读数据,自动取DS作为内存的段地址,改变DS的值必须通过寄存器或内存单元,不能直接赋值
mov bx,1000h
mov ds,bx
mov al,ds:[0] 读取1000:0的数据到al中
mov ds:[0],al 读取al中数据到1000:0

只有bx、si、di、bp可以用在[ ]中表示偏移地址,进行内存单元寻址
[bx+si+8]表示偏移地址,段地址默认在ds中 = [bx].8[si] (结构体中bx定位整个结构体,8定位某个数据项,si定位数据项中元素)
[bp+si+8]表示偏移地址,段地址默认在ss中

CPU读栈只认识SS:SP指向栈顶(地址大的一端),以字(16位)为单位
mov bx,1000h
mov ss,bx
mov sp,0010h (10000h~1000Fh为栈,初始化栈为空时,栈顶要指向1000:10h,即1000Fh+2)

push ax 把ax中数据入栈(注意:先sp=sp-2,再入栈到新的栈顶
pop [0] 把数据出栈到ds:0中

一个程序多个段(数据、代码、栈)

assume cs:code,ds:data,ss:stack  (给每个段取名字:code、data、stack)data segment    dw 0123h,0456h,...   (数据段,dw=define word,每个word字类型占两个字节)    //db 1 (每个db字节类型占一个字节)    //db 'ABC'  (字符串,编译时转化为ASCII码,所以每个字母占一个字节)    //dd 1   (每个dd双字类型即两个字,占4个字节)    //db、dw、dd  重复的次数 dup (重复的数据)data endsstack segment         (堆栈段,初始化空间)    dw 0,0,0,0...stack endscode segment          (代码段)start: mov ax,stack    //start,指示程序从这句开始执行,前面不管       mov ss,ax       //将栈顶ss:sp指向stack:1616为数据段的总字节数)       mov sp,16       mov ax,data     //将数据ds:偏移 指向第一个数据       mov ds,ax       ...code endsend start     (注意,要有start的结束)

循环
mov cx,循环次数
s: 循环执行的程序段
loop s (默认先cx-1,不为0再跳回s处)

计算ffff:0~ffff:b内存单元中的数据的和mov ax,0ffffh   //汇编源程序中,数据不能以字母开头,前面必须加0mov ds,as...mov cx,12s: mov al,[bx]  //实现偏移地址从0到b,注意内存单元数据8位,寄存器DX16位,需要用AX(al、ah)作为中介   mov ah,0   add dx,ax   //用dx存放数据和   inc bx         loop smov ax,4c00h   //结束指令int 21h       

二重循环
Inc bx bx中内容加1
[bx+200] = [bx].200 = 200[bx] 可用来表示数组,从200位置开始
[bx+si] = [bx][si] 可用来表示二维数组,bx为行,si为列

//将数据段中的每个单词的前4个字母改成大写字母assume cs:codesg,ss:stacksg,ds:datasgstacksg segment     //设置堆栈,用来暂存数据,这里暂存 外层循环的cx(不用寄存器暂存,因为寄存器数量有限)dw 0,0,0,0,0,0,0,0stacksg endsdatasg segmentdb '1. display      '  //4*16的矩阵,需要改每行的3~6列db '2. brows        'db '3. replacs      'db '4. modify       'datasg endscodesg segmentstart:mov ax,stacksg      mov ss,ax      mov sp,16      mov ax,datasg      mov ds,ax      mov bx,0     //bx寄存器表示行      mov cx,4   s0:push cx      //暂存外层循环的cx,用堆栈      mov si,0     //si寄存器表示列       mov cx,4    s:mov al,[bx+si+3]      and al,11011111B     //小写变成大写,第5位从1变成0即可      mov [bx+3+si],al      inc si      loop s      add bx,16    //外层循环,进入下一行      pop cx      loop s0mov ax,4c00hint 21hcodesg endsend start

出栈/入栈
所有寄存器的值入栈/出栈
pushad也就相当于:PUSH EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI。POPAD相反;
pusha 等价于 :PUSH AX, CX, DX, BX, SP, BP, SI, DI。POPA相反;

加法
add ax,bx(16位数加法)
adc ax,bx = ax+bx+CF(无符号数的进位或借位)
两者结合,进行大数据的加法–>add加低位,adc加高位
xadd(交换并相加)

减法
sub ax,bx = ax - bx,结果存入ax
sbb ax , bx = ax-bx-CF(带借位的减法)
cmp ax,bx 两个相减比大小,影响符号标志位S
(EAX减去ECX的结果是负的,也就是说ECX大于EAX。所以符号标志位S被置为了1。)

乘法
无符号乘法:
mul b1 :用b1的值 * ax的值,结果8位保存在ax中,结果16位则高位在dx低位在ax
有符号乘法:
1.一个操作数 imul b1 :用b1的值 * ax的值,结果8位保存在ax中,结果16位则高位在dx低位在ax
3.三个操作数:IMUL EBP, DWORD PTR [ESI+74],FF800002 相当于[ESI+74] x FF800002 -> EBP

除法
除数8位(bl),被除数16位(小于65535)(AX),商(AL),余数(AH)
除数16位(bx),被除数32位(DX高16位,AX低16位),商(AX),余数(DX)
div bx(除数) 或 div bl
除数16位,被除数32位,商>8位时,不能存入ax中会溢出,这时需要用其他方法(见子程序)
idiv(有符号除法)

获得指令的地址和长度
offset 标号:获得标号处的偏移地址
offset 标号2 - 标号1:获得从标号1到标号2的指令长度
seg:获得标号处的段地址

逻辑指令
shl al,1=左移一位,移出的写入CF(1位)或cl(多位)中
shr al,1=右移一位
test(逻辑比较,与cmp类似):两个数值进行与操作,结果不保存,但是会改变相应标志位(比如说,SF,ZF,PF标志位)–>test eax,eax 确定eax是否等于0(根据0标志位)
sal/sar=算数左移/右移(最高位是符号位,不移)
rol/ror=循环左移/右移
rcl/rcr=带进位循环左移/右移(其实是CF+8位,共9位循环)

读写端口
in al,60h=从60h端口读入一个字节,写入al(只能用al和ax)
out 20h,al=写入20h端口一个字节

转移数据
mov dword prt ds:[400500],EAX 4个字节
mov word ptr ds:[405008],AX 2个字节
mov byte ptr ds:[405008],AL 1个字节

movsx EAX,BX (带符号扩展的传送指令):第一个操作数的位数比第二个操作数多,第二个操作数的符号位填充第一个操作数剩余部分。
movzx (带0扩展的传送指令):剩余的部分总是被填充为0。

lea EAX,DWORD PTR DS:[ECX+38] 计算【】里的值,作为地址,放入EAX

串处理指令:movsb(字节)/movsw(字)
从ds:[si]传到es:[di],与rep配合使用
根据CF的值决定si和di递增还是递减:CF=0则inc遍历串(cld置0),CF=1则sub遍历串(std置1)

给ds、si、es、di赋值mov cx,8cldrep movsb  //将数据复制到后面的空间

其他
lods:从源地址(ESI)拷贝数据到EAX中。
stos:将EAX的值拷贝到EDI指向的内存单元中。
cmps :比较ESI和EDI指向内存单元的内容。
xchg :EAX,ECX 交换
neg :将操作数的符号取反


转移指令

段内转移–>只修改IP的值(IP范围-128~127)
段间转移–>修改CS和IP的值(IP范围-32768~32767)

无条件转移:jmp
根据位移:
段内短转移:jmp short 标号 (8位位移)
汇编指令:EB 偏移值(当前地址 - 跳的新地址,正的表示向前跳,负的表示向后跳)
段内近转移:jmp near 标号 (16位位移)
段间转移:jmp far ptr 标号

根据寄存器(只改IP):
jmp ax

根据内存:
jmp word ptr 内存地址(IP的值,一个字即两个字节)
jmp dword ptr 内存地址(前两个字节为IP,后两个字节为CS)

有条件转移:jcxz 标号
如果(cx) ==0,则 jmp short 标号(两个字节)

与cmp(比较大小)一起使用的转移指令
无符号数:
je 等于则转移(equal)、jne、jb低于则转移(below)、jnb、ja高于则转移(above)、jna
有符号数:
jg 大于则转移 、jng、jge大于等于、jnge小于、jl小于则转移、

循环指令:loop
(cx)–
如果(cx)不为0,则 jmp short 标号(两个字节)

压入栈(保存返回地址)并转移:call
根据位移:
call 标号 = jmp near ptr 标号(16位),并将当前IP,即下一条指令的偏移地址,压入栈
call far ptr 标号,并将下一指令的CS和IP压入栈(入栈:先CS后IP;出栈:先IP,后CS)

根据寄存器:
call 寄存器:跳到寄存器值的偏移地址,压IP值入栈

根据内存:
call word ptr 内存:压IP(两个字节),并跳到内存地址处
call dword ptr 内存:压CS(前两个字节)和IP(后两个字节),并跳到内存地址处

用栈修改:ret/retf(配合call使用,返回到call的下一句,实现子程序)
ret 用栈中数据修改IP、retf用栈中数据修改IP和CS(出栈:先IP,后CS)

子程序(模块化)main:    call sub1    ...    结束sub1:    push cx  保存主程序中用过的寄存器    ...    pop cx等寄存器恢复原值,注意出栈顺序    ret(子程序结束,返回到主程序)

根据标志位跳转的转移指令
jz:当零标志位Z为1时跳转——jnz
JS:当符号标志位S为1时跳转——jns
JP/JPE:当奇偶标志位P置1的时候跳转(比较的结果中1的个数要是偶数)——jnp/jnpe
JO:当溢出标志位O置1时跳转——jno
JL:当符号标志位S为1时跳转
JB:进位/借位标志位置1时跳转(结果为负)——jnb
(JB比较两个数的时候,认为它们是无符号数;JL指令要考虑符号)
JBE:小于或者等于的时候跳转,两个标志位的,进位/借位标志位置1或者零标志位Z置1的时候跳转——JNBE当进位/借位标志位C与零标志位Z都为0时跳转。


标志寄存器flag

这里写图片描述
11 OF:溢出
10 DF:串处理指令中,控制si、di的增减
7 SF:负数1,非负数0
6 ZF:零标志位
2 PF:偶数个1为1,奇数个1为0
0 CF:进位和借位

pushf将标志寄存器的值(16位)压栈,popf出栈放入标志寄存器


编译和执行

(Win7 64位系统需要安装DOSBOX,和debug.exe、edit.com、masm.exe等,才能进入DOS的C盘)
(mount设置c盘;debug模式中输入q退出,到C盘)
DOS的C盘–>debug
r 查看各个寄存器内容
r cs:修改CS寄存器中内容–>r ip–>r ax都可以

d 段地址 : 偏移地址–>查看内存的内容,从该地址开始的128个内存单元–>d 查看后续内容
d 段地址 : 偏移地址 结尾偏移地址–>查看该范围的内存块

e 段地址 : 偏移地址–>修改该地址内存的内容–>空格,继续修改下一个地址–>Enter 修改命令结束
e 段地址 : 偏移地址 1 2 ‘a’“a+b”“asd”–>从该地址开始,以此修改为这些值

a 段地址 : 偏移地址–>修改该地址内存的内容为汇编指令–>不输入按Enter修改命令结束

u 段地址 : 偏移地址–>从该地址开始的内容翻译为汇编指令

t 执行当前CS:IP所指的指令(记得之前把CS和IP的值修改)–>t 继续单步执行

g 汇编指令偏移地址 –>直接运行到指定地址处

p 执行int 21、循环自动重复执行到结束

单步执行看结果:
a输入汇编指令,r修改CS和IP到指令开始地方,t单步执行并显示寄存器的值

中断机制:
t执行 修改ss 的指令时,下一条指令也紧接着执行

编译和执行
DOS的C盘–>edit(编辑源代码)–>1.asm–>masm(编译)–>1.obj–>link(连接)–>1.exe–>debug 1.exe–>-g 4c(执行)

1.exe执行过程:
命令解释器command.com将1.exe加载入内存–>command设置CPU的CS:IP指向程序入口,CPU运行程序–>运行完后,CPU继续运行command,等待用户输入
跟踪.exe执行过程:
DOS的C盘–>debug 1.exe–>.r查看寄存器–>t单步执行–>p执行int 21(注意)
这里写图片描述
分析:
CX:程序的长度
DS:程序所在内存的段地址
CS:IP :程序所在地址(DS+0010h = CS 因为该内存段的前256个字节存放PSP段用来通信,后面接程序)

0 0
原创粉丝点击