恶意代码分析实战-x86反汇编速成班
x86反汇编速成
x86体系结构
3种硬件构成:
- 中央处理器:负责执行代码
- 内存(RAM):负责存储所有的数据和代码
- 输入/输出系统(I/O):为硬盘、键盘、显示器等设备提供接口
内存
一个程序的内存可以分为以下四个主要的节:
- 栈:栈用于函数的局部变量和参数,以及控制程序执行流。
- 堆:堆是为程序执行期间需要的动态内存准备的,用于创建(分配)新的值,以及消除(释放)不再需要的值。
- 代码:代码节包含了在执行程序任务时CPU所取得的指令。
- 数据:在程序初始加载时放到这里,程序运行时它们并不发生变化。
指令格式
一条指令由一个助记符,以及另个或多个操作数组成。
| 助记符 | 目标操作数 | 源操作数 |
|---|---|---|
| mov | ecx | 0x42 |
操作码和字节序
每条指令使用操作码告诉CPU程序要执行什么样的操作。反汇编将操作码翻译为人类易读的指令。
| 指令 | mov ecx, | 0x42 |
|---|---|---|
| 操作码 | B9 | 42 00 00 00 |
用0x42000000表示值0x42,是因为x86架构使用小端字节序。数据的字节序是指在一个大数据项中,最高位(大端)还是最低位(小端)被排在第一位。
在大端字节序下,IP地址127.0.0.1会被表示为0x7F000001,而在(本地内存的)小端字节序下,表示为0x0100007F。
操作数
操作数说明指令要使用的数据。有以下三种类型:
- 立即数:一个固定的值,如0x42
- 寄存数:指向寄存器,如ecx
- 内存地址:所在的内存地址,一般由方括号内包含值,寄存器或方程式组成,如[eax]
寄存器
寄存器是可以被CPU使用的少量数据存储器,x86处理器中有一组寄存器,可以用于临时存储或者作为工作区。
- 通用寄存器
- 段寄存器
- 状态标志
- 指令指针
| 通用寄存器 | 段寄存器 | 标志寄存器 | 指令指针 |
|---|---|---|---|
| EAX [AX, AH, AL] | CS | EFLAGS | EIP |
| EBX [BX, BH, BL] | SS | ||
| ECX [CX, CH, CL] | DS | ||
| EDX [DX, DH, DL] | ES | ||
| EBP [BP] | FS | ||
| ESP [SP] | GS | ||
| ESI [SI] |
所有通用寄存器的大小都是32位,可以在汇编代码中以32位或16位引用。
有4个寄存器(EAX,EBX,ECX,EDX)还可以8位值的方式引用,从而使用其最低的8位,或次低的8位。例如AL指向EAX寄存器的最低8位,AH指向它的次底8位。
| 32bits | 1010 | 1001 | 1101 | 1100 | 1000 | 0001 | 1111 | 0101 |
|---|---|---|---|---|---|---|---|---|
| A | 9 | D | C | 8 | 1 | F | 5 | |
| AX | ||||||||
| 1000 | 0001 | 1111 | 0101 | |||||
| AH | AL | |||||||
| 1000 | 0001 | 1111 | 0101 | |||||
| 8 | 1 | F | 5 |
通用寄存器
通用寄存器一般用于存储数据或内存地址,EAX通常存储了一个函数调用的返回值。
标志寄存器
EFLAGS寄存器是一个标志寄存器。执行期间,每一位表示要么是置位(值为1),要么是清除(值为0),并由这些值来控制CPU的运算,或者给出某些CPU的运算。重要的标志介绍如下:
ZF 当一个运算的结果等于0时,ZF被置位,否则被清除。
CF 当一个运算的结果相对于目标操作数太大或太小时,CF被置位。否则被清除。
SF 当一个运算的结果为负数,SF被置位:若结果为正数,SF被清除。对算术运算,当运算结果的最高位值为1时,SF也会被置位。
TF TF用于调式,当它被置位时,x86处理器每次只执行一条指令。
EIP,指令指针
EIP寄存器,又称为指令指针或程序计数器,保存了程序将要执行的下一条指令在内存中的地址。EIP的唯一作用就是告诉处理器接下来要做什么。
简单指令
mov 指令
| 指令 | 描述 |
|---|---|
| mov eax, ebx | 将EBX中的内容复制至EAX寄存器 |
| mov eax,0x42 | 将立即数0x42复制至EAX寄存器 |
| mov eax,[0x4037C4] | 将内存地址0x4037C4的4个字节复制到EAX寄存器 |
| mov eax,[ebx] | 将EBX寄存器指向的内存地址处4个字节复制到EAX寄存器 |
| mov eax,[ebx+esi*4] | 将ebx+esi*4等式结果指向的内存地址处4个字节复制到EAX |
lea指令
lea指令用来将一个内存地址赋值给目的操作数。
lea eax,[ebx+8] // 将EBX+8的值给EAX。
mov eax,[ebx+8] // 加载内存中地址为EBX+8处的数据。
mov和lea是等价指令,但是mov是将从内存中获得的值给eax,lea是将内存地址给eax。
算术运算
sub eax,0x10 // EAX寄存器值减去0x10
add eax,ebx // 将EBX值加入EAX并将结果保存至EAX
inc edx // EDX值递增1
dec ecx // ECX值递减1
mul value // 将eax乘上value,乘法的结果以64位形式分开保存在EDX和EAX中
// EDX存储了高的32位,EAX存储低的32位
div value // 与mul类似,但运算方向正好相反
shr // 右移
shl // 左移
ror和rol与移位指令类似,但移出的那一位会被填到另一端空出来的位上,即右循环移位(ror)会将最低位循环移到最高位;左循环(rol)则相反。
常用的逻辑和移位算术运算指令
| 指令 | 描述 |
|---|---|
| xor eax,eax | 将EAX寄存器清零 |
| or eax,0x7575 | 对EAX值进行与0x7575的or操作 |
| mov eax,0xA | 将EAX寄存器左移两位,这两个指令将导致EAX = 0x28 |
| shl eax,2 | 因为1010(0xA的二进制表示)左移两位后为101000(0x28) |
| mov bl,0xA | 将BL寄存器循环移位移两位,这两条指令将导致BL=10000010,因为1010向右循环移位2位为10000010 |
| ror bl,2 |
NOP指令
NOP什么事情也不做,当它出现时,直接执行下一条指令。nop指令实际上是xchg eax,eax的一个伪名字。不过EAX与它自身的交换等于什么事都没有做。OPCODE是0x90。
栈
后入先出的结构,用于对栈支持的寄存器包括ESP和EBP。
ESP是栈指针,包含了指向栈顶的内存地址。一些东西被压人或弹出堆栈时,这个寄存器的值相应改变。
EBP是栈基址寄存器,在一个函数中会保持不变,因此程序把它当成定位器,用来确定局部变量和参数的位置。
栈用于短期存储,经常用于保存局部变量、参数和返回地址。主要用途是管理函数调用之间的数据交换。
函数调用
1、call等于 push 参数,push当前指令地址(EIP寄存器中的内容)压入栈中。
2、分配栈中用于局部变量的空间,EBP(基址指针)也被压入栈中。
3、函数处理部分
4、调整ESP来释放局部变量的空间,恢复EBP。
5、通过调用ret指令返回,指令会从栈中弹出返回地址给EIP,程序会从原来调用的地方继续执行。
栈的布局
当数据被压入栈时,push eax,ESP会随之减小4。
当数据被取出时,pop ebx,ESP会增加4
pushad、pusha 将所有寄存器都压入栈中
popad、popa 从栈中弹出所有的寄存器
- pusha 将16位寄存器压入栈中
- pushad 将32位寄存器压入栈中
条件指令
- test 不会修改其使用的操作数,只设置标志位
- cmp 设置标志位
cmp dst,src ZF CF
dst == src 1 0
dst < src 0 1
dst > src 0 0
分支指令
jmp 无条件跳转指令
部分常见跳转指令
jz/jnz/je/jg/jge/ja/jae/jl/jle/jl/jle/jb/jbe/jo/js/jecxz
重复指令
重复指令是一组操作数据缓冲区的指令,常见的缓冲区操作指令:
movsx/cmpsx/stosx/scasx,其中x可以是b,w或者d。分别表示字节、字和双字
这些指令需要一个前缀,用于对长度超过1的数据做操作。movsb指令本身只会移动一个字节,而不使用ecx寄存器。
rep // 循环终止条件 ECX=0
repe,repz // 循环终止条件 ECX=0 , ZF = 0
repne,repnz // 循环终止条件 ECX=0 ,ZF = 1
示例:
repe cmsb // EDI和ESI设为两段缓冲区的地址,ECX必须被设为缓冲区长度,当ECX=0或者缓冲区不一致的时候,停止比较
rep stosb //用于一个给定的值初始化一块缓冲区中的字节。EDI包含了缓冲区地址,AL则包含初始值。通常与xor eax,eax一起使用
rep movsb // 一般用于复制缓冲区中的字节,ESI需要被设为源缓冲区地址,EDI被设为目的缓冲区地址,ECX则必须为要复制的长度。会逐字节复制,直至ECX=0
rep scasb // 用于一段数据缓冲区中搜索一个字节,EDI需指向缓冲区地址,AL则包含要找的字节,ECX设为缓冲区长度。当ECX=0或找到该字节时,比较停止
恶意代码分析实战-x86反汇编速成班的更多相关文章
- 恶意代码分析实战五:OllyDebug动态结合
目录 恶意代码分析实战五:OllyDebug动态结合 OllyDebug界面介绍 OllyDebug载入程序方法 OllyDebug地址跳转 OllyDebug下断点 OllyDebug单步执行 Ol ...
- 恶意代码分析实战四:IDA Pro神器的使用
目录 恶意代码分析实战四:IDA Pro神器的使用 实验: 题目1:利用IDA Pro分析dll的入口点并显示地址 空格切换文本视图: 带地址显示图形界面 题目2:IDA Pro导入表窗口 题目3:交 ...
- 恶意代码分析实战-启动一个恶意的DLL
如果不能把恶意代码运行起来,那么动态分析基础技术没有什么用. Windows版本中包含rundll32.exe程序,提供了一个运行DLL的平台. rundll32.exe Dllname,Export ...
- 恶意代码分析实战-PE资源提取
场景 1.提取恶意代码中的资源部分内容 思路 存在Loadresource函数的时候说明有一部分内容在资源里. 技术点 Lab1-4 ResourceHacker打开保存资源,载入IDA查看
- 第4章 x86反汇编速成班
4.1 抽象层次 硬件<微指令<机器码<低级语言<高级语言<解释型语言 4.2 逆向工程 4.3 x86体系结构 冯-诺依曼体系结构 中央处理器(CPU): 负责执行代码 ...
- 恶意代码分析实战-确认EXE什么时候编译的
场景 确认开源的后门在中毒机器上是什么版本,具有什么功能. 思路 1.查看样本PE里的编译时间 2.对照开源后门里组件的编译时间 技术点 查看NT头-TimeDateStamp struct IMAG ...
- Exp4 恶意代码分析 20154320 李超
恶意代码 概述 恶意代码是指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的计算机代码.最常见的恶意代码有计算机病毒(简称病毒).特洛伊木马(简称木马).计算机蠕虫(简称蠕虫).后门.逻辑炸弹等. ...
- 2017-2018-2 20155314《网络对抗技术》Exp4 恶意代码分析
2017-2018-2 20155314<网络对抗技术>Exp4 恶意代码分析 目录 实验要求 实验内容 实验环境 基础问题回答 预备知识 实验步骤 1 静态分析 1.1 使用virsca ...
- 20145236《网络攻防》Exp4 恶意代码分析
20145236<网络攻防>Exp4 恶意代码分析 一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些 ...
随机推荐
- 自学Linux Shell11.6-退出shell
点击返回 自学Linux命令行与Shell脚本之路 11.6-退出shell shell运行的每一个命令都是使用 退出状态码 告诉shell它已经运行完毕.退出状态码是一个0~255的整数值,在命令结 ...
- 自学Zabbix14.1 二次开发API
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix14.1 二次开发API Zabbix API我们可以做很多,自己开发web界面. ...
- luogu1712 区间 (尺取法+线段树)
先把区间按照长度从小到大排序,然后用尺取法来做 大概就是先一点一点把区间算上 直到某个点被覆盖了m次,然后一点一点把最前面的区间扔掉,直到没有点被覆盖m次,这样反复做(相当于是它选择的区间左右端点在那 ...
- 01---JMS与消息中间件的基本概念
JMS消息服务介绍和使用场景 什么是JMS JMS : Java Message Service(Java消息服务),Java平台中关于面向消息中间件的接口. 重点在于接口,接口就意味着与JDBC类似 ...
- ASP.NET Session的实现原理分析
ASP.NET Session的实现原理分析 用户向服务器提交请求时,服务器都会给每个用户分配一个SessionId,保存在用户浏览器的Cookies中,SessionId是全局的,也就是说只要Coo ...
- eclipse --- 新建JSP页面默认模版设置
设置 在eclipse中新建 jsp时是这样的: 有时候我们不想字符集是ISO_8859-1,想字符集是UTF-8,一个个修改会很麻烦,那么我们可以修改jsp模版的设置: window>Pref ...
- 面向对象——类的内置attr(三十三)
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('----> from geta ...
- 关于promise的一些用法
Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息. Promise对象有以下两个特点 ...
- 基于tcp和多线程的多人聊天室-C语言
之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室. 具体的实现过程: 服务器端:绑定socket对象->设置监听数-> ...
- Problems you may meet
一.正确安装sklearn却提示No module named 'sklearn.lda' It seems that you have installed a newer version of sk ...