关于汇编的一些基础笔记
因为之前刷PWN类型的题目,发现基础不牢,强行做题还是太难搞了,所以开了二倍速快速学了点基础知识。下面是这两天的笔记。
#二进制
#字节 => 8Bit
1.原码\反码\补码
-1
10000001 原码
11111110 反码
11111111 补码
-7
10000111 原码
11111000 反码
11111001 补码
2.正负数
无符号数:0 1 2 3 4 ... FF
有符号数:
正数: 0 ... 7F
负数:FF ... 80
#计算机只会位运算
#与运算
两个位都为1时,结果才为1
10110001
and(&) 11011000
---------------------
10010000
#或运算
两个位都为1时,结果才为1
10110001
or(|) 11011000
---------------------
11111001
#异或运算
不一样的时候结果才为1
10110001
xor(^) 11011000
---------------------
01101001
#非运算 => 单目运算
0就是1,1就是0
not(~) 11011000
---------------------
00100111
#位移运算 -》 左移
分别二进位全部左移若干位,高位丢弃,低位补0
shl(<<) 11011000 左移2位为:0110000
#右移
各二进位全部右移若干位,低位丢弃,高位补0或者补符号位
shr(>>) 11010101 00110101
unsigned int a=10;
print("%d\n",a>>2);
sar(>>) 11010101 11110101
int a=10;
printf("%d\n",a>>2);
#通用寄存器
EAX ESP
ECX EBP
EDX ESI
EBX EDI
#MOV指令
<1>立即数到寄存器 向EAX寄存器中存 1
MOV EAX,1 MOV EDX,EAX
<2>寄存器到寄存器
<3>内存到寄存器
32位 16位 8位
EAX AX AL L低八位 H高八位
ECX CX CL
EDX DX DL
EBX BX BL
ESP SP AH
EBP BP CH
ESI SI DH
EDI DI BH
#内存地址(32位,前面的0可省略)
0x00000000 0x00
#写入时保证宽度一样
MOV BYTE PTR DS:[18FFF0],1
MOV DWORD PTR DS:[18FFF8],12345678
MOV DWORD PTR DS:[18FFFC],EAX
BYTE 1 WORD 2 DWORD 4 (字节)
#内存读取的五种形式
1.【立即数】
读取内存的值
MOV EAX,DWORD PTR DS:[0x12FFC3]
内存地址
向内存中写入数据
MOV DWORD PTR DS:[0X12FFC4],EAX
2.【reg】reg代表寄存器可以是8个通用寄存器中的任意一个
读取内存的值
MOV ECX,0X12FFD0
MOV EAX,DWORD PTR DS:[ECX]
向内存中写入数据
MOV EDX,0X13FFD8
MOV DWORD PTR DS:[EDX],0x87654321
3.【reg+立即数】
读取内存的值
MOV ECX,0X12FFD0
MOV EAX,DWORD PTR DS:[ECX+4]
向内存中写入数据
MOV EDX,0X13FFD8
MOV DWORD PTR DS:[EDX+0xC],0x87654321
4.【reg+reg*{1,2,4,8}】
读取内存的值
MOV EAX,13FF4C4
MOV ECX,2
MOV EDX,DWORD PTR DS:[EAX+ECX*4]
向内存中写入数据
MOV EAX,13FFC4
MOV ECX,2
MOV DWORD PTR DS:[EAX+ECX*4],87654321
5.【reg+reg*{1,2,4,8}+立即数】
读取内存的值
MOV EAX,13FF4C4
MOV ECX,2
MOV EDX,DWORD DS:[EAX+ECX*4+4]
向内存中写入数据
MOV EAX,13FF4C4
MOV ECX,2
MOV EDX DWORD DS:[EAX+ECX*4+4],87654321
#DTDEBUG内存
<1>分别以字节、字、双字形式来查看内存(db dw dd)
<2>向内存中写入四个字节的数据,并观察存储形式(大端存储、小段存储)
#MOV指令
指令格式:
1、MOV r/m8,r8 r通用寄存器
2、MOV r/m16,r16 m代表内存
3、MOV r/32.r32 imm代表立即数
4、MOV r8,r/m8 r8代表8位通用寄存器
5、MOV r16,r/m16 m8代表8位内存
6、MOV r32,r/m32 imm8代表8位立即数
7、MOV r8,imm8
8、MOV r16,imm16
9、MOV r32,imm32
#ADD指令 加
#SUB指令 减
#AND指令 与
#OR指令 或
#XOR指令 异或
#NOT指令 非
#内存复制
1.MOVS指令:移动数据 内存-内存
BYTE/WORD/DWORD
MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 简写为:MOVSB
MOVS WORD PTR ES:[EDI],BYTE PTR DS:[ESI] 简写为:MOVSW
MOVS DWORD PTR ES:[EDI],BYTE PTR DS:[ESI] 简写为:MOVSD
例子:
MOV EDI,12ffd8
MOV ESI,12ffd0
MOVS DWORD PTR ES:[EDI] DWORD PTR DS:[ESI] 观察EDI的值
2.STOS指令:讲AI/AX/EAX的值存储到【EDI】指定的内存单元
STOS BYTE PTR ES:[EDI] 简写为:STOSB
STOS WORD PTR ES:[EDI] 简写为:STOSW
STOS DWORD PTR ES:[EDI] 简写为:STOSD
MOV EAX,12345678 观察EDI的值
MOV EDI,12FFC4
STOS BYTE PTR ES:[EDI]
STOS WORD PTR ES:[EDI]
STOS DWORD PTR ES:[EDI]
MOV EAX,12345678
MOV EDI
3.REP指令:按计数寄存器(ECX)中指定的次数重复执行字符串指令
MOV ECX,10 ECX计数器
REP MOVSD
REP STOSD
堆栈操作 ESP栈顶指针
MOV DWORD PTR DS:[18FF88],1 堆栈地址由大到小
MOV DWORD PTR DS:[18FF84],2
SUB ESP,8 指定新栈顶
ADD ESP,8 恢复原栈顶
4.PUSH指令:
<1>向堆栈中压入数据
<2>修改栈顶指针ESP寄存器
指令格式:
1.PUSH r32
2.PUSH r16
3.PUSH m16
4.PUSH m32
5.PUSH imm8/imm16/imm32
MOV DWORD PTR DS:[18FF84],3 => PUSH 3
SUB ESP,8
PUSH 1
PUSH 2
PUSH 3 向栈里压入3个数,然后恢复栈顶
ADD ESP,OC
PUSH ECX
MOV ECX,10 将原ecx中的内容放置栈顶,而后将10放进ecx中
MOV ECX PTR DS:[ESP] 取栈顶地址给ecx,将栈顶恢复4个字节空间
ADD ESP,4
5.POP指令:
<1>将栈顶数据存储到寄存器/内存
<2>修改栈顶指针ESP寄存器
指令格式:
1.POP r32
2.POP r16
3.POP m16
4.POP m32
MOV ECX PTR DS:[ESP] => POP ECX
ADD ESP,4
POP EAX 栈顶加4
#修改EIP的指令
JMP 的作用就是修改 EIP的值
1.JMP指令:
MOV EIP,寄存器/立即数/内存 简写为 JMP寄存器/立即数/内存
2.CALL指令:F7进入
PUSH 下一行地址
MOV EIP,寄存器/立即数/内存 简写为 CALL立即数/寄存器/内存
与JMP唯一的区别:
在堆栈中存储CALL指令下一行的指定
3.RET指令:
ADD ESP,4
MOV EIP,[ESP-4] 简写为:RET 栈顶指针加4,再把原来栈顶指向的东西放到EIP中
#反调试
1.单步步入(F7) 单步步过(F8)
<1>单步步入与单步步过的区别
<2>调试器实现原理:
断点:0xCC =》 ini 3
单步步入:设置EFLAGS的TF位
#什么是函数
函数就是一系列指令的集合为了完成某个会重复使用的特定功能。
#如何执行一个函数?即函数调用
<1>用JMP来执行函数
<2>用CALL来执行函数 在函数的最后会有一个return,返回到CALL指令的下一行,如果没有,那就是反调试
#什么是参数?什么是返回值
ADD ECX,EDX 实现两个数相加
MOV EAX,ECX
RETN
函数调用
MOV ECX,1
MOV EDX,2
CALL 0D221FC [函数的地址]
通过堆栈的型式传递参数
PUSH 1
PUSH 2
CALl 【函数地址】
ADD ESP+4
ADD ESP+8
RETN
#什么是堆栈平衡?
<1>如果要返回父程序,则当我们在堆栈中进行堆栈的操作的时候,一定要保证在RET这条指令之前,EPS指向的是我们压入栈中的地址
<2>如果通过堆栈传参了,那么在函数执行完毕后,要平衡参数导致的堆栈变化。
ADD ESP+8 CALL下面执行,称为外平衡,在函数最后RETN 8执行称为内平衡。
push 1
push 2
call [函数地址]
add esp,8 外平衡
mov eax,dword ptr ss:[esp+4] 通过堆栈的型式传递参数
mov eax,dword ptr ss:[esp+8]
retn
#ESP寻址的弊端:
ESP存储的是当前栈顶的地址,如果临时存储数据的话,栈顶地址必然会发生变化。所以需要修正这个值
#EBP寻址
push 1
push 2
call 4183EE
push EBP 新建栈底
mov ebp,esp 将原栈顶的地址交给新建的栈底
sub esp,10 分配空间
mov eax,dword ptr ss:[ebp+8]
add eax,dword ptr ss:[esp+C]
mov esp,ebp 恢复原栈顶
pop ebp 恢复原栈底
retn
#JCC指令
1.JE,JZ 结果为零则跳转(相等时跳转) ZF=1
2.JNE,JNZ 结果不为零则跳转(不相等时跳转) ZF=0
3.JS 结果为负则跳转 SF=1
4.JNS 结果为非负则跳转 SF=0
5.JP,JPE 结果中1的个数为偶数则跳转 PF=1
6.JNP,JPO 结果中1的个数为偶数则跳转 PF=0
7.JO 结果溢出了则跳转 OF=1
8.JNO 结果没有溢出则跳转 OF=0
9.JB,JNAE 小于则跳转(无符号数) CF=1
10.JNB,JAE 大于等于则跳转(无符号数) CF=0
11.JBE,JNA 小于等于则跳转(无符号数) CF=1 or ZF=1
12.JNBE,JA 大于则跳转(无符号数) CF=0 and ZF=0
13.JL,JNGE 小于则跳转(有符号数) SF≠0F
14.JLN,JGE 大于等于则跳转(有符号数) SF=0F
15.JLE,JNG 大于则跳转(有符号数) ZF=1 or SF≠0F
16.JNLE,JG 大于则跳转(有符号数) ZF=0 and SF=0F
1.标志寄存器:EFLAGS
溢出标志 OF
方向标志 DF
中断使能标志 IF
单步标志 TF
符号标志 SF
零标志 ZF 0
辅助进位标志 AF 0
奇偶标志 PF 1
进位标志 CF
2.CF(bit 0)[Carry flag]
若算术操作产生的结果在最高有效位(most-significant bit)发生进位或借位则将其置1,反之清零。
这个标志通常用来指示无符号整型运算的溢出状态。
MOV AL,0xFE MOV AL,0x7F
ADD AL,2 或者 SUB AL,0xFF
3.PF(bit 2)[Parity flag]
如果结果的最低位有效字节(least-significant byte)包含偶数个1位则该位置1,否则清零。
利用PF可进行奇偶校验检查:
需要传输“11001110”,数据中包含5个“1”,所以其奇校验位为“0”,同时把“1100111100”传输给接收方,接收方收到数据后再一次计算奇偶性,“1100111000”中仍然含有5个“1”,所以接收方计算出的奇校验位还是“0”,发送方一致,表示在此次传输过程中未发生错误。
MOV AL,0CE
ADD AL,0
4.AF(bit 4)[Adjust Carry flag]
如果算术操作在结果的第3位发生进位或借位则将该标志置1,否则清零。
这个标志在BCD(binary-code decimal)算术运算中被使用。
5.零标志ZF(Zero flag)
零标志ZF用来反映运算结果是否为0
如果运算结果为0,则其值为1,否则为0.在判断运算结果是否为0时,可使用此标志位。
XOR EAX,EAX MOV EAX,100 AND EAX,EAX 0 ZF=1
MOV ECX,100 TEST EAX,EAX
MOV EAX,2 CMP EAX,ECX TEST => AND
SUB EAX,2 判断2个值是否相等 CMP => SUB
6.符号标志SF(Sign Flag)
符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。
MOV AL,7F
ADD AL,2
7.DF(bit 10)[Direction Flag]
这个方向标志位控制串指令(MOVS,CMPS,SCAS,LODS以及STOS)。设置DF标志使得指令自动递减(从高地址向低地址方向处理字符串),清除该标志则使得串指令自动递增。
STD以及CLD指令分别用于设置以及清除DF标志。
发表评论
木有头像就木JJ啦!还木有头像吗?点这里申请属于你的个性Gravatar头像吧!