逆向笔记之基础学习(一)
本文笔记均来自于对滴水逆向教程的学习,通过学习教程记录的笔记,个人所见所得。
我感觉滴水课程原理性的讲的蛮好,通过这个来夯实基础。
大纲:
-
进制学习
- 数据宽度
- 二进制的逻辑运算
- 通用寄存器
- 常见汇编指令
- 内存
- 标志寄存器
- 堆栈
- jcc
进制
学习大纲:
- 进制的实质就是查表
- 熟悉2进制跟16进制的转换
- 熟悉进制表的制作以及计算进制之间的加减乘除
进制练习
- 通过编写7进制加法表,乘法表,并计算
- 23456+54356 = ?
- 5621 - 654 = ?
- 234 * 65 = ?
- 2+3 = 1?可能嘛
- 16进制与二进制的映射
- 自行编写进制加密
练习1解答
首先编写1-100的7进制数据
一 |
二 |
三 |
四 |
五 |
六 |
七 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
编写7进制加法表
一 |
二 |
三 |
四 |
五 |
六 |
1+1=2 |
|
|
|
|
|
1+2=3 |
2+2=4 |
|
|
|
|
1+3=4 |
2+3=5 |
3+3=6 |
|
|
|
1+4=5 |
2+4=6 |
3+4=10 |
4+4=11 |
|
|
1+5=6 |
2+5=10 |
3+5=11 |
4+5=12 |
5+5=13 |
|
1+6=10 |
2+6=11 |
3+6=12 |
4+6=13 |
5+6=14 |
6+6=15 |
编写7进制乘法表
一 |
二 |
三 |
四 |
五 |
六 |
1*1=1 |
|
|
|
|
|
1*2=2 |
2*2=4 |
|
|
|
|
1*3=3 |
2*3=6 |
3*3=12 |
|
|
|
1*4=4 |
2*4=11 |
3*4=14 |
4*4=22 |
|
|
1*5=5 |
2*5=13 |
3*5=21 |
4*5=26 |
5*5=34 |
|
1*6=6 |
2*6=15 |
3*6=24 |
4*6=33 |
5*6=42 |
6*6=51 |
计算结果:
$23456 + 54356 = ?$
计算过程:
- 6+6 查表是15,进一位,留5
- 5+5 查表是13, 13 + 1,3+1查表为4,为14,进一位,留4
- 4+3 查表是10, 10 + 1,11,进一位,留1
- 3+4 查表是10, 10+1 = 11,进一位,留1
- 2+5 查表是10, 10+1 = 11,进一位,留1
结果为:111145
$5621 - 654 = ?$
计算过程:
- 1不够减,借一位,为11,11-4=?,查表可得为4,
- 2-1 = 1,1-5不够,借一位,11-5=3
- 5-6不够,15-6=6
- 4
结果为:4634
$234 * 65 = ?$
计算过程:
- 4*5 = 26,留6 进2
- 3*5 = 21, 21+2, 23,留3 进2
- 2*5 = 13 13+2=15 留5,进1
- 1536
- 4*6 = 33, 留3 进3
- 3*6 = 24, 24+3,4+3 == 10,留0,进3
- 2*6 = 15, 15+3, 5+3=11,进2,留1
- 2103
结果为:22536
练习2解答
可能,当定义如下的10进制时便可,0,2,3,1,5,6,7,8,9,4
练习3解答
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
0001 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
1000 |
1001 |
1010 |
1011 |
1100 |
1101 |
1110 |
1111 |
练习4解答
定义如下的7进制,4,5,6,1,2,3,0
试着计算上题中的计算题目
先编写进制对应
一 |
二 |
三 |
四 |
五 |
六 |
七 |
4 |
5 |
6 |
1 |
2 |
3 |
0 |
54 |
55 |
56 |
51 |
52 |
53 |
50 |
64 |
65 |
66 |
61 |
62 |
63 |
60 |
14 |
15 |
16 |
11 |
12 |
13 |
10 |
24 |
25 |
26 |
21 |
22 |
23 |
20 |
34 |
35 |
36 |
31 |
32 |
33 |
30 |
04 |
05 |
06 |
01 |
02 |
03 |
00 |
编写7进制加法表
一 |
二 |
三 |
四 |
五 |
六 |
5+5=6 |
|
|
|
|
|
5+6=1 |
6+6=2 |
|
|
|
|
5+1=2 |
6+1=3 |
1+1=0 |
|
|
|
5+2=3 |
6+2=0 |
1+2=54 |
2+2=55 |
|
|
5+3=0 |
6+3=54 |
1+3=55 |
2+3=56 |
3+3=51 |
|
5+0=54 |
6+0=55 |
1+0=56 |
2+0=51 |
3+0=52 |
0+0=53 |
编写7进制乘法表
一 |
二 |
三 |
四 |
五 |
六 |
5*5=5 |
|
|
|
|
|
5*6=6 |
6*6=2 |
|
|
|
|
5*1=1 |
6*1=0 |
1*1=56 |
|
|
|
5*2=2 |
6*2=55 |
1*2=53 |
2*2=66 |
|
|
5*3=3 |
6*3=51 |
1*3=65 |
2*3=60 |
3*3=12 |
|
5*0=0 |
6*0=53 |
1*0=62 |
2*0=11 |
3*0=26 |
0*0=35 |
计算
$23456+54356=?$
计算过程:
- 6+6 = 2 留2
- 5+5 = 6 留6
- 4+3 = 3 留3
- 3+4 = 3 留3
- 2+5 = 3 留3
结果:33362
$5621-654=?$
计算过程:
- 1-4 = 1
- 2-5 = 1
- 6-6 = 0
- 5
结果:5011
$234*65=?$
计算过程:
- 4*5 = 4
- 3*5 = 3
- 2*5 = 2
- 234
- 4*6 = 4
- 3*6 = 51 留1 进5
- 2*6 = 55 55 + 5 , 5+5=6, 55+5=56,留6,进5
- 5614
结果:51434
数据宽度
记住圆圈,
数据类型 |
单位(bit) |
byte 字节 |
8 |
word 字 |
16 |
dword 双字 |
32 |
qword 四字 |
64 |
内存中只存0和1,没有正负数只分,正负数是人为分开的,通过圆圈
二进制逻辑运算
- 与(and &)
- 或(or |)
- 异或(xor ^)
- 非(not !)
具体应用
- CPU如何计算2+3=?
X:0010
Y:0011
其实很好理解,xor是取出不需要进位的,而&是取出要进位的,
X&Y=0010
X^Y=0001
所以x+y的时候需要第二位进第三位,所以左移一位
0100 在将不需要进位的搞回去
0100 ^ 0001 = 0101
- 获取某个值的第N位的值是多少?
与第n位就行
- 简单加密算法
xor加密,然后xor还可以解密
通用寄存器
|
寄存器 |
|
(编号)二进制 |
(编号)十六进制 |
32位 |
16位 |
8位 |
|
|
eax |
ax |
al |
000 |
0 |
ecx |
cx |
cl |
001 |
1 |
edx |
dx |
dl |
010 |
2 |
ebx |
bx |
bl |
011 |
3 |
esp |
sp |
ah |
100 |
4 |
ebp |
bp |
ch |
101 |
5 |
esi |
si |
dh |
110 |
6 |
edi |
di |
bh |
111 |
7 |
r通用寄存器
m代表内存
imm代表立即数
r8代表8位通用寄存器
imm8代表8位立即数
m8代表8位内存
小结
-
32位通用寄存器,
位通用寄存器,8位寄存器
EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
-
寄存器eax-ax-ah-al的关系
EAX > ax > ah=al
子集关系
常见汇编
mov指令
mov 目标操作数,源操作数
- 源操作数可以是立即数,通用寄存器,段寄存器,内存单元
- 源操作数和目标操作数不能同时为内存单元
- 操作数宽度必须一样
- mov r/m8, r8
- mov r/m16, r16
- mov r/m32, r32
- mov r8, r/m8
- mov r16, r/m16
- mov r32, r/m32
- mov r8, imm8
- mov r16, imm16
- mov r32, imm32
add指令
同理,替换掉mov指令成add指令,上述也是成立的
sub指令
同理,替换掉mov指令成sub指令,上述也是成立的
and指令
同理,替换掉mov指令成sub指令,上述也是成立的
or指令
同理,替换掉mov指令成sub指令,上述也是成立的
xor指令
同理,替换掉mov指令成sub指令,上述也是成立的
not指令
not r/m8
not r/m16
not r/m32
ADC指令带进位加法
ADC R/M,R/M/IMM 两边不能同时为内存,宽度要一样
SBB带借位减法
SBB R/M,R/M/IMM 两边不能同时为内存,宽度要一样
XCHG 交换数据
XCHG R/M, R/M 不能为立即数啊,想想变量a跟1交换是什么鬼
MOVS 移动数据 内存-内存
都是内存
只有edi跟esi能用
movs byte ptr es:[edi],byte ptr ds:[esi]
简写
- movsb byte
- movsw word
- movsd dword
D标志为1,esi跟edi减,D标志为0,+
STOS 将AL/AX/EAX的值存储到[edi]指定的内存单元
stos byte ptr es:[edi]
简写
方向由D位决定
REP 按ecx指定的次数重复执行
mov ecx,10
rep movsd
就是重复movsd 16次
内存
寄存器与内存的区别
- 寄存器位于CPU内部,执行速度块,但比较贵
- 内存速度相对较慢,成本较低,可以做的很大
- 计算机中几个常用计量单位: byte, word, dword, qword
byte 字节 = 8bit
word 字 = 16bit
dword 双字 = 32bit
qword 四字 = 64bit
1kb = 1024 byte
1mb = 1024kb
1gb = 1024mb
1024 = 2的10次方
-
32位计算机是因为地址总线总共有32条,最大寻址范围是0-0xFFFFFFFF, 内存中最多能存储信息0+0xFFFFFFFF = 100000000即4g
-
32位寻址最多识别内存为4g对吗?
通常情况下是4g
不对,可以通过打补丁
内存与立即数区别
内存:[编号]
立即数: 数值
内存读写
涉及内存读写要指定数据宽度,也就是word,dword指定
mov word ptr ds:[0x12345678],0xffff
mov dword ptr ds[0x12345678],0xffff
从高位往低写,比如写word,小端存储的话,是高位存高位,低位存低位
寻址公式
立即数寻址
mov eax,dword ptr ds:[0x13ffc4]
获取内存编号
lea eax,dword ptr ds:[0x13ffc4]
lea还可以用来计算
寄存器寻址
mov ecx,12ffc4
mov eax,dword ptr ds:[ecx]
lea eax,dword ptr ds:[ecx]
寄存器+立即数寻址
mov eax,dword ptr ds:[ecx+4]
lea eax,dword ptr ds:[ecx+8]
[reg+reg*{1,2,4,8}]
mov eax,13ffc4
mov ecx,2
mov edx,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]
标志寄存器
- 进位标志CF(carry flag) 最高位产生进位或者借位,
- 奇偶标志位PF(Parity flag) 结果中1的个数,偶数PF=1,奇数PF=0
- 辅助进位标志AF(Auxiliary Carry flag)
- 零标志位ZF(zero flag) 用来反映结果是否是0
- 符号标志位SF(signed flag) 运算结果的符号位
- 溢出标志位OF(overflow flag)
自己学会拆EFL
进位标志CF(Carry Flag)
如果运算结果的最高位产生了一个进位或借位,要确定数据宽度,比如add al,1 只要al进位了,就会改变标志位
无符号关注CF位
奇偶标志位PF(Parity Flag)
奇偶标志位PF用于反映运算结果中'1'的个数的奇偶性,如果为偶数,则为1, 反之为0
mov al,3 011
add al,3 110 #P为1
add al,2 1000 #P为0
辅助进位标志AF(Auxiliary Carry Flag)
以下情况,AF为1,否则为0
1) 在字操作时,发生低字节向高字节进位或借位时
2) 在字节操作时,发生低4位向高四位进位或借位时
mov eax,55eeffff
add eax,2
低四位+2进位了,所以AF为1
mov ax,5efe
add ax,2
就看fe进位没,进位了,所以AF为1
注意这里要看bit
零标志位ZF(Zero Flag)
零标志ZF用来反映运算结果是否为0
xor eax,eax 清0同时还会影响标志位
mov eax,0 清0 不影响标志位
符号标志SF(Sign Flag)
运算结果的符号位,与运算结果最高位相同
mov al,7f
add al,2
溢出标志OF(Overflow Flag)
进位标志表示无符号数运算结果是否超出范围
溢出主要是给有符号运算使用
- 正+正=正 如果结果是负数,则说明溢出了
- 负+负=负 如果结果是整数,则说明溢出了
- 正+负 永远不会溢出
理解那个圈,那个圈挺有用的
1. 无符号,有符号都不溢出
mov al,8
add al,8
2. 无符号溢出,有符号不溢出
mov al,0ff
add al,2
无符号超过了,溢出,有符号,-1+2 = 1肯定不溢出
3. 无符号不溢出,有符号溢出
mov al,7f
add al,2
有符号,7f和2都是正数,+过后变成负数了,所以溢出了
4. 无符号,有符号都溢出
mov al,0fe
add al,80
fe负数,80负数 加起来是正数,
无符号,也溢出了,超过最大的ff了
方向标志DF(Direction Flag)
edi跟esi的方向
堆栈
EBP跟ESP,
EBP栈底
ESP栈顶
push 一次 esp-4
pop 一次 esp+4
push
push r32
push r16
push m32
push m16
push imm8,imm16,imm32
pop
pop r32
pop r16
pop m16
pop m32
pushad
pushad将通用寄存器全部push进去,按照寄存器顺序,eax,ecx,edx,ebx,esp,ebp,esi,edi,8个通用寄存器8*4=32个字节,所以是sub esp,0x20
popad
恢复全部通用寄存器
练习
- push 后,esp改动的一定是按机器字长来的吗?
练习解答
不一定,可以push 16位的二进制数,esp-2,不可以弄8进制的数
32位:
pushad popad
jcc
修改eip
jmp 影响eip的值 jmp reg/imm
call 也影响eip的值 call imm/reg
push 当前指令地址+指令长度地址,mov eip,imm/reg
retn 相当于pop eip
cmp指令
cmp只修改标志寄存器,相当于sub,
作用比较大小,看sf
是否等于0,看zf
test指令
test R/M,R/M/IMM
实质是&
test eax,eax 判断eax是不是0
jcc跳转
jcc指令 |
说明 |
条件 |
JE, JZ |
结果为零则跳转(相等时跳转) |
ZF=1 |
JNE, JNZ |
结果不为零则跳转(不相等时跳转) |
ZF=0 |
JS |
结果为负则跳转 |
SF=1 |
JNS |
结果为非负则跳转 |
SF=0 |
JP, JPE |
结果中1的个数为偶数则跳转 |
PF=1 |
JNP, JPO |
结果中1的个数为偶数则跳转 |
PF=0 |
JO |
结果溢出了则跳转 |
OF=1 |
JNO |
结果没有溢出则跳转 |
OF=0 |
JB, JNAE |
小于则跳转 (无符号数) |
CF=1 |
JNB, JAE |
大于等于则跳转 (无符号数) |
CF=0 |
JBE, JNA |
小于等于则跳转 (无符号数) |
CF=1 or ZF=1 |
JNBE, JA |
大于则跳转(无符号数) |
CF=0 and ZF=0 |
JL, JNGE |
小于则跳转 (有符号数) |
SF≠ OF |
JNL, JGE |
大于等于则跳转 (有符号数) |
SF=OF |
JLE, JNG |
小于等于则跳转 (有符号数) |
ZF=1 or SF≠ OF |
JNLE, JG |
大于则跳转(有符号数) |
ZF=0 and SF=OF |
总结
基础不扎实,感觉逆向起来特费劲,通过这个教程来巩固基础,将笔记进行整理分享