位运算
与运算

或运算

异或

非运算

左移

右移
各二进位全部右移若干位,低位丢弃,高位补0或者补符号位
shr是无符号的,高位用0补
sar是有符号的,高位用符号位补
在c语言中>>是包含了shr和sar的,怎么区分有符号和无符号要看类型,比如 unsigned int就是无符号的,右移会使用shr

计算机做加法的过程
4 + 5 = ?
1、4和5,先异或 4xor5
2、4和5进行与运算,得出来的结果判断是否有进位,如果是0就是没有进位,如果是非0就是有进位。最后左移1位
(4 and 5 )<< 1
3、将步骤1和步骤2的结果异或
4、将步骤1和步骤2的结果相与,判断还有没有进位,如果有则继续重复上述步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| 4------ 0000 0100 5------ 0000 0101 加--------------------------- 0000 1001 第一步 异或 0000 0100
0000 0101 异或--------------------------- 0000 0001 第二步 与,判断是否有进位
0000 0100
0000 0101 与--------------------------- 0000 0100
第三步,如果第二步与的结果非0表示有进位,需要左移1位
0000 0100 << 1 = 0000 1000
第四步 继续异或
0000 0001
0000 1000 异或--------------------------- 0000 1001
第五步 将第一步和第三步的结果进行与运算判断是否还有进位
0000 0001
0000 1000 与--------------------------- 0000 0000
发现是0 表示没有进位,运算结束
|
4-5=?
4-5 = 4 + (-5)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 4 + (-5)
4 0000 0100
-5 1111 1011
1) 异或
0000 0100 1111 1011 异或--------------------------- 1111 1111
2) 判断是否有进位
0000 0100 1111 1011 与--------------------------- 0000 0000 结果是0,没有进位。1111 1111 就是最终结果
|
X / Y 表示 X 可以减去多少次Y
DTDebug
配置DTDebug


UDD path和Plugin path 写自己安装目录下的
通用寄存器

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| MOV 目标操作数,源操作数
mov eax,12 mov eax,ecx
mov ax,12 mov ax,cx
mov ah,ch mov ah,12
mov al,cl mov al,2
mov指令 左右两边的操作数必须是等宽的 例如 ax 和 cx是等宽的 al 和 cl是等宽的 ah 和 cl是等宽的 eax 和 ax不是等宽的,因为eax是32位的,ax是16位的
|
内存

每个进程都有4G的虚拟内存,当某一块虚拟内存需要用到的时候,会将这块虚拟内存映射到物理内存中,最后物理内存会将这块内存映射到内存条中
1 2 3 4 5 6 7
| BYTE 字节 = 8(BIT) WORD 字 = 16(BIT) DWORD 双字 = 32(BIT) 1KB = 1024 BYTE 1MB = 1024 KB 1GB = 1024 MB
|
mov指令使用内存
1 2 3 4 5
| mov 类型 ptr ds:[内存编号],值
mov byte ptr ds:[00A90280],22 mov word ptr ds:[00A90280],22 mov dword ptr ds:[00A90280],22
|
从指定内存中写入/读取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| mov dword ptr ds:[0x0012FF34],0x12345678 mov eax,dword ptr ds:[0x0012FF34] dword :要读/写多少 此时是4字节 byte == 1字节 word == 2字节 ptr: Point 代表后面是一个指针 (指针的意思就是里面存的不是普通的值,而是个地址) ds:段寄存器 先不用管 记住就行 0x0012FF34:内存编号,必须是32位的 前面0可以省略 注意:地址编号不要随便写,因为内存是有保护的,并不是所有的内存都可以直接读写(需要特别处理) 建议地址编号写成esp的值
|
寻址公式
1 2 3 4 5 6 7
| LEA 指令 作用: 取当前内存的地址编号
lea 寄存器,内存地址
LEA EAX,DWORD PTR DS:[0X13FFC4] 内存地址的编号存放到EAX中 将DS:[0X13FFC4] 内存地址的编号存放到EAX中
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| 寻址公式一:[立即数] 读取内存的值: MOV EAX,DWORD PTR DS:[0x13FFC4] MOV EAX,DWORD PTR DS:[0x13FFC8] 向内存中写入数据: MOV DWORD PTR DS:[0x13FFC4],eax MOV DWORD PTR DS:[0x13FFC8],ebx 获取内存编号: LEA EAX,DWORD PTR DS:[0X13FFC4] LEA EAX,DWORD PTR DS:[ESP+8] 寻址公式二:[reg] reg代表寄存器 可以是8个通用寄存器中的任意一个 读取内存的值: MOV ECX,0x13FFD0 MOV EAX,DWORD PTR DS:[ECX] 向内存中写入数据: MOV EDX,0x13FFD8 MOV DWORD PTR DS:[EDX],0x87654321 获取内存编号: LEA EAX,DWORD PTR DS:[EDX] MOV EAX,DWORD PTR DS:[EDX] 寻址公式三:[reg+立即数] 读取内存的值: MOV ECX,0x13FFD0 MOV EAX,DWORD PTR DS:[ECX+4] 向内存中写入数据: MOV EDX,0x13FFD8 MOV DWORD PTR DS:[EDX+0xC],0x87654321 获取内存编号: LEA EAX,DWORD PTR DS:[EDX+4] MOV EAX,DWORD PTR DS:[EDX+4] 寻址公式四:[reg+reg*{1,2,4,8}] 读取内存的值: MOV EAX,13FFC4 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 获取内存编号: LEA EAX,DWORD PTR DS:[EAX+ECX*4] 寻址公式五:[reg+reg*{1,2,4,8}+立即数] 读取内存的值: MOV EAX,13FFC4 MOV ECX,2 MOV EDX,DWORD PTR DS:[EAX+ECX*4+4] 向内存中写入数据: MOV EAX,13FFC4 MOV ECX,2 MOV DWORD PTR DS:[EAX+ECX*4+4],87654321 获取内存编号: LEA EAX,DWORD PTR DS:[EAX+ECX*4+2]
|
存储模式
大端模式:数据高位在低位,数据低位在高位
小端模式:数据低位在低位,数据高位在高位
| 大端0x12345678 |
小端0x12345678 |
地址 |
| 12 |
78 |
0x00000000 |
| 34 |
56 |
0x00000001 |
| 56 |
34 |
0x00000002 |
| 78 |
12 |
0x00000003 |
DTDEBUG内存窗口的使用
分别以字节/字/双字形式来查看内存(db dw dd)

基本汇编指令
MOV指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| MOV 的语法: 1、MOV r/m8,r8 r 通用寄存器 2、MOV r/m16,r16 m 代表内存 3、MOV r/m32,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指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ADD AL, imm8
ADD AX, imm16
ADD EAX, imm32
ADD r/m8, imm8
ADD r/m16,imm16
ADD r/m32,imm32
ADD r/m16, imm8
ADD r/m32, imm8
ADD r/m8, r8
ADD r/m16, r16
ADD r/m32, r32
ADD r8, r/m8
ADD r16, r/m16
ADD r32, r/m32
|
ADC指令:带进位加法
1 2 3 4 5 6 7 8
| 格式:ADC R/M,R/M/IMM 两边不能同时为内存 宽度要一样 ADC AL,CL ADC BYTE PTR DS:[12FFC4],2 ADC BYTE PTR DS:[12FFC4],AL
|
SBB指令:带借位减法
1 2 3 4 5 6 7 8
| 格式:SBB R/M,R/M 两边不能同时为内存 宽度要一样 SBB AL,CL SBB BYTE PTR DS:[12FFC4],2 SBB BYTE PTR DS:[12FFC4],AL
|
SUB指令
减法指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| SUB AL, imm8
SUB AX, imm16
SUB EAX, imm32
SUB r/m8, imm8
SUB r/m16,imm16
SUB r/m32,imm32
SUB r/m16, imm8
SUB r/m32, imm8
SUB r/m8, r8
SUB r/m16, r16
SUB r/m32, r32
SUB r8, r/m8
SUB r16, r/m16
SUB r32, r/m32
|
XCHG指令:交换数据
1 2 3 4 5 6 7 8
| 格式:XCHG R/M,R/M/IMM 两边不能同时为内存 宽度要一样 XCHG AL,CL XCHG DWORD PTR DS:[12FFC4],EAX XCHG BYTE PTR DS:[12FFC4],AL
|
AND 指令
与指令,两个是1才是1,否则是0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| AND AL, imm8
AND AX, imm16
AND EAX, imm32
AND r/m8, imm8
AND r/m16,imm16
AND r/m32,imm32
AND r/m16, imm8
AND r/m32, imm8
AND r/m8, r8
AND r/m16, r16
AND r/m32, r32
AND r8, r/m8
AND r16, r/m16
AND r32, r/m32
|
OR指令
或指令,有一个是1就是1,两个是0就是0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| OR AL, imm8
OR AX, imm16
OR EAX, imm32
OR r/m8, imm8
OR r/m16,imm16
OR r/m32,imm32
OR r/m16, imm8
OR r/m32, imm8
OR r/m8, r8
OR r/m16, r16
OR r/m32, r32
OR r8, r/m8
OR r16, r/m16
OR r32, r/m32
|
XOR指令
异或指令, 两个不一样才是1,否则是0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| XOR AL, imm8
XOR AX, imm16
XOR EAX, imm32
XOR r/m8, imm8
XOR r/m16,imm16
XOR r/m32,imm32
XOR r/m16, imm8
XOR r/m32, imm8
XOR r/m8, r8
XOR r/m16, r16
XOR r/m32, r32
XOR r8, r/m8
XOR r16, r/m16
XOR r32, r/m32
|
NOT 指令
非指令,0变1,1变0
1 2 3 4 5
| NOT r/m8
NOT r/m16
NOT r/m32
|
MOVS指令:移动数据 内存-内存
移动内存[ESI]]的数据到内存[EDI]中
每复制一次,ESI和EDI都会+1(具体加几或减几要看你一次移动多少个字节)或-1,具体是加还是减要看标志寄存器中DF的值,DF是0就+1,D是1就-1
1 2 3 4 5 6 7
| 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
|

STOS指令:
将Al/AX/EAX的值存储到[EDI]指定的内存单元
1 2 3 4 5
| STOS BYTE PTR ES:[EDI] 简写为STOSB STOS WORD PTR ES:[EDI] 简写为STOSW STOS DWORD PTR ES:[EDI] 简写为STOSD
|

REP指令:
按计数寄存器 (ECX) 中指定的次数重复执行字符串指令
1 2 3 4 5 6 7 8 9 10 11
| MOV ECX,10 REP MOVSD REP STOSD
将内存[esi]中的数据重复ecx次复制到内存[edi]中,每次重复esi和edi都加4 REP MOVS DWORD PTR ES:[EDI],DWORD PTR ES:[ESI]
将EAX中的值重复ECX次复制到内存[EDI]中,每重复一次,edi都加4 REP STOS DWORD PTR ES:[EDI]
|
堆栈
查看堆栈的大小



ESP寄存器用来存放当前堆栈使用到哪里的地址
PUSH指令:
入栈指令
1 2 3 4 5 6 7 8 9
| 1、PUSH r32
2、PUSH r16
3、PUSH m16
4、PUSH m32
5、PUSH imm8/imm16/imm32
|
POP指令
出栈指令
1 2 3 4 5 6 7
| 1、POP r32
2、POP r16
3、POP m16
4、POP m32
|
通过其他指令实现堆栈的存取

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| 步骤一:压入数据 MOV EBX,13FFDC BASE MOV EDX,13FFDC TOP 方式一: MOV DWORD PTR DS:[EDX-4],0xAAAAAAAA SUB EDX,4 方式二: SUB EDX,4 MOV DWORD PTR DS:[EDX],0xBBBBBBBB 方式三: MOV DWORD PTR DS:[EDX-4],0xDDDDDDDD LEA EDX,DWORD PTR DS:[EDX-4] 方式四: LEA EDX,DWORD PTR DS:[EDX-4] MOV DWORD PTR DS:[EDX],0xEEEEEEEE 步骤二:读取第N个数 1、方式一:通过Base加偏移来读取 读第一个压入的数据: MOV ESI,DWORD PTR DS:[EBX-4] 读第四个压入的数据: MOV ESI,DWORD PTR DS:[EBX-0x10] 2、方式二:通过Top加偏移来读取 读第二个压入的数据: MOV EDI,DWORD PTR DS:[EDX+4] 读第三个压入的数据: MOV EDI,DWORD PTR DS:[EDX+8] 步骤三:弹出数据 MOV ECX,DWORD PTR DS:[EDX] LEA EDX,DWORD PTR DS:[EDX+4] MOV ESI,DWORD PTR DS:[EDX] ADD EDX,4 LEA EDX,DWORD PTR DS:[EDX+4] MOV EDI,DWORD PTR DS:[EDX-4]
|
修改EIP寄存器
EIP寄存器存放的是cpu下一条执行的指令
JMP指令:修改EIP的值
1 2 3 4 5 6
| JMP 寄存器/立即数 类似 MOV EIP,寄存器/立即数
jmp eax jmp 0x11232244
|
CALL指令:
1 2 3 4 5
| CALL 地址A/寄存器
类似 PUSH 地址B MOV EIP,地址A/寄存器
|
RET指令:
1 2 3 4 5 6 7 8 9 10
| RET [num] [num] 可选
ret ret 8
类似 LEA ESP,[ESP+4] MOV EIP,[ESP-4]
|
堆栈平衡
进函数前esp和ebp是什么样的,执行函数之后就要还原什么样的
EFLAGS寄存器

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| 查看DTDEBUG中的EFLAGS的值,然后转换成二进制的形式,并取出CF/PF/AF/ZF/SF/OF的值 记住这几个寄存器的位置和名称 1、进位标志CF(Carry Flag):如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。 MOV AL,0xEF MOV AL,0xFE ADD AL,2 ADD AL,2 2、奇偶标志PF(Parity Flag):奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。 如果“1”的个数为偶数,则PF的值为1,否则其值为0。 MOV AL,3 ADD AL,3 ADD AL,2 3、辅助进位标志AF(Auxiliary Carry Flag): 在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0: (1)、在字操作时,发生低字节向高字节进位或借位时; (2)、在字节操作时,发生低4位向高4位进位或借位时。 MOV EAX,0x55EEFFFF MOV AX,5EFE MOV AL,4E ADD EAX,2 ADD AX,2 ADD AL,2 4、零标志ZF(Zero Flag):零标志ZF用来反映运算结果是否为0。 如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。 XOR EAX,EAX MOV EAX,2 SUB EAX,2 5、符号标志SF(Sign Flag):符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。 MOV AL,7F ADD AL,2 6、溢出标志OF(Overflow Flag):溢出标志OF用于反映有符号数加减运算所得结果是否溢出。 如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。 最高位进位与溢出的区别: 进位标志表示无符号数运算结果是否超出范围. 溢出标志表示有符号数运算结果是否超出范围. 溢出主要是给有符号运算使用的,在有符号的运算中,有如下的规律: 正 + 正 = 正 如果结果是负数,则说明有溢出 负 + 负 = 负 如果结果是正数,则说明有溢出 正 + 负 永远都不会有溢出.
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 1、无符号、有符号都不溢出 MOV AL,8 ADD AL,8 2、无符号溢出、有符号不溢出 MOV AL,0FF ADD AL,2 3、无符号不溢出、有符号溢出 MOV AL,7F ADD AL,2 4、无符号、有符号都溢出 MOV AL,0FE ADD AL,80
|
CMP指令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 指令格式:CMP R/M,R/M/IMM 该指令是比较两个操作数,实际上,它相当于SUB指令,但是相减的结构并不保存到第一个操作数中。 只是根据相减的结果来改变零标志位的,当两个操作数相等的时候,零标志位置1。 MOV EAX,100 MOV ECX,100 CMP EAX,ECX 观察Z位 MOV EAX,100 MOV ECX,200 CMP EAX,ECX 观察S位 CMP AX,WORD PTR DS:[405000] CMP AL,BYTE PTR DS:[405000] CMP EAX,DWORD PTR DS:[405000]
|
TEST指令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 指令格式:TEST R/M,R/M/IMM 该指令在一定程序上和CMP指令时类似的,两个数值进行与操作,结果不保存,但是会改变相应标志位. 与的操作表项如下: 1 and 1 = 1 1 and 0 = 0 0 and 1 = 0 0 and 0 = 0 常见用法:用这个指令,可以确定某寄存器是否等于0。 TEST EAX,EAX 观察Z位 但是如果EAX的二进制某些位为1的话,那么运算的结果就不为零。
|
JCC指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| 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≠ OF 14、 JNL, JGE 大于等于则跳转 (有符号数) SF=OF 15、 JLE, JNG 小于等于则跳转 (有符号数) ZF=1 or SF≠ OF 16、 JNLE, JG 大于则跳转(有符号数) ZF=0 and SF=OF 有符号无符号的区别: CMP AL,CL JG 0x12345678 JA 0x12345678
|