0x01 常用汇编指令
mov
就比较熟悉了,前面练习使用的都是这个指令,支持以下用法
mov r,imm 立即数到寄存器
mov r,m 内存到寄存器
mov r,r 寄存器到寄存器
mov m,r 寄存器到内存
mov m,imm 立即数到内存
r是寄存器,m是内存,imm是立即数
这个就不再演示了
add 加法
先将eax
值设置为1
,然后给eax
寄存器的值增加4
add eax,4
运行结果如下
sub 减法
基于上一部操作,给eax
寄存器的值减少2
sub eax,2
运算结果如下
and 与运算
将ecx
设置为1
,和上一步操作的的eax
进行与运算
and eax,ecx
运算结果如下
这里其实是0011
与0001
的与运算,结果肯定为1
or 或运算
将ecx
设置为3
,和上一步操作的eax
进行或运算
or eax,ecx
运行结果如下
实际就是0001
和0011
进行或运算,结果为3
not 非运算
直接对上一步的eax
取非
not eax
运行结果如下
3
转为000 0000 0000 0000 0000 0000 0000 0011
二进制,取非就是1111 1111 1111 1111 1111 1111 1111 1100
即FFFFFFFC
movs 移动数据
mov
指令不能完成内存到内存的操作,但是movs
指令可以。由于内存需要指令数据宽度,所以一共有下面3种写法
movs byte ptr es:[edi],byte ptr ds:[esi] 简写:movsb
movs word ptr es:[edi],word ptr ds:[esi] 简写:movsw
movs dword ptr es:[edi],dword ptr ds:[esi] 简写:movsd
这里的esi
和edi
两个寄存器用来存放需要调整数据的内存地址。
举个例子,这里我将0012FFC8
的值改为1
,然后将这个值移动到0012FFF0
上
mov edi,0012FFF0
mov esi,0012FFC8
movs dword ptr es:[edi],dword ptr ds:[esi]
运行指令结果如下
0012fff0
值已成功修改,这里除了内存的值移动修改外,还有一个需要注意的点,就是寄存器的值。
可以发现这两个寄存器的值和之前设置的都不一样了,全部都增加了4
,这个增加4
或者2
或者1
取决于数据宽度,是增加还是减少取决于EFL
寄存器中DF
位(第10位)
的取值,当DF
为0
时,进行增加,当DF
为1
时,进行减少。
这里将EFL
第十位更改为1
后,值为00000606
再次进行测试
此时0012FFCC
的值为1A2B
,再次运行指令
movs dword ptr es:[edi],dword ptr ds:[esi]
可以看到值已经修改完成,同时再次观察esi
和edi
寄存器的值
发现已经减少4
,完成实验。
stos,将al/ax/eax的值存储到[edi]指定的内存单元
在学习了一上一个指令后,看完解释,应该可以理解此命令等同于下面两条指令
mov [edi], eax
add edi, 4 ;或者 sub edi, 4
同样也是存到内存中,所以和数据宽度也有关系
stos byte ptr es:[edi] 简写为stosb,对应的就是al寄存器
stos word ptr es:[edi] 简写为stosw,对应的就是ax寄存器
stos dword ptr es:[edi] 简写为stosd,对应的就是eax寄存器
目前DF
位为1
,则存储后会减少,这里使用ax
做测试,先将eax
设置为0
,此时[edi]
为0012fff0
,然后运行以下指令
mov ax,1a2b
stos word ptr es:[edi]
运行后结果如下
运行结果如期,同时观察edi
寄存器
确实也是在之前的寄存器的值上减少了2
,因为用的是word
,所以只减少2
rep,按计数寄存器ecx
中指定的次数重复执行字符串指令
比如可以重复使用stos
,movs
等命令。比如重复10
次stos
,当前ax
为4444
,edi
为0012FFEE
,运行以下代码
mov ecx,0xa
rep stos word ptr es:[edi]
运行结果如下
同时的edi
也减少了10*2
。
0x02 堆栈常用指令
堆栈是什么?
其实我现在还没太理解清楚,还挺模糊的,按教程老师讲的话就是,程序运行时操作系统为程序分配好的内存,供程序使用。
可以通过FS
位查看到堆栈的信息,
在内存窗口中输入dd 7ffde000
可以看到栈底是0012d000
,栈顶是00130000
,堆栈是从大往小
用的。
ESP寄存器
esp
栈指针寄存器,存放当前的栈用到哪了。
push指令
用于向栈中压入数据的同时修改(减少)esp
寄存器,可以支持以下命令
push r
push m
pusm imm
运行命令push 1111
可以看到,直接基于栈指针之上的内存地址写入了1111
,同时将原本ESP
的值0012ffc4
改为了0012ffc0
,减少了4
。
pop指令
将栈当前数据存入到寄存器或者内存中,同时ESP
的值增加,感觉就和push
是相反的。
pop ebp
运行指令后,结果如下
ebp
中已存入1111
,同时也将esp
的值增加至0012ffc4
。
0x03 修改eip的指令
eip
寄存器存放着是cpu
下一次会执行的指令,是不可以通过mov
指令来进行修改的。
jmp指令
jmp
命令相当于 mov eip,1
,专用于修改eip
寄存器。可以支持两种方式
jmp r
jmp imm
立即数要写成内存地址的格式,并且此内存地址需要使用,当然也可以使用寄存器。
mov eax,0040ef57
jmp eax
按第一个f8
可以看到,多出了个红色箭头指向了下一次要执行命令的地方,再按第二个f8
eip
已经成功修改。
call指令
call
指令功能和jmp
基本一样,在此基础上,还在堆栈中存储call
指令的下一行地址
CALL 0040EF35
使用f7
进行调试
可以看到eip
成功修改,同时esp
指针也减少了4
,并且将call
指令的下一行地址进行存储。
ret指令
相当于下列两条指令
jmp [esp]
add esp,4
可以看到将栈顶的值存入了eip
中,同时将esp
的值增加4
指向下一个值。