逆向汇编与反汇编——汇编基础快速入门

一、常用32位寄存器介绍 

 不同位数的寄存器的名称: 

eax:累加寄存器。通常用于算数运算,将结果保留在eax当中,当然也可以用于其他用途,比如一般把返回值通过eax传递出去。

ebx:基址寄存器 。有点类似于ebp,代表基础地址,加上偏移量可以得到新的地址

ecx:计数寄存器。用来存储循环的次数,同时也常用于保存this指针。每循环一次,ecx-1

edx:数据寄存器。通常配合eax来使用。例如上面的mov ebx,10 ;div ebx ;由于除数ebx是32位,所以被除数是64位的(高32:edx,低32:eax)

将数据从原地址转移到目的地址

使用REPE MOVSB(move string byte)实现字符串复制:

MOV ESI, source_address    ; 将源字符串的起始地址加载到ESI
MOV EDI, destination_address   ; 将目标字符串的起始地址加载到EDI
MOV ECX, length      ; 将字符串的长度加载到ECX

REPE MOVSB    ; 从源字符串复制数据到目标字符串,重复ECX次

 使用REPE STOSB(store string byte)实现固定字符串填充:

扫描二维码关注公众号,回复: 15274052 查看本文章
MOV EDI, destination_address   ; 将目标字符串的起始地址加载到EDI
MOV AL, value    ; 将要填充的值加载到AL寄存器
MOV ECX, length      ; 将字符串的长度加载到ECX

REPE STOSB    ; 将值填充到目标字符串,重复ECX次

ebp与esp结合使用

因为esp经常变化,所以把esp保存在ebp这里

eip就是下一次要执行的指令的地址

其中最重要的就是ZF 

直接寻址:读写变量

int x = 10;
00BF1836  mov         dword ptr [x],0Ah  

寄存器寻址:指针解引用 

int* p = &x;
00EC1836  lea         eax,[x]  
00EC1839  mov         dword ptr [p],eax  

寄存器相对寻址:访问数组和结构体

访问数组:

int arr[4] = { 1,2,3,4 };
005C1825  mov         dword ptr [ebp-20h],1  
005C182C  mov         dword ptr [ebp-1Ch],2  
005C1833  mov         dword ptr [ebp-18h],3  
005C183A  mov         dword ptr [ebp-14h],4  

 访问结构体:

Student st;
    st.age = 10;
001C48E5  mov         dword ptr [ebp-0Ch],0Ah  
    st.agender = 1;
001C48EC  mov         byte ptr [ebp-8],1  
    st.score = 100;
001C48F0  mov         eax,64h  
001C48F5  mov         word ptr [ebp-6],ax 

Linux常用AT&T ,Windows使用intel格式

lea取地址指令

比如:lea dword ptr ds:[0xAAAAAAAA]

mov eax,10+3        (×)        mov eax,13        (√)

TEST将A和B做逻辑与,和AND的区别:TEST 不改变A的值

比如:AND eax,ebx ->会把eax与ebx做与运算,并把结果赋值给eax

而TEST eax,ebx则不会赋值给eax,而只是会影响标志位

test eax,eax 》会影响ZF标志位

JZ 0x123

CMP eax,0 (eax-0也是只影响ZF标志位)

JZ 0x123

条件跳转:JNZ JA等等

无条件跳转:JMP

NEG:0-操作数

NOT:逻辑取反(真->反)

1)movzx和movsx指令介绍

凡是带mov的指令都是用于数据传输:

mov在使用的过程当中,他的两边的操作数的位数应该是一样的

而movzx/movsx要求右边宽度必须小于左边

要求:操作数1是寄存器,op2是寄存器或者内存,不能是立即数

movzx eax,byte ptr [0x123] 》

高位没有使用的部分全部用0填充

这就非常类似数据类型之间的转换,比如char -> int类型

在od里面双击寄存器可以直接修改它的值

movsx eax,cx当中eax的高位全部使用符号位(0/1)来填充,比如:

mov ecx,0x00000088

movsx eax,cx

》结果就是eax=0xffffff88

总结一下:movzx直接不管九九八十一,最高位全部填0,而movsx则根据cx的最高位,把eax的高位全部填上符号位(0/1)

2)Test指令介绍

1.Test用来测试一个位,例如寄存器:

test eax,100b;b后缀意为二进制

jnz 0x1234;如果eax右数第三个位为1,jnz将会跳转

我是这样想的,jnz跳转的条件是ZF=0,ZF=0意味着ZF(零标志)没被置位,即逻辑与结果为1。

2.Test的一个非常普遍的用法是用来测试一方寄存器是否为空:

test ecx, ecx

jz somewhere

如果ecx为零,设置ZF零标志为1,jz跳转。

二、C++函数入口深度剖析

int argc(argument count) ,char*argv[](argument varable) 

函数调用栈:kernel32 -> mainCRTStartup -> main

CRT:C Run Time:C运行库

获取操作系统版本,在控制台程序是在命令行运行的

netstat -ano 可以加上一个命令行参数

环境变量,有变量名和值

为什么输入cmd可以进入shell执行程序呢?

》因为环境变量,执行程序会在当前环境变量当中去找/系统路径去找,如果找到了就会执行

环境变量%temp%就会打开他的值所指示的路径

把获取到的参数的数量保存在argc,把每一个参数的首地址保存在argv这个数组里面

setenvp把环境变量的地址分别保存

cinit初始化全局变量,静态变量,就比如类的构造函数执行之前他的静态成员就已经存在了

main实际push了三个参数,其中环境变量这个参数是不需要程序员来进行操作的,所以由运行库来给他填充进来就可以了

一个函数的返回值是放在eax当中的

最终main的底层是调用exit函数来进行退出的

 如何使用反汇编工具识别main函数?

将exe拖入od,main在cinit后面

od如何安装插件? 

ida使用:

debug版本有调试的信息,release发行版不包含调试信息,所以无法在VS里面调试,即使打了断点也直接就运行完了

start才是程序执行的入口

不用连接服务器获取调试信息

保存数据库就保存了一个MAIN.idb的数据库文件,如果我们自己修改了程序的内容,他就会保存在这个文件里面,下次直接打开这个就好,而不会破坏源文件,当然也可以直接保存到原文件

猜你喜欢

转载自blog.csdn.net/Tandy12356_/article/details/130916859
今日推荐