win32汇编入门教程

信息来源:红狼安全小组(www.wolfexp.net)  
文章作者:Asm


注:择写过程参考和借鉴一些书籍资料.....在此感谢各大牛淫 :)

汇编指令-------------(推荐程度:必须)
  计算机能直接识别的只有机器语言,就是只有0和1组成的二进制的指令,而汇编语言,其实就是利用字符来表示的一种机器语言,本质上,汇编也算是一种机器语言。机器语言和汇编语言统属“低级语言”,相反的,还有一些高级语言,例如 C/C++,VB,VC++,Perl等等,这些语言和我们的自然语法都类型,但是不能被计算机直接识别,只有通过编译,才能够转换成0和1。
  在DOS时代,积存器是16位的,那个时候的汇编,是DOS16位,积存器是16位的,即:ax,bx,cx,dx。现在我们所使用的windows,是32位的处理器,所以,在windows下用汇编语言编程,也叫win32位汇编,积存器分别是eax,ebx,ecx,edx.当然还有LINUX/UNIX等汇编.
  现在我们所学的,就是win32位汇编,首先我们要知道汇编基础的指令。例如
mov,它的用法是:mov eax,ebx,执行了这条指令,就是把ebx的值传送到eax里边,如果eax=0001H,ebx=0002H,指令执行后,它们的值分别是eax=0002H,
ebx=0002H。下面我把常用的指令列举出来:
   
1)MOV AX,0001H  ;把0001H送到寄存器AX,执行后(AX)=0001H
2)PUSH AX ;压栈指令 其中对SP的影响是:由低向高,SP-2
3)POP AX ;出栈指令 其中对SP的影响是:由高向低,SP+2
4)XCHG AX,BX;交换指令,当(AX)=1234H,(BX)=5678H,执行的结果是

(AX)=5678H,(BX)=1234H
5)IN ;输入指令,一般对于CPU与I/O设备之间的联系
6)OUT ;输出指令,一般对于CPU与I/O设备之间的联系
7)XLAT ;换码指令,
8)LEA SPO SPO1 ;执行的结果是将SPO1送SPO,即SPO1=SPO 有效地址送寄存器
9)LDS ;指针送寄存器DS
10)LES ;指针送寄存器ES

=======================================================================

标志寄存器传送指令

11)LAHF ;标志送AH
12)SAHF ;AH送标志寄存器
13)PUSHF ;标准出栈
14)POPF ;标志压栈

=====================================================================

算术指令

15)ADD ;加法指令 
16)ADC ;带进位加法指令
17)INC ;加1

======================================================================

减法指令

18)SUB ;减法指令
19)SBB ;带借位减法指令
20)DEC ;减1
21)NEG ;求补
22)CMP ;比较

=======================================================================

乘法指令

23)MUL ;无符号数乘法
24)IMUL ;带符号数乘法

=======================================================================

除法指令

25)DIV ;无符号数除法
26)IDIV ;带符号数除法
由于使用除法指令,务必有如下两个
27)CBW ;字节转换为字
28)CWD ;字转换为双字

=======================================================================

十进制调整指令(压缩BCD码调整指令)

29)DAA ;加法的十进制调整指令
30)DAS ;减法的十进制调整指令

非压缩BCD码调整指令

31)AAA ;加法的ASCII调整指令
32)AAS ;减法的ASCII调整指令
33)AAM ;乘法的ASCII调整指令
34)AAD ;出发的ASCII调整指令

=======================================================================

逻辑运算指令

35)AND ;逻辑与
36)OR ;逻辑或
37)NOT ;逻辑非
38)XOR ;异或
39)TEST ;测试

DOS汇编寻址方式-------------(推荐程度:一般了解)

计算机指令是由操作码和操作数组成,操作码表明操作性质的代码,操作数则说明操作的数或数的地址.一般计算机指令是由二进制0或1组成,也就是可以直接被计算机识别的二进制代码.
  操作数直接存放在指令中,紧跟操作码之后,它作为指令的一部分存放在代码段里,这种操作数称为立即数.立即数可以是8位或者16位,如果是16位,则高字节存放在高地址中,低字节存放在低地址中.
   (1)立即寻址方式用来表示常数,它经常用于给寄存器赋初值,并且只能用于源操作数字段,不能用于目的操作数字段..例如:       
MOV AL,5 
指令执行后结果为(AL)=05H 
MOV AX,3064H
指令执行后结果为(AX)=3064H

  (2)寄存器寻址方式:操作数在寄存器中,指令指定寄存器号,对于16位操作数,寄存器可以是AX,BX,CX,DX,SI,DI,SP,BP等;对于8位数的操作数,寄存器可以是AL,AH,BL,BH,CL,CH,DL,DH.这种寻址方式由于操作数就在寄存器中,不需要访问存储器来取得操作数,因而可以取得较高的运算速度.
MOV AX BX
指令执行前,(AX)=3064H,(BX)=1234H,指令执行后,(AX)=1234H,(BX)保持不变.

  (3)直接寻址方式:在IBM PC中把操作数的偏移地址称为有效地址EA.在直接寻址方式中,有效地址EA就在指令中,它存放在代码段中指令操作码之后,但操作数一般存放在数据段中,所以必须先求出操作数的物理地址,然后再访问存储器才能取得操作数.操作数在数据段中,那么 物理地址=(DS)*16D+有效地址EA  
MOV AX,[2000H]
如(DS)=3000H,执行后,(AX)=16D*3000H+2000H=3050H
在汇编语言指令中,可以用符号地址代替数值地址,如:
MOV AX,VALUE
此时VALUE为存档操作数单元的符号地址,也可以写成:
MOV AX,[VALUE]
两者是等效的.在VALUE附加段中,则应指定段跨越前缀如下:
MOV AX,ES:VALUE
MOV AX,ES:[VALUE]  
   (4)寄存器间接寻址方式:操作书的有效地址在基址寄存起BX,SI,DI,则操作数据段中,所以用DS段寄存器的内容作为段地址,即操作数的物理地址为:
物理地址=16D*(DS)+(BX)
物理地址=16D*(DS)+(SI)
物理地址=16D*(DS)+(DI)
如指令中指定BP寄存器,则操作数在堆栈中,段地址在SS中,所以操作数的物理地址为物理地址=16D*(SS)+(BP)
   例: MOV AX,[BX]
        如果段寄存器(DS)=2000H,(BX)=1000H,
        则 物理地址=20000H+1000H=21000H
       然后送AX,(AX)=50A0H
指令中也可以指定段跨越来取得其他段中的数据.如 MOV AX,ES:[BX]  这种寻址方式可以用于表格处理,执行完一条指令后,只需要修改寄存器内容就可以取出表格中的下一项.
EAX,AX,AL和AH的关系:
AX,AH,AL是EAX的一部分,EAX是一个32位的寄存器(仅在386以上存在),AX包含了EAX的低16位(2字节),AH包含了AX的高字节,而AL包含了AX的低字节。因而AX是16位的,AL和AX是8位的。
  (5)段内直接寻址转移指令的汇编格式表示:
JMP NEAR PTR PROGIA
JMP SHORT QUEST
其中,PROGIA和QUEST均为转向的符号地址,在机器指令中,用位移来表示。在汇编指令中,如果位移量为16位,则在符号地址前加操作符NEAR PTR,如果位移量为8位,则在符号地址前加操作符SHORT
  (6)段内间接寻址转移指令的汇编格式表示:
JMP BX
JMP WORD RTP[BP+TABLE]等,其中WORD PTR为操作符,用以指出其后的寻址方式所取得的转向地址是一个字的有效地址,也就是说它是一种段内转移!
以上的两种寻址方式都为短内转移,所以直接把求得的转移的有效地址送到IP寄存器就可以了。如果需要计算转移的物理地址,则计算公式应该是:
   物理地址=16D*(CS)+EA


win32汇编开始-------------(推荐程度:必须)

一般常用的指令有:mov,add,inc,jmp,push,pop,cmp等等

在win32位汇编中,已经没有了dos汇编的中断int,编写一些程序,还要熟悉API函数。例如一个简单的win32汇编的例子:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  .386
.model flat,stdcall
option casemap:none

include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib

.data
szTitle db '简单的例子',0  
szCaption db '恭喜,你看到了一个win32汇编程序,0

.code
start:
     invoke MessageBox,NULL,addr szCaption,addr szTitle,MB_OK
     invoke ExitPorcess,NULL
end start 
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

利用IDC集成环境,推荐编译工具是 MASMPlus,下载地址:http://www.aogosoft.com/masmplus/官方站已经对它的编译方法详细说明
   我们注意分析这个例子

  .386
.model flat,stdcall
option casemap:none

386,就是采用386指令集,另外的还有486,586,686等指令集,特权指令486P,586P。如果要编写驱动程序,防火墙,就要用到特权指令。我们编写一般的win32程序,只要386就行了。
.model flat,stdcall,这个表示内存平坦模式编程,option casemap:none要求程序区分大小写。接着用include包含调用函数用到的库,例如MessageBox是user32.dll里面,所以要include user32.inc,includelib user32.lib
.data,下面定义了一些数据,例如我定义的是szTitle和szCaption,等到下面要调用MessageBox函数的时候需要用到的参数。
start 这里是程序开始的标号,也可以是Mian。接着利用伪指令invoke调用MessageBox,将定义的szTitle和szCaption的数值显示出来,也就是弹出来.ExitPorcess用来结束进程退出。如果没有ExitPorcess,程序在运行完毕后会提示说:“程序遇到麻烦需要结束..........”


一般的win32汇编的结构如下

  .386
.model flat,stdcall
option casemap:none

include .....

.data


.data?


.code
start:    ;开始标号
....................;这里程序开始
end start ;结束标号


注:以上代码用MASM格式编写


上面的例子使用了伪指令invoke,为什么要使用这个?原因就是使用伪执行,windows可以帮我们自动对齐堆栈.
还可以写成如下:




.386
.model flat,stdcall
option casemap:none

include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib

.data
szTitle db '简单的例子',0  
szCaption db '恭喜,你看到了一个win32汇编程序,0

.code
start:
     push MB_OK
     push szTitle
     push szCaption
     push  NULL
     call MessageBox
     push NULL
     call ExitPorcess
end start 
有堆栈先进后出的原则,将MessageBox的参数逐步压栈,然后MessageBox
换成一个执行地址指向导入表,导入表指向MessageBox函数的实际地址,接着windows会根据User32.dll的内存地址动态填入.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值