参考资料:

本文大量内容抄袭看雪作者:waiWH的VMP系列

1、名称:谈谈vmp的还原(1)

网址:[原创]谈谈vmp的还原(1)-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com

2、名称:汇编指令之OpCode快速入门

网址:[原创]汇编指令之OpCode快速入门-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com

3、名称:X86指令编码内幕 --- 指令 Opcode 码

网址:X86指令编码内幕 --- 指令 Opcode 码_晓风残月的技术天地-CSDN博客

说明:

1、将struct_VmFunctionAddr结构体称为需要二次解析的称为:特殊Opcode(SetDisassemblyFunction_Address函数填充)

2、将struct_DisassemblyFunction结构体称为:基础Opcode(Vmp_Disassembly填充)

3、壳模板代码和用户加密代码都是调用Vmp_AllDisassembly函数解析,只是保存的位置不一样而已

4、注意struct_DisassemblyFunction是按顺序存放的

例如:

push 1

push 2

push 3

那么push 1 肯定存放在Address[0]

那么push 2 肯定存放在Address[1]

那么push 3 肯定存放在Address[2]

正文:

1、Vmp_AllDisassembly框架详解

总结:

1、核心部分在于Vmp_Disassembly函数,里面就是解析Opcode指令

2、部分Opcode需要二次处理

3、解析壳自身代码跟用户Opcode都是调用这个函数

2、Vmp_Disassembly解析Opcode函数分析

2、1: 随便拿条Opcode实例说明:

举例Opcode:0047497B 8B7424 28 mov esi,dword ptr ss:[esp+0x28]

1、Legacy Prefix(可选)
2、Opcode(必须有) 0x8B
3、ModRM(可选) 0x74
4、SIB(可选) 0x24
5、Displacement(可选) 0x28
6、Immediate(可选)

2、2: 读取主操作码或则前缀,因为Prefix 与 Opcode 共同占用这个空间

由于 x86/x64 是 CISC 架构,指令不定长。解码器解码的唯一途径就是按指令编码的序列进行解码,关键是第 1 字节是什么? 如:遇到 66h,它就是 prefix,遇到 89h,它就是 Opcode。

2、3:GetSize_0函数

函数作用:用来区别读取字节长度

哪里找到赋值的?

Vmp_ReadPEInformation函数,我整个文件导了个遍都只发现赋值为1,没有2?

2、4:三个比较重要的变量(legacy prefix 的作用)

UPX0:00481DDE ; 546: v529 = 0;

UPX0:00481DDE 094 C6 45 F5 00 mov [ebp+var_B], 0

UPX0:00481DE2 ; 547: v531 = 0;

UPX0:00481DE2 094 C6 45 F7 00 mov [ebp+var_9], 0

UPX0:00481DE6 ; 548: v530 = 0;

UPX0:00481DE6 094 C6 45 F6 00 mov [ebp+var_A], 0

1、它们在哪里赋值?

v529 赋值的地方:

case 0x66u: // 指令前缀:66H—操作数大小重载前缀,也可被用作某些指令的强制性前缀.

v529 = 1;

v531 赋值的地方:

case 0x67u: // 指令前缀:67H—地址尺寸重载前缀

v531 = 1;

v530 赋值的地方:(大概猜测是Rex前缀,因为没有Magic=2)

REX前缀是16个编码操作码的集合,包含40H到4FH。这些操作码在IA-32模式和兼容模式中代表有意义的指令。在64位模式中,相同的操作码则代表REX前缀,不再当做单独的指令看待。

3、根据switch执行不同的流程解析Opcode

3、1:通过手册我们得知8B对应的是MOV r32,r/m32(Gv, Ev)

3、2: Register_Or_Memory = (v13 & 2) == 2这句代码是什么意思?(只针对我举例的,这里只是说明如何找)

我们翻看手册发现了规律是判断目标操作数:G 是寄存器或则E 是寄存器或者内存操作数

Gv, Ev 表示:

(1)两个 Operands 分别是:目标操作数 Gv,源操作数 Ev 或说:frist operand 是 Gv, second operand 是 Ev

(2)Gv 表示:G 是寄存器操作数,v 是表示操作数大小依赖于指令的 Effective Operand-Size,可以是 16 位,32 位以及 64 位。

(3)Ev 表示:E 是寄存器或者内存操作数,具体要依赖于 ModRM.r/m,操作数大小和 G 一致。

4 个字符便可以很直观的表示出:操作数的个数以及寻址方式,更重要的信息是这个 Opcode 的操作数需要 ModRM 进行寻址。

举例子说明:

0047497B    8B7424 28       mov esi,dword ptr ss:[esp+0x28]

0047497B    8A7424 28       mov dh,byte ptr ss:[esp+0x28]

0047497B    887424 28       mov byte ptr ss:[esp+0x28],dh

0047497B    897424 28       mov dword ptr ss:[esp+0x28],esi

v14 =88 Register_Or_Memory =0

v14 =89 Register_Or_Memory =0

v14 =8a Register_Or_Memory =1

v14 =8b Register_Or_Memory =1

总结:

1、这句代码是判断目标操作数是:G 是寄存器或则E 是寄存器或者内存操作数

2、Ev是包含不确定性具体要依赖于 ModRM.r/m

3、3:通过上文描述就可以解释作者为何设计成要区分Register_Or_Memory来区分先执行SetReg跟ModRm

因为假设是Mov Gv,Ev这种类型的:目标操作数是确定Gv,但是源操作数是Ev是包含不确定性具体要依赖于 ModRM.r/m

我们举例的很明显就是MOV r32,r/m32(Gv, Ev),目标已知,源带有未知性

3、4:我们先来分析Decode_SetReg函数

一共有3组,每组0x17个字节,包含结尾表示0xFFFFFFFF,这些都是保存目标操作数或则源操作数信息的

v6 = (v9 >> 3) & 7;

首先v9=0x74,继续我们的查表

转换成二进制如下:

0x74=‭‭01 110 100‬

结构 描述 内容
ModRM.mod 寻址模式 01
ModRM.reg 寄存器 110
ModRM.r/m 寄存器或则地址 100

很明显v6=ModRM.reg(Esi)

3、5:分析Decode_ModRM结构

1、首先解析ModRm判断寻址模式

首先先将ModRM转换下

转换成二进制如下:

0x74=‭‭01 110 100‬

结构 描述 内容
ModRM.mod 寻址模式 01
ModRM.reg 寄存器 110
ModRM.r/m 寄存器或则地址 100

0x40=01,0x80=10,0xC0=11以此类推

2、判断是否需要SIB寻址方式

R/M==8(100),只有ModRM.mod寻址模式是11(寄存器是不带SIB的)如上图所示

1、第一种这里是ModRM.mod 提供寻址模式: 11 = register(寄存器)

直接保存ModRM.r/m

2、第二种情况存在SIB寻址方式

根据上文找到的地址发现是[--][--]”,表示有SIB表

SIB结构如下:

转换成2进制如下:

0x24=‭00 101 100‬

结构 描述 内容
SIB.scale 提供 index 寄存器乘数因子 scale 00
SIB.index 提供 index 寄存器寻址 101
SIB.base 提供 base 寄存器寻址 100

1、读取SIB字节

2、((unsigned __int8)v10 >> 3) & 7; // SIB.index 提供 index 寄存器寻址

3、v9->SIB_base = SIB & 7; // SIB.base 提供 base 寄存器寻址

4、if ( v9->ModRM_Reg_Or_SIB_index_Or_ModRM_rm == 4 )// SIB.index 提供 index 寄存器寻址是否是none 4 = (100)

5、假设index寄存器!=4就保存SIB.scale 提供 index 寄存器乘数因子 scale

6、判断SIB.base 提供 base 寄存器寻址是否是[*] 5 = (101)

最后读取Displacement_Immediate

3、6 还有一些Opcode需要ModRM进行补充的

单纯的一个FF无法表达它到底是CALL、INC、jmp、push需要ModRm辅助的,具体看ModRm.Reg

3、7 Vmp_Disassembly使用的结构体如下:

所有解析后的数据都保存在struc_SaveAllDisasmFunData结构里面

4、特殊Opcode解析

一般例如jmp call都是需要二次解析的

0、随便拿条命令举例说明:

jmp dword ptr ds:[eax*4+0x474FCF] 这一条命令就是跳到不同的Handle块执行

jmp它Opcode是FF所以对应的VMOpcode=0xC

根据跳转类型判断,判断E8 E9 EA 近 段间 短跳转

例如像那种:jmp VMDispatcher就会符合条件

我们这个是else if ( DisassemblyFunction->Magic == 2 )

1、首先解析sub_4918E8函数

1、1 首先看一看sub_494F60函数

1、保存VmOpcode信息跟Displacement

2、根据大小读取

设置ModRM信息

v5->First.ModRM_mod__Or__Size = 2;

jmp dword ptr ds:[eax*4+0x474FCF] 就是这种寻址方式

1、2 SetDisassemblyFunction_Address函数解析

if ( v8->VMOpcode == 1 || (result = v8->VMOpcode - 3, v8->VMOpcode == 3) )成立条件

v533->VMOpcode=1:

case 0xA8: // Test al,imm8

case 0x16u: // push ss

case 0x1Eu: // push ds

case 0x50~0x57: // 50=push rax/r8 51=push rcx/r9以此类推

case 0x68u: // push Imm32/16

等等

v533->VMOpcode=3:

case 0xC7u: // MOV R/M32,IMM32

case 0x20: // and Eb,Gb

case 0x22: // and Gb,Eb

等等

1、3 SetDisassemblyFunction_Address函数设计到的结构体如下:

2、执行依次SetDisassemblyFunction_Address标记结尾

注意这里参数2就是:0xC

5、历史遗留问题

1、保存的所有struct_DisassemblyFunction(基础)、struct_VmFunctionAddr(特殊)该如何使用,这个留到后面揭晓

2、v530 赋值的地方:(大概猜测是Rex前缀,因为没有Magic=2)

3、Magic==2满足条件(这个我没仔细跟)

VMP学习笔记之反汇编引擎学习(三)相关推荐

  1. R语言学习笔记——入门篇:第三章-图形初阶

    R语言 R语言学习笔记--入门篇:第三章-图形初阶 文章目录 R语言 一.使用图形 1.1.基础绘图函数:plot( ) 1.2.图形控制函数:dev( ) 补充--直方图函数:hist( ) 补充- ...

  2. 阿里云学习笔记——设置规则引擎(2)

    标题阿里云学习笔记--设置规则引擎(2) 下面是我自己作为学习笔记分享,大神勿喷,如有叙述错误的地方欢迎指正. 1.定义Topic 定义了p_data和s_data 2.创建规则引擎,这里创建了APP ...

  3. 机器人学中的状态估计学习笔记(二)第三章线性高斯系统的状态估计

    机器人学中的状态估计学习笔记(二)第三章线性高斯系统的状态估计 3.1 离散时间的批量估计问题 3.1.1 问题定义 3.1.2 最大后验估计 3.1.3 贝叶斯推断 3.1.4 存在性.唯一性与能观 ...

  4. oracle 百万记录 cache,学习笔记:通过案例深入学习In-Memory Database Cache 总结配置过程...

    天萃荷净 详细记录关于In-Memory Database Cache配置方法与使用案例 一.Oracle数据库创建相关用户和权限 1.创建timesten用户 store information a ...

  5. Hadoop学习笔记—15.HBase框架学习(基础知识篇)

    Hadoop学习笔记-15.HBase框架学习(基础知识篇) HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase ...

  6. Hadoop学习笔记—16.Pig框架学习

    Hadoop学习笔记-16.Pig框架学习 一.关于Pig:别以为猪不能干活 1.1 Pig的简介 Pig是一个基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin, ...

  7. 学习笔记之——基于深度学习的图像超分辨率重建

    最近开展图像超分辨率( Image Super Resolution)方面的研究,做了一些列的调研,并结合本人的理解总结成本博文~(本博文仅用于本人的学习笔记,不做商业用途) 本博文涉及的paper已 ...

  8. 梅科尔工作室-Django学习笔记(二次学习)(3)

    本次学习的是如何用django实现前端鸿蒙OS登录 下面介绍一下本次的操作过程. 1.首先创立MySQL数据并将数据库导入到django当中 其中:导入数据库的操作: 2.配置urls 对应新建的pe ...

  9. 【学习笔记】Pytorch深度学习—Batch Normalization

    [学习笔记]Pytorch深度学习-Batch Normalization Batch Normalization概念 `Batch Normalization ` `Batch Normalizat ...

最新文章

  1. 查看服务器物理内存大小,如何看服务器的物理内存大小
  2. pandas最常用的几个功能,随时翻阅就差不多弄懂了pandas的75%左右
  3. 计算机职称考试知识点,职称计算机考试复习知识点
  4. java编写正则表达式引擎_从0到1打造正则表达式执行引擎(一)
  5. java 数组的应用(一维)
  6. 广义表的存储结构算法c语言,广义表(一)
  7. dnSpy 反编译exe
  8. Android MIDI音乐播放/生成相关总结
  9. word文档如何画线条流程图_word怎么画图,如何用word制作流程图
  10. anaconda打不开怎么办
  11. 费雪分离定理的证明与评价
  12. 【SQLServer】用SQL语句更改数据库名,表名,列名
  13. excel 重复方差分析_如何在Excel中运行方差方差分析的两种方法
  14. js百度地图鼠标绘制工具条库
  15. 沙盘游戏(2017绍兴市第十五届少儿信息学竞赛复赛试题)
  16. 以太坊学习路线——(二、下)以太坊编程接口:web3.js
  17. 2. JavaScript基础实战高级
  18. Android 一种关于解决 No view found for id xxxx for fragment xxxx 问题的方案
  19. 【科普】通过西方人的姓名判断血统国籍
  20. 亚马逊的飞轮效应到底是不是真的?

热门文章

  1. 回归分析之最小平方法(符号记忆公式)
  2. linux挂载局域网存储
  3. python监控网页更新_【小白教程】Python3监控网页
  4. 设置电脑开机软件自启动的简便小方法
  5. 烟大计算机基础考试试题库,上海市高等学校计算机等级考试 一级试卷
  6. AI 资料及学习路线
  7. c语言程序设计北京交通大学答案,北京交通大学《C语言程序设计(专)》复习题A...
  8. 经纬度距离和直角坐标距离转换
  9. Python-同一个类两个函数间变量的调用
  10. Django-Xadmin的安装和应用