-
-
[分享]汇编语言(王爽)回顾
-
发表于: 2021-6-7 09:44 3718
-
一.汇编语言的组成
汇编语言发展至今,有以下3类指令组成。
1.汇编指令:机器码的助记符,有对应的机器码。
2.伪指令:没有对应的机器码,由编译器执行,计算机并不执行。
3.其他符号:如+、-、*、/等,由编译器识别,没有对应的机器码。
汇编语言的核心是汇编指令,它决定了汇编语言的特性。
可见,CPU要想进行数据的读写,必须和外部器件(标准的说法是芯片)进行下面3类信息的交互:
1 2 3 4 5 | ( 1 )存储单元的地址(地址信息); ( 2 )器件的选择,读或写的命令(控制信息); ( 3 )读或写的数据(数据信息)。 |
对CPU来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受CPU寻址能力的限制,这个逻辑存储器既是我们所说的内存地址空间
8086处理器在启动或者重启的时候,会对寄存器执行一个初始化的操作。初始化后的寄存器信息如下:
CS:FF FF,其它的寄存器:00 00。
jmp 某一合法寄存器”指令的功能为:用寄存器中的值修改IP。
jmp ax,在含义上好似:mov IP,ax。 (但是注意并不存在这样的语法)
汇编伪指令db,dw,dd
db
db定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1
dw ‘define word’
dw定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2
dd
dd定义双字类型变量,一个双字数据占4个字节单元,读完一个,偏移量加4
END [label]
其中标号指示程序开始执行的起始地址。如果多个程序模块相连接,则只有主程序要使用标号,其他子程序模块则只使用END 而不必使用标号。
用END START表示程序结束。end叫做结束语句,它的格式为:
END 表达式
也就是说,end start是一条语句,不是两条,它是一个完整的表达式!
你要知道的是“汇编程序并非将在遇END时结束汇编”,而是在“遇END语句时结束汇编”
整个程序会不会出现2个end?
不会出现两个 end 的,至少只有第一个 end 是有效的;即便有第二个 end 也由于是在第一个的 end 之后而根本不会被汇编程序处理,所以等于是没有。一个程序可以由多个源程序组成,由于程序入口只可以有一个,所以其它的源程序就在 end 后不应该有标号,否则多个程序入口指定会让连接程序无所适从而拒绝后续操作。如果单一源程序的 end 后面没有标号(或所有源程序的 end 后都没有标号),那就会是把程序最开始处作为入口,如果那里是数据段或不是需要的程序入口,程序执行的结果就难料了。
将我们要转换大小写的字母与空格进行异或(xor)运算
“jmp short 标号”指令所对应的机器码中,并不包含转移的目的地址,而是包含转移的移位。这移位是编译器根据汇编指令中的标号计算出来的
jmp short 标号 的功能为:(IP)=(IP)+8位位移
8位位移=标号处的地址-jmp指令后的第一个字节的地址(为什么是指令后第一个字节的地址,是因为和cpu执行指令的方式有关)
short指明此处的位移为8位位移
8位位移的范围为-128~127,用补码表示
8位位移由编译程序在编译时算出
cpu执行ret指令时,相当于进行
pop IP
cpu执行retf指令时,相当于进行
pop IP
pop CS
call 标号相当于
push IP
jmp near ptr 标号
call far ptr 标号相当于
push cs
push ip
jmp far ptr 标号简洁的描述中断过程int N,如下:
- 取得中断类型码N;
- pushf
- TF = 0,IF = 0
- push CS
- push IP
- (IP) = (N*4),(CS) = (N*4+2)
中断处理程序的iret指令相当于- pop IP
- pop CS
- popf
PF:(ParityFlag)
奇偶标志位,所有bit位中1的个数为偶数时PF=1
CF:(carryFlag)
OF:(overflowFlag)
CF是无符号数溢出标志,OF是有符号数溢出标志
CPU进行运算时并不关心操作数有没有符号,而是我们把操作数当做有符号数时就用OF参与运算,把操作数当做无符号数时就用CF参与运算
1、CF的判断:
①加法
二进制角度,如果两无符号数相加,最高位向前有进位,则CF=1,否则CF=0。
②减法
二进制角度,如果两无符号数相减,最高位向前游借位,则CF=1,否则CF=0。
2、OF的判断
①加法
二进制角度,如果两有符号数同号,而相加结果与之异号,则OF=1,否则OF=0。
②减法
二进制角度,如果两个数异号,而相减结果与被减数符号相反,则OF=1,否则OF=0。
CPU可以直接读写的三个地方的数据:
- cpu内部的寄存器
- 内存单元
- 端口
在访问端口的时候,CPU通过端口地址来定位端口,因为端口所在的芯片和CPU通过总线相连。所以端口地址和内存地址一样,通过地址总线传送。
在PC中CPU最多可以定位64KB个不同端口,0~65535
对于端口的读写不能用mov、push、pop等内存读写指令,端口指令只有in和out,分别是用来读数据和写数据
访问内存
mov ax,ds:[8]
- CPU通过地址线将地址信息8发出
- CPU通过控制线发出内存读命令
- 存储器将8号单元中的数据通过数据线送入CPU
访问端口
in al,60h
从60号端口读入一个字节给al
操作流程:
- CPU通过地址线将地址信息60h发出
- CPU通过控制线发出端口命令,选择端口所在芯片,通知它要读数据
- 端口所在芯片将60h端口中的数据通过数据线送入CPU
在in和out指令中只能用al或ax这样的8位16位寄存器
SHL是Shift Logical Left的缩写,是逻辑左移指令,将目的操作数顺序左移1位或CL寄存器中指定的位数。 左移一位时,操作数的最高位移入进位标志位CF,最低位补零。
自己调试程序时遇到过
shl eax,20h
按字面理解是左移32位,运行结果eax应该是0,但是奇怪的是实际结果eax的值并没有变化。
老师给的解释是位移指令只识别移动位数的低5bit位,即20h实际有效的是低5位,全为0,所以没有进行位移操作
x86指令体系
1.寄存器组
x86指令体系中的寄存器组具体如下。
- 通用寄存器:包括EAX、EBX、ECX、EDX、ESI、 EBP、ESP。
- 指令指针寄存器(EIP):指向当前要执行的指令。
- 状态标识寄存器(EFLAGS):根据状态标识寄存器中状态的值控制程序的分支跳转。
- 段寄存器:CS、DS、SS、ES、FS、GS。在当前的操作系统中,CS、DS、SS和ES的段寄存器的基地址通常为0。
- 特殊寄存器:包括DRO-DR7,用于设置硬件断点。
32位寄存器的名称就像16位寄存器一样,带有“ E”前缀以表示扩展
2.汇编指令集
x86汇编代码有两种语法记法:Intel和AT&T。
常用的逆向分析工具IDA Pro、Ollydbg和MASM通常使用Intel记法,
而UNIX系统上的工具gcc通常遵从AT&T记法。
Intel记法在实践中占据统治地位。
3.控制转移指令
·cmp:对两个操作数执行减法操作,修改状态标识寄存器。
.test:对两个操作数执行与操作,修改状态标识寄存器。
·jmp:强制跳转指令。
·jcc:条件跳转指令,包括jz、jnz等。
x64指令体系
x64指令体系与x86指令体系大致相同,这里主要针对不同点进行说明。
1.寄存器组
通用寄存器增加到16个,分别为RAX、RBX、RDX、RCX、RBP、RDI、RSI、RSP,R8~R15。
前面的“R”它只是意味着“注册”。由于历史原因。
2.系统调用指令
syscall/sysret是Linux 64位操作系统的系统调用方式。
3.x64应用程序二进制接口
有两种广泛使用的x64 ABI,列举如下。
- Microsoft's x64 ABI:主要用于Windows操作系统中的64位程序。
- SysV x64 ABI:主要用于Linux、BSD、MAC等操作系统中的64位程序。
Microsoft's x64 ABI的前4个参数通过寄存器RCX、RDX、R8、R9传递,其余则是通过栈传递,但在栈上会预留下Ox20字节的空间用于临时保存前4个参数,返回值为RAX。对应的函数调用形式如下:
1RAX func(RCX, RDX, R8, R9,[rsp
+
0x20
], [rsp
+
0x28
],...)
SysV x64 ABI的前6个参数(RDI、RSI、RDX、RCX、R8、R9)通过寄存器传递,其余则是通过栈传递,在栈上没有为前6个参数预留空间,返回值为RAX寄存器。对应的函数调用形式如下:
1RAX func(RDI, RSI, RDX,RCX, R8, R9, [RSP
+
8
], [RSP
+
0x10
],..)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [求助]Android auto 7450
- web渗透-清理痕迹 3822
- [求助]web渗透是找个师傅好还是自学好? 4945
- linux系统/etc/shadow文件密码项 14561
- 小端存储 3649