一道VM的逆向所引发的符号执行思路
逆向虚拟机保护
虚拟机保护类的题目需要找到虚拟机的vm_code(字节码),各个handler,然后进一步分析虚拟机保护代码的流程。
用IDA打开程序,经分析后0x403040全局变量地址处存储的就是所有的字节码,共114个。

所有的字节码:
0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0xA7, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x84, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0xC1, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00
我们进入vm函数后发现,虚拟机的流程大致是将我们的输入flag与a1字节码数组运算后存到V4数组中,然后比较V4数组与a1字节码中的某些数据是否相等,相等则输入正确。所以我们可以先得出数组V4。

我们将v4[v8] != a1[v10 + 1] 改为 v4[v8] = a1[v10 + 1]的出正确的数组,同时记录虚拟机的执行顺序即执行字节码的顺序。最后的出V4数组与执行字节码的顺序分别为:
unsigned char v4[] = { 0X22, 0X3F, 0X34, 0X32, 0X72, 0X33, 0X18, 0XFFFFFFA7, 0X31, 0XFFFFFFF1, 0X28, 0XFFFFFF84, 0XFFFFFFC1, 0X1E, 0X7A };
unsigned char Index[100] = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114 };
将虚拟机的算法的逆过程结合V4和Index得出代码求出flag。
int __cdecl vm_operad(int *a1, int a2)
{
int result; // eax
unsigned char Str[100] = {0}; // [esp+13h] [ebp-E5h]
unsigned char v4[100] = {0x22, 0x3f, 0x34, 0x32, 0x72, 0x33, 0x18, 0xa7, 0x31, 0xf1, 0x28, 0x84, 0xc1, 0x1e, 0x7a }; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int v6; // [esp+DCh] [ebp-1Ch]
int v7; // [esp+E0h] [ebp-18h]
int v8; // [esp+E4h] [ebp-14h]
int v9; // [esp+E8h] [ebp-10h]
int v10; // [esp+ECh] [ebp-Ch]
char Index[] = {1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114};
v10 = 0x72;
v9 = 0xf;
v7 = 0xf;
v6 = 0xf;
int i = 0;
while ( 1 )
{
result = v10;
if ( sizeof(Index) - i + 1 == 0 )
return result;
i++;
switch ( a1[Index[sizeof(Index) - i]] )
{
case 1:
--v9;
--v7;
--v10;
v5 = v4[v7];
break;
case 2:
v10 -= 2;
Str[v9] = v5 - a1[v10 + 1];
break;
case 3:
v10 -= 2;
Str[v9] = v5 + LOBYTE(a1[v10 + 1]);
break;
case 4:
v10 -= 2;
Str[v9] = v5 ^ a1[v10 + 1] ;
break;
case 5:
v10 -= 2;
Str[v9] = v5 / a1[v10 + 1];
break;
case 6:
--v10;
break;
case 7:
v10 -= 2;
break;
case 8:
--v6;
--v10;
v5 = Str[v6];
break;
case 10:
--v10;
break;
case 11:
--v10;
Str[v9] = v5 + 1;
break;
case 12:
--v10;
Str[v9] = v5 - 1;
break;
default:
continue;
}
}
}
利用符号执行
符号执行
符号执行指的是用符号值来代替某些变量的真实值,用符号值来遍历程序所有的执行分支,而用真实值只能遍历一条分支。然后通过约束求解引擎来在筛选所有的分支选出符合条件的那一个,最后得出正确的输入值。
angr
angr是二进制程序分析框架,可以用来进行完成符号执行。
在此题目中我们希望程序执行到vm函数自然返回处,而不会执行到what a shame...处,这样就说明其输入正确。
vm函数自然返回处的地址为0x40175E

what a shame...处的地址为0x4016e6

所以我们可以利用angr写python符号执行脚本:
import angr #导入angr库
p = angr.Project('signal.exe',auto_load_libs=False) #创建一个Project,程序不引用任何其他导入库
st = p.factory.entry_state() #将程序加载并执行到入口处,返回其状态
sm = p.factory.simulation_manager(st) #创建一个模拟执行器
sm.explore(find=0x40175E, avoid=0x4016E6) #设置约束条件,find是程序需要执行到的地址,avoid是程序不能执行到的地址
print(sm.found[0].posix.dumps(0)) #输出结果
参考:https://www.52pojie.cn/thread-1176826-1-1.html
一道VM的逆向所引发的符号执行思路的更多相关文章
- 一道国外前端面试题引发的Coding...
刚刚看到CSDN微信公众号一篇文章,关于国外程序员面试前端遇到的一道测试题,有点意思,遂写了下代码,并记录一下~ 题目是这样的: ['Tokyo', 'London', 'Rome', 'Donlon ...
- 一道有意思的笔试题引发的对于new操作符的思考
楼主比较喜欢看一些很短但很有意思的题目,无意间又瞥到了一题,大家不妨可以一试.(原题链接猛戳这里) function Fn1() { this.name = 'peter'; return { nam ...
- 一道JS面试题所引发的"血案",透过现象寻本质,再从本质看现象
觉得本人写的不算很烂的话,可以登录关注一下我的GitHub博客,新手写东西写的不好之处,还望见谅,毕竟水平有限,写东西只为交流提高,一起学习,还望大神多加指点,指出纰漏,和提出宝贵的意见,博客会坚持写 ...
- 通过JS逆向ProtoBuf 反反爬思路分享
前言 本文意在记录,在爬虫过程中,我首次遇到Protobuf时的一系列问题和解决问题的思路. 文章编写遵循当时工作的思路,优点:非常详细,缺点:文字冗长,描述不准确 protobuf用在前后端传输,在 ...
- 【一天一道LeetCode】#57. Insert Interval
一天一道LeetCode系列 (一)题目 Given a set of non-overlapping intervals, insert a new interval into the interv ...
- 网络爬虫之记一次js逆向解密经历
1 引言 数月前写过某网站(请原谅我的掩耳盗铃)的爬虫,这两天需要重新采集一次,用的是scrapy-redis框架,本以为二次爬取可以轻松完成的,可没想到爬虫启动没几秒,出现了大堆的重试提示,心里顿时 ...
- x32下PsSetLoadImageNotifyRoutine的逆向
一丶简介 纯属兴趣爱好.特来逆向玩玩. PsSetLoadImageNotifyRoutine 是内核中用来监控模块加载.操作系统给我们提供的回调. 我们只需要填写对应的回调函数原型即可进行加监控. ...
- 「每日一题」有人上次在dy面试,面试官问我:vue数据绑定的实现原理。你说我该如何回答?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 来源:原创 一.前言 文章首发在「松宝写代码」 2020. ...
- JavaScript OOP 之「创建对象」
工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...
随机推荐
- Webpack 学习笔记(1) 开始
目录 参考资料 1. 基础设定 2. 创建一个包 3. 使用配置文件完成打包命令 4. 使用 NPM Scripts 完成打包命令 参考资料 Getting Started | Webpack web ...
- 《Selenium自动化测试实战:基于Python》之 Selenium IDE插件的安装与使用
第3章 Selenium IDE插件的安装与使用 京东:https://item.jd.com/13123910.html 当当:http://product.dangdang.com/292045 ...
- [Design Pattern With Go]设计模式-工厂模式
这次介绍的设计模式是工厂模式,这是一个比较常见的创建型模式.一般情况下,工厂模式分为三种:简单工厂.工厂方法和抽象工厂,下面慢慢举例介绍下. 简单工厂 考虑一个加密程序的应用场景,一个加密程序可能提供 ...
- 使用 Android Studio 的日志工具 Log
•Log简介 Android中的日志工具类是Log,这个类中提供了5个方法来供我们打印日志: 1. $Log.v()$ 用于打印那些最为琐碎的,意义最小的日志信息 对应级别 verbose,是 And ...
- 力扣 - 208. 实现Trie(前缀树)
目录 题目 思路 代码 复杂度分析 题目 208. 实现 Trie (前缀树) 思路 在我们生活中很多地方都用到了前缀树:自动补全,模糊匹配,九宫格打字预测等等... 虽然说用哈希表也可以实现:是否出 ...
- 多线程安全的单例模式(使用判断nullptr和call_once两种方法)
转载请注明: https://blog.csdn.net/Stephen___Qin/article/details/115583694 使用判断nullptr #include <thread ...
- Hystrix熔断原理
Netflix的开源组件Hystrix的流程: 图中流程的说明: 将远程服务调用逻辑封装进一个HystrixCommand. 对于每次服务调用可以使用同步或异步机制,对应执行execute()或que ...
- 1.设置和验证MySQL数据库的隔离级别
登录数据库 mysql -u root - p 新建用户,各启动一个事物,用于同时操作数据库表中数据 create user tom identified by 'tom'; 然后同时再用该用户启动M ...
- 自动化kolla-ansible部署ubuntu20.04+openstack-victoria之镜像制作ubuntu16.04-16
自动化kolla-ansible部署ubuntu20.04+openstack-victoria之镜像制作ubuntu16.04-16 欢迎加QQ群:1026880196 进行交流学习 制作Ope ...
- SHA256sum系列命令检测文件完整性
1 sha256sum sha256sum是一个检测文件完整性的命令,一般下载的文件都会附带一个哈希值,使用sha256sum计算下载文件的哈希值再与目标哈希值比较即可确定文件是否完整,类似的命令还有 ...