逆向工程实战分享

逆向工程实战分享

本文转自移动开发:http://mobilev5.github.io/2016/03/24/crack-share/

原作者:金山

逆向工程一般说来就是在没有源代码的情况下,通过一定手段分析软件结构,挖掘出有用的信息或绕过软件自身的一些限制。目前对逆向的研究主要集中在Windows, Android,Mac和iOS这几个平台,各平台的发展也参差不齐。

  • 对Windows平台的研究可以追溯到win32时代,因此目前发展比较成熟,而且拥有大量的工具和插件,比较有名的工具如ollydbg和ida pro。魔高一尺道高一丈,在逆向研究发展的火热的同时对软件的保护的研究也迅速发展起来。目前Windows下的收费软件大多数都有一定的保护措施如加壳,对逆向的研究增加了一些难度。
  • Android是一个后兴起的平台,由于拥有大量的用户,所以对Android的逆向也很成熟。Android app 逆向后是一种高层次的汇编语言,也有一些工具可将之转换为更高级的java语言,虽然有部分代码混淆,但是可以很方便的注入代码,因此逆向相对容易一些。Android逆向一般要经过反编译,dex转换,代码修改,重新打包,重新签名,运行调试这几个过程。
  • mac平台用的人更少,对之研究相对少些,不过Windows平台的技术可以借鉴,只不过逆向的工具或插件比较少,好在这个平台的大多数软件都没有壳,难度系数一般。
  • iOS未接触, 但感觉跟Mac平台的逆向差不多。

开始真正的逆向之前先逆向一个简单的程序

#include <iostream>
using namespace std;
int max(int a, int b) {
       // return a > b ? a : b;
	if (a > b)
           return a;
	else
	   return b;
}
int main() {
	int result = max(56, 32);
	cout << "Result: " << result;
	return 0;
}

未优化编译并逆向后的主要代码如下(在右侧增加了一些注释):

__Z3maxii:        // max(int, int)    ; have 8B on stack or two vars
00000001000010d0         push       rbp         ; XREF=0x1000000d0, _main+25
00000001000010d1         mov        rbp, rsp
00000001000010d4         mov        dword [ss:rbp+var_8], edi ; assign first var
00000001000010d7         mov        dword [ss:rbp+var_C], esi ; assign second var
00000001000010da         mov        esi, dword [ss:rbp+var_8] ; stack: rbp, rsi
00000001000010dd         cmp        esi, dword [ss:rbp+var_C]
00000001000010e0         jle        0x1000010f1 ; >=

00000001000010e6         mov        eax, dword [ss:rbp+var_8]
00000001000010e9         mov        dword [ss:rbp+var_4], eax
00000001000010ec         jmp        0x1000010f7

00000001000010f1         mov        eax, dword [ss:rbp+var_C] ; XREF=__Z3maxii+16
00000001000010f4         mov        dword [ss:rbp+var_4], eax

00000001000010f7         mov        eax, dword [ss:rbp+var_4] ; XREF=__Z3maxii+28
00000001000010fa         pop        rbp
00000001000010fb         ret

_main:
0000000100001100         push       rbp
0000000100001101         mov        rbp, rsp
0000000100001104         sub        rsp, 0x10   ; alloc some memory on stack
0000000100001108         mov        edi, 0x38   ; argument #1 for method __Z3maxii
000000010000110d         mov        esi, 0x20   ; argument #2 for method __Z3maxii
0000000100001112         mov        dword [ss:rbp+var_4], 0x0 ; init a var with 0
0000000100001119         call       __Z3maxii   ; max(int, int) ; result assigned to eax
000000010000111e         mov        rdi, qword [ds:imp___got___ZNSt3__14coutE] ; load object(cout) address
0000000100001125         lea        rsi, qword [ds:0x100001f3c]  ; "Result: "
000000010000112c         mov        dword [ss:rbp+var_8], eax ; max result assign to 2th var
000000010000112f         call       imp___stubs___ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<< <std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*)
0000000100001134         mov        esi, dword [ss:rbp+var_8]
0000000100001137         mov        rdi, rax ; eax != rdi, cout object has changed
000000010000113a         call       imp___stubs___ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEi ; std::__1::basic_ostream<char, std::__1::char_traits<char> >::operator<<(int)
000000010000113f         xor        esi, esi ; reset
0000000100001141         mov        qword [ss:rbp+var_10], rax ; assign result(output stream) to  last var
0000000100001145         mov        eax, esi
0000000100001147         add        rsp, 0x10 ; balance stack
000000010000114b         pop        rbp       ; restore rbp
000000010000114c         ret

理解上面的代码需要注意一些调用规定,上面的代码使用的fastcall调用约定。

  • 调用约定

    • stdcall 参数从右向左压入堆栈;函数自身平衡堆栈;
    • cdecl 参数首先由有向左压入堆栈;调用者负责平衡堆栈
    • fastcall 使用寄存器传递参数

实战Reveal Download from offical website

本次破解使用的reveal版本是1.6.3(5790),也是目前的最新版。由于编写一个注册机的难度较高,本次破解只是针对打补丁的方式,想挑战的话可以尝试编写一个注册机。

工具

工欲善其事,必先利其器,mac下的破解工具主要有俩个,一个是hopper,另外一个是ida pro。本次破解使用hopper,这个软件更容易上手,注意需要装额外的调试工具,也可从官网下载到。

破解流程

方法一

  1. 直接打开Reveal, 复制提示的字符串Your
    free trial of Reveal has expire
    ,也可能是其它的,取决于你的reveal是否过期
  2. 使用Hopper加载Reveal
  3. 搜索前面复制的字符串Your
    free trial of Reveal has expire
    ,跳到引用该字符串的地方,这时会跳到[IBATrialModeReminderWindowController
    trialExpiresTitle]
    ·函数中间的某个地方,查找函数调用的对照,只要在根源处注释掉即可达到破解的目的
  4. 继续查找引用或调用这个函数·trialExpiresTitle·的地方,没有找到。换个思路,搜索字符串IBATrialModeReminderWindowController,这是会调到[IBATrialModeReminderWindowController
    controller]
    函数里面
  5. 继续向上查找调用该函数[IBATrialModeReminderWindowController
    controller]
    的地方,会跟进这个函数[IBATrialModeReminderPresenter
    showTrialModeSheetForWindow:]
  6. 继续向上查找,会进入[IBATrialModeReminderPresenter
    presentTrialModeReminderIfNecessaryForWindow:]
    ·这个函数,观察如下的代码,已经定位到我们想要的地方。
000000010007f306         mov        r14, rax
000000010007f309         mov        rsi, qword [ds:0x1001b3150]                 ; @selector(shouldShowTrialModeSheet), argument "selector" for method imp___got__objc_msgSend
000000010007f310         mov        rdi, rbx
000000010007f313         call       qword [ds:imp___got__objc_msgSend]
000000010007f319         test       al, al
000000010007f31b         je         0x10007f330

000000010007f31d         mov        rsi, qword [ds:0x1001b3158]                 ; @selector(showTrialModeSheetForWindow:), argument "selector" for method imp___got__objc_msgSend
000000010007f324         mov        rdi, rbx                                    ; argument "instance" for method imp___got__objc_msgSend
000000010007f327         mov        rdx, r14
000000010007f32a         call       qword [ds:imp___got__objc_msgSend]

000000010007f330         mov        rdi, r14                                    ; argument "instance" for method imp___got__objc_release, XREF=-[IBATrialModeReminderPresenter presentTrialModeReminderIfNecessaryForWindow:]+40
000000010007f333         pop        rbx
000000010007f334         pop        r14
000000010007f336         pop        rbp
000000010007f337         jmp        qword [ds:imp___got__objc_release]
  1. 注意地址000000010007f31b处的代码je
    0x10007f330
    ,如果不跳转回执行下面的代码就会显示提示对话框,因此把条件取反,或者无条件跳转改成jmp
    je 0x10007f330
    即可

方法二

如果觉得上面步骤繁琐的话,其实还有更简单的方法,按照一般的编程思维,一般都会写一个shouldShow…的方法来显示提示对话框,所以直接搜索字符串·shouldShow·,调到这个函数[IBATrialModeReminderPresenter
shouldShowTrialModeSheet]
,这个函数的代码如下:

-[IBATrialModeReminderPresenter shouldShowTrialModeSheet]:
000000010007fde3         push       rbp                                         ; Objective C Implementation defined at 0x10018dc40 (instance)
...
...
000000010007fdf1         mov        r15, rdi
000000010007fdf4         call       sub_10007e91a
000000010007fdf9         test       al, al
000000010007fdfb         jne        0x10007fe06

000000010007fdfd         call       sub_10007e95e
000000010007fe02         test       al, al
000000010007fe04         je         0x10007fe1a

000000010007fe06         xor        ebx, ebx                                    ; XREF=-[IBATrialModeReminderPresenter shouldShowTrialModeSheet]+24

000000010007fe08         movzx      eax, bl
...
...
000000010007fe19         ret

觉得汇编不好理解不直观的话,可以来点黑科技,看自动生成的高级语言代码:

    char -[IBATrialModeReminderPresenter shouldShowTrialModeSheet](void * self, void * _cmd) {
    r15 = self;
    if ((sub_10007e91a() != 0x0) && (sub_10007e95e() == 0x0)) {
            r14 = [[NSDate date] retain];
            r13 = [[[r15 class] lastPresentationDateTime] retain];
            [r13 release];
            rbx = 0x1;
            if (r13 != 0x0) {
                    [r14 timeIntervalSinceReferenceDate];
                    var_30 = intrinsic_movsd(var_30, xmm0);
							...
							...
                    COND = xmm1 > 0x0;
                    rbx = COND ? 0x1 : 0x0;
                    [r13 release];
            }
            [r14 release];
    }
    else {
            rbx = 0x0;
    }
    rax = rbx & 0xff;
    return rax;
}

仔细分析代码,发现两处关键代码:

000000010007fdfb         jne        0x10007fe06
000000010007fe04         je         0x10007fe1a

所以只需要把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级下的调试器调试。可以有效阻止动态调试。

时间: 2025-01-01 03:06:00

逆向工程实战分享的相关文章

UEditor实战分享(三)常用方法

1.初始化 1. 1 创建basic_common.html文件 在Demo目录下创建 basic_common.html 文件,填入下面的html代码,初始化UEditor. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title&g

UEditor实战分享(二)定制

UEditor提供了三种版本:开发板.Mini版.UBuilder版,其中UBuilder版是支持用户定制功能,UBuilder主要为开发者定制一个最精简的编辑器,故在下载包中不包含开发源码.代码示例,开发合并工具等.详情请关注UBuilder版本. UEditor实战分享(二)定制

逆向工程实战——互动出版网

这篇是计算机类的优质预售推荐>>>><逆向工程实战> 逆向工程领域先驱Rolf Rolles审校并鼎力推荐:包含针对真实病毒和后门程序的练习和实验 编辑推荐 探索独特的逆向工程系统化方法,包含对真实恶意软件的分析 覆盖三个最流行的处理器架构(x86.x64和ARM) 提供针对真实后门程序的综合练习 讲解复杂的代码混淆技术 探索高级调试技术,实现逆向工程过程的自动化和高效化 内容简介 本书是一本涵盖x86.x64 和ARM 操作系统的逆向工程类图书,由浅入深地讲解了包括W

UEditor实战分享(一)入门

UEditor 介绍 UEditor 是由百度「FEX前端研发团队」开发的所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码. 1 入门体验 1.1 下载编辑器 到官网下载 UEditor 最新版:[官网地址] 1.2 创建basic_config文件 解压下载的包,在解压后的目录创建一个目录为Demo,并在Demo目录下创建 basic_config.html 文件,填入下面的html代码 1 <!DOCTYPE HTML PUBLI

Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式百度云实战分享

muke慕课实战课程分享QQ313675301 新增课程: Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式百度云实战分享 后端开发: 1.高级java软件架构师实战培训视频教程2.大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分布式电商项目视频教程3.Spark Streaming实时流处理项目实战4.Java校招面试 Google面试官亲授5.Java开发企业级权限管理系统6.Java大牛 带你从0到上线开发企业级电商项目7.Java

实战分享:如何借力贴吧平台吸引精准粉丝(借力网)

相信大家看到这个标题,第一眼,一定会认为是标题党,毕竟网络这类文章太多,多数都是标题党,就算真正有用的也少之又少,分享给大家的要么已经过期,要么没有教具体的方法,这类的文章,不看也罢,而宅男,这篇文章,会给大家一步步的操作,实战教您如何引流,如果此时,您依然抱有这个想法,首先恭喜您,一定会失去贴台平台引流的方法和技巧,因为在这里会进行一步步实操,教大家如何去操作,此时不学,更待何事,如果被对手学去,可谓后悔莫及. 实战分享:如何借力贴吧平台吸引精准粉丝 经验心得 第1张 众所周知,很多引流技巧,

世界杯百T级CDN智能流量调度系统的实战分享

摘要: 在刚刚落幕的重庆云栖上,阿里云高级技术专家仔晟为现场观众带来议题<百T级CDN智能流量调度系统的实战分享>,重点介绍了在世界杯直播业务场景之下,阿里云CDN的产品架构.技术方案与客户实践. 在刚刚落幕的重庆云栖上,阿里云高级技术专家曾福华为现场观众带来议题<百T级CDN智能流量调度系统的实战分享>,重点介绍了在世界杯直播业务场景之下,阿里云CDN的产品架构.技术方案与客户实践. 曾福华老师的分享从CDN系统相关介绍.智能调度产品.世界杯场景优化三个方面展开. CDN系统相关

nRF24L01+组网方式及防撞(防冲突)机制的实战分享

利用多个nRF24L01+模块组网通信的实现方式 这里讨论的组网方式,不包含使用6个通道实现的多对1通信方式,因其只限于6个发送端,局限性很大,可以附加其他技术实现更好的组网,暂时这里不讨论.这里分享的是所有nRF24L01+模块都使用通道0,实现的数量远超过6个的组网方式. 经过实战总结,可以实用到落地项目的有轮询方式.时分方式.自主避让方式等几种常用的组网方式,下面会逐一讲解实现原理. 防撞(防冲突)机制的实现原理 其实无论使用那种方式,都会涉及到防止冲突,也就是防止该信道出现多个发射信号冲

nRF24L01+不能接收或接收偶尔异常等问题实战分享

nRF24L01+接收异常问题综述 在调试nRF24L01+无线收发模块的时候,最具标志性的环节就是在接收端可以收到数据.在实际应用调试中,会出现很多意想不到的情况,造成nRF24L01+模块接收端无法收到发送端发出的数据. 根据以往对nRF24L01+模块的N多次调试的经验,总结大致可以分为如下几种情况: 现象1:一次也收不到发送端发送的数据 现象2:只能在发送端或接收端重新上电的时候收到一次 现象3:偶尔在发送完数据转为接收模式后就不能接收了 现象4:大功率带PA的模块工作一段时间就不能接收