当前位置:   article > 正文

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

反汇编

一、常用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)实现字符串复制:

  1. MOV ESI, source_address ; 将源字符串的起始地址加载到ESI
  2. MOV EDI, destination_address ; 将目标字符串的起始地址加载到EDI
  3. MOV ECX, length ; 将字符串的长度加载到ECX
  4. REPE MOVSB ; 从源字符串复制数据到目标字符串,重复ECX次

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

  1. MOV EDI, destination_address ; 将目标字符串的起始地址加载到EDI
  2. MOV AL, value ; 将要填充的值加载到AL寄存器
  3. MOV ECX, length ; 将字符串的长度加载到ECX
  4. REPE STOSB ; 将值填充到目标字符串,重复ECX次

ebp与esp结合使用

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

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

其中最重要的就是ZF 

直接寻址:读写变量

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

寄存器寻址:指针解引用 

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

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

访问数组:

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

 访问结构体:

  1. Student st;
  2. st.age = 10;
  3. 001C48E5 mov dword ptr [ebp-0Ch],0Ah
  4. st.agender = 1;
  5. 001C48EC mov byte ptr [ebp-8],1
  6. st.score = 100;
  7. 001C48F0 mov eax,64h
  8. 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的数据库文件,如果我们自己修改了程序的内容,他就会保存在这个文件里面,下次直接打开这个就好,而不会破坏源文件,当然也可以直接保存到原文件

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/461022
推荐阅读
相关标签
  

闽ICP备14008679号