逆向工程实战分享
逆向工程一般说来就是在没有源代码的情况下,通过一定手段分析软件结构,挖掘出有用的信息或绕过软件自身的一些限制。目前对逆向的研究主要集中在Windows, Android,Mac和iOS这几个平台,各平台的发展也参差不齐。
- 对Windows平台的研究可以追溯到win32时代,因此目前发展比较成熟,而且拥有大量的工具和插件,比较有名的工具如ollydbg和ida pro。魔高一尺道高一丈,在逆向研究发展的火热的同时对软件的保护的研究也迅速发展起来。目前Windows下的收费软件大多数都有一定的保护措施如加壳,对逆向的研究增加了一些难度。
- Android是一个后兴起的平台,由于拥有大量的用户,所以对Android的逆向也很成熟。Android app 逆向后是一种高层次的汇编语言,也有一些工具可将之转换为更高级的java语言,虽然有部分代码混淆,但是可以很方便的注入代码,因此逆向相对容易一些。Android逆向一般要经过反编译,dex转换,代码修改,重新打包,重新签名,运行调试这几个过程。
- mac平台用的人更少,对之研究相对少些,不过Windows平台的技术可以借鉴,只不过逆向的工具或插件比较少,好在这个平台的大多数软件都没有壳,难度系数一般。
- iOS未接触, 但感觉跟Mac平台的逆向差不多
开始真正的逆向之前先逆向一个简单的程序
1 |
|
未优化编译并逆向后的主要代码如下(在右侧增加了一些注释):
1 | __Z3maxii: // max(int, int) ; have 8B on stack or two vars |
理解上面的代码需要注意一些调用规定,上面的代码使用的fastcall调用约定
- 调用约定
- stdcall 参数从右向左压入堆栈;函数自身平衡堆栈;
- cdecl 参数首先由有向左压入堆栈;调用者负责平衡堆栈
- fastcall 使用寄存器传递参数
实战Reveal Download from offical website
本次破解使用的reveal版本是1.6.3(5790),也是目前的最新版。由于编写一个注册机的难度较高,本次破解只是针对打补丁的方式,想挑战的话可以尝试编写一个注册机。
工具
工欲善其事,必先利其器,mac下的破解工具主要有俩个,一个是hopper,另外一个是ida pro。本次破解使用hopper,这个软件更容易上手,注意需要装额外的调试工具,也可从官网下载到。
破解流程
方法一
- 直接打开Reveal, 复制提示的字符串
Your free trial of Reveal has expire
,也可能是其它的,取决于你的reveal是否过期 - 使用Hopper加载Reveal,点击下载
- 搜索前面复制的字符串
Your free trial of Reveal has expire
,跳到引用该字符串的地方,这时会跳到[IBATrialModeReminderWindowController trialExpiresTitle]
·函数中间的某个地方,查找函数调用的对照,只要在根源处注释掉即可达到破解的目的 - 继续查找引用或调用这个函数·trialExpiresTitle·的地方,没有找到。换个思路,搜索字符串
IBATrialModeReminderWindowController
,这是会调到[IBATrialModeReminderWindowController controller]
函数里面 - 继续向上查找调用该函数
[IBATrialModeReminderWindowController controller]
的地方,会跟进这个函数[IBATrialModeReminderPresenter showTrialModeSheetForWindow:]
- 继续向上查找,会进入
[IBATrialModeReminderPresenter presentTrialModeReminderIfNecessaryForWindow:]
·这个函数,观察如下的代码,已经定位到我们想要的地方
1 | 000000010007f306 mov r14, rax |
- 注意地址000000010007f31b处的代码
je 0x10007f330
,如果不跳转回执行下面的代码就会显示提示对话框,因此把条件取反,或者无条件跳转改成jmp je 0x10007f330
即可
方法二
如果觉得上面步骤繁琐的话,其实还有更简单的方法,按照一般的编程思维,一般都会写一个shouldShow…的方法来显示提示对话框,所以直接搜索字符串·shouldShow·,调到这个函数[IBATrialModeReminderPresenter shouldShowTrialModeSheet]
,这个函数的代码如下:
1 | -[IBATrialModeReminderPresenter shouldShowTrialModeSheet]: |
觉得汇编不好理解不直观的话,可以来点黑科技,看自动生成的高级语言代码:
1 | char -[IBATrialModeReminderPresenter shouldShowTrialModeSheet](void * self, void * _cmd) { |
仔细分析代码,发现两处关键代码:
1 | 000000010007fdfb jne 0x10007fe06 |
所以只需要把000000010007fdfb地址处的代码改为jmp 0x10007fe1a
即可
以上的操作都是在内存中修改的,关闭后重新打开还是无法使用,执行File -> Produce New Executable file, 这是会提示你签名无效,是否移除签名,选择否,(如果选择是的话,每次启动都会有个提示很烦人的),替换原来的可执行文件,重新启动Reveal,会提示This copy of Reveal is damaged
,解决方法同上,不在这里赘述。
安全防范
- Web请求加入
Authorization header
REST服务的web请求中加入Authorization header验证,对资源进行校验。可有效阻止爬虫。 - 代码混淆(Android)
- 花指令
伪装其他编译器的特征码,干扰反汇编,绕过杀毒软件。 - 加壳
在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作。常见的壳分为压缩壳和加密壳,加壳的软件直接破解难度很大需要先进行脱壳处理。 - 加密, 代码签名
一定程度上阻止逆向。 - 调试检测
用ring3级下的调试器对可执行程序进行调试时,调试器会把被调试的可执行程序作为一个子线程进行跟踪.这时被调试的可执行程序的PEB结构偏移0x02处的BeingDebugged的值为1,如果可执行程序未被调试,则值为0,所以可以利用这个值来检测程序是否被ring3级下的调试器调试。可以有效阻止动态调试。