大家好,投资破产,暂时不准备做逆向了,希望能找到10个人购买我的逆向分析系统源码,每个人500块(是的,你没有看错)。
我发过几个帖子,如果希望了解更多的详情请翻看以前的记录(也方便你了解实际效果)。这里我再简单介绍下:我的工具(系统)不是模拟执行,模拟执行通常只能针对某个线程、某个函数进行的,因为它是非常非常慢的,不可能用于模拟执行整个程序。也不是frida类似的stalker(虽然我用到了frida的代码,只是用于insert lib抢占入口),因为它只是效率提高了有限多,当你企图在所有线程上应用stalker的时候基本都会以崩溃结束。我的工具只是用了一种新的方法(我确实看过不少二进制翻译的论文,并没有发现完全像我这么做的,我觉得是可以发一篇论文的),我根据arm64指令的固定特点,同时操作系统未来会倾向于禁止程序自修改,这其实我们就可以通过静态重编译二进制代码达到stalker的效果,速度又快了很多(如果是自修改代码,是非常非常困难的,dynamoRIO号称他们的程序可以近乎10%-30%的损耗进行动态jit,确实大部分情况如此,但是国内某个XX壳(windows)进行了变态级别的动态自修改加载,仅仅是启动阶段就膨胀了几十亿条指令,我使用了dynamoRIO加载后整整等待了一分钟才看到了启动界面,注意,这只是一个有两个按钮一个文本框的demo程序哦,庆幸的是这种情况未来会越来越少了),如果我们就可以结合ida的分析结果进行二进制的静态翻译,因为arm64指令的特性我们几乎不会翻译错误(错误通常来自把数据当成指令,但不严重),这样我们就可以识别找到程序中所有的动态跳转指令(ret br bl ….),其中最关键的是,如果我们保持原有程序的结构,那么我们的速度就可能非常快,比stalker更快,因为如果是本程序模块内跳转(ret br blr 地址在你的当前jit程序中)那么我们就完全可以直接判断跳转地址范围,如果落在模块内就加上一个固定偏移跳转(因为你的jit指令代码区和原始代码区大小一致,只是有一个固定偏移),只需要增加10几条指令,stalker是怎么做的呢?它是采用了查表比较的方式加速,如果目标地址在表的几个缓存地址中也可以直接跳转(fast path),但是实测下来这个查表miss概率其实不低,导致整体性能某些情况下依然非常慢(slow path)。通过这种方式,其实我们就算是基本比较完美的解决了一直困扰我们的jit效率问题,但是有个小问题,就是我们跳转的时候用到了一些寄存器,跳转到目标后怎么恢复,是否需要恢复在实测中都是需要考虑的,这可能也是唯一不足的地方。
好了,解决了jit的问题,接下来就是函数跟踪和内存数据读写跟踪的问题,在dynamoRIO和stalker中是怎么做的呢,他们都是采用了hook相关指令然后跳转到你的记录函数中,这其实速度是非常非常慢的,因为首先进入hook函数就需要保存几十条指令,然后你的函数中又写一堆代码,所以最终甚至会出现速度慢100倍的情况,那么我们能否能不用函数,直接保存调用的函数和内存数据读写呢,看上去也可以,但是,如果你要从程序起始开始记录所有线程的所有相关数据,可能你遇到的最大的问题就是如何让这些数据按照线程进行保存,否则所有线程的数据都混杂在一起,这完全背离了我们的初衷。这个问题也困扰了我很久,后来我就发现了一种新的方法,不算彻底解决,但是我确实只用了10几条指令就让数据保存在了线程内存中。实测下来即使进行程序起始所有线程的堆内存(栈内存就算了,我想不会你不会想要分析这个的,除非是特定函数的)读写损耗也不超过50%。
有时候看了一些网友的回复,我自己也奇怪,我在做什么呢?我们已经有了stalker 、unidbug,我们完全可以一点点调试分析程序,甚至对于VM我们也可以人力恢复所有函数(某些逆向大v)。但是,如果你看过很多二进制翻译的论文,可以发现他们研究的却可能不是网上讨论的这些东西。我们为什么要花费这么大力气,企图跟踪记录程序所有的行为呢?但是程序是什么呢?程序不就是:输入数据→处理数据→输出数据吗?函数?不,我觉得函数是不重要的(起码不像我们想象的那么重要,我也不会尝试想要跟一些VM混淆函数死磕),当我们能看到一个软件输入了什么数据,这个数据最后流向了哪里,那么其实这个软件就已经被我们很好的理解了,你觉得呢?
好了,写完了,如果你需要购买,请加我tel:@nobody_ji