IOS逆向技术入门

目录

 

环境准备

使用USB调试iphone

ssh连接越狱iPhone

默认密码

免密登录

数据传输

静态分析篇

iOS应用程序砸壳

使用dumpdecrypted砸壳

使用frida-ios-dump砸壳(推荐使用)

Class-dump导出头文件

使用restore-symbol恢复部分Symbol

使用IDA分析可执行程序

动态调试篇

使用LLDB调试

配置debugserver

在iOS上用debugserver来attach进程

对抗反调试问题

LLDB+Python

使用IDA-Server调试

使用Frida调试

使用Objection调试

其他分析方法

BurpSuite截获网络流量

Reveal -- UI分析利器

重打包技术

附录

iPhone与CPU架构对应关系

LLDB Cheatsheet


环境准备

使用USB调试iphone

用wifi调试的时候,会觉得有些卡壳,所以,改用USB,这样速度会明显提升。使用USB连接,需要安装usbmuxd,安装以后,做端口转发即可。

ssh连接越狱iPhone

usbmuxd自带工具iproxy,iproxy可以快捷连接iPhone操作。由于Mac上只支持4位的端口号,所以需要把iPhone的默认端口22映射到Mac上,相当于建立一个Mac和iPhone的通道。

终端输入:

iproxy 25025 22

然后会自动显示如下等待连接字样

waiting for connection

在另外一个终端输入:

ssh -p 25025 [email protected]

参考:SSH连接越狱iPhone

 

下面的nohup命令是让iproxy在后台运行,这样,可以避免起多个terminal:

nohup iproxy 25025 22 > /dev/null 2>&1 &
ssh root@localhost -p 25025

默认密码

越狱以后的默认密码:alpine

免密登录

在/var/root/.ssh/authorized_keys文件中添加本机的id_rsa.pub内容,可以实现免密ssh登录iOS。

 

数据传输

scp -P 25025 image.jpg root@localhost:/var/mobile/Containers/Data/Application/498DC197-C1C2-46B0-A828-3AF1E9C36CE1/tmp/

静态分析篇

要对一个iOS应用进行分析,尤其是有壳的应用程序,需要先砸壳。下面就从砸壳开始说起,如果没有壳,也不影响,可以将应用程序dump成IPA,方便进一步分析。

 

iOS应用程序砸壳

使用dumpdecrypted砸壳

下面就介绍砸壳的过程:

  • 下载和编译下面的dumpdecrypted,编译完成以后,会生成dumpdecrypted.dylib

参考:https://github.com/stefanesser/dumpdecrypted

  • 将dumpdecrypted.dylib拷贝到当前权限可以写的目录下(看到不少文章写要放在对应的document目录,应该是对于没有越狱的iphone,有权限限制的问题)
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Applications/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AAA.app/AAA
  • 执行完成以后,就会发现有一个AAA.decrypted的程序,这样,就解决加壳的问题了。

 

使用frida-ios-dump砸壳(推荐使用)

除了上面的方法,还有使用frida-ios-dump的一键砸壳,可以参考:

http://www.alonemonkey.com/2018/01/30/frida-ios-dump/

这种方法对于动态库(dylib)加壳是非常有用的,可以方便处理。默认dump.py使用的事2222端口,所以,需要将2222映射到IOS的22端口上。

nohup iproxy 2222 22 > /dev/null 2>&1 &

frida-ios-dump之前的版本,在Frida 12.5.0以后,存在兼容性问题,不过,后面作者修改了code,已经解决了。所以,如果你的Frida版本高于12.5.0,一定要用最新版的frida-ios-dump。

 

# 列出iOS设备上的应用程序
python dump.py -l

 PID  Name                  Identifier
----  --------------------  ---------------------------------
 672  微信                    com.tencent.xin
1250  绿伞身份                  com.antgroup.nacIphoneClient
1180  设置                    com.apple.Preferences
 670  邮件                    com.apple.mobilemail
1108  钉钉                    com.laiwang.DingTalk

# 使用Name或者Identifier,进行砸壳
python dump.py com.tencent.xin -o=wechat.ipa

 

Class-dump导出头文件

通过Class-dump工具可以从应用程序文件中导出相应的头文件,这对于逆向而言,是非常重要的资源,毕竟有些code可以参考,要不直接在IDA里逆向要来的快。

下面是class-dump的命令行参数,支持不同的arch,具体可以参考下面的说明。

class-dump 3.5 (64 bit) (Debug version compiled Sep 17 2017 16:24:48)
Usage: class-dump [options] <mach-o-file>

  where options are:
        -a             show instance variable offsets
        -A             show implementation addresses
        --arch <arch>  choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, armv6, armv7, armv7s, arm64)
        -C <regex>     only display classes matching regular expression
        -f <str>       find string in method name
        -H             generate header files in current directory, or directory specified with -o
        -I             sort classes, categories, and protocols by inheritance (overrides -s)
        -o <dir>       output directory used for -H
        -r             recursively expand frameworks and fixed VM shared libraries
        -s             sort classes and categories by name
        -S             sort methods by name
        -t             suppress header in output, for testing
        --list-arches  list the arches in the file, then exit
        --sdk-ios      specify iOS SDK version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS<version>.sdk
                       or /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS<version>.sdk)
        --sdk-mac      specify Mac OS X version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX<version>.sdk
                       or /Developer/SDKs/MacOSX<version>.sdk)
        --sdk-root     specify the full SDK root path (or use --sdk-ios/--sdk-mac for a shortcut)

这里,以微信为例,将微信的头文件导出到wechat-7.0.4文件夹中。

$ class-dump -H -o ~/Desktop/wechat-7.0.4/ WeChat

 

使用restore-symbol恢复部分Symbol

iOS应用程序可以恢复一部分符号,以AlipayWallet为例。

# 检查AlipayWallet是不是fat file
lipo -info AlipayWallet 
# 瘦身
lipo AlipayWallet -thin arm64 -output AlipayWallet.arm64 
# 恢复符号
restore-symbol AlipayWallet.arm64 -o AlipayWallet.arm64.symbol
# 使用ida_search_block.py生成json file
# https://github.com/tobefuturer/restore-symbol/blob/master/search_oc_block/ida_search_block.py
# 恢复block symbol
restore-symbol AlipayWallet.symbol -o AlipayWallet.symbol.2 -j AlipayWallet_block_symbol.json
# 将AlipayWallet.symbol.2拷贝到Payload/AlipayWallet.app/AlipayWallet
cp AlipayWallet.symbol.2 Payload/AlipayWallet.app/AlipayWallet
# 获得权限文件
ldid -e Payload/AlipayWallet.app/AlipayWallet > ~/workspace/alipay-ios8/AlipayWalletEntitlements.plist
# 签名
codesign -f -s "iPhone Developer: xxxxx" --entitlement ~/workspace/alipay-ios8/AlipayWalletEntitlements.plist Payload/AlipayWallet.app/AlipayWallet
# 压缩打包成ipa,用iTools安装到手机上

细节可以参考:

http://www.cocoachina.com/cms/wap.php?action=article&id=23921

http://blog.imjun.net/posts/restore-symbol-of-iOS-app/

 

使用IDA分析可执行程序

这个毋庸多说,直接找对应的可执行程序,拷贝到mac上,然后,用IDA打开就可以了。

 

动态调试篇

使用LLDB调试

配置debugserver

默认连接xcode给ios添加的debugserver是支持多个CPU架构的,需要根据自己的机型选择合适的CPU架构,这些信息可以参考下面的iPhone与CPU架构对应关系

目前个人使用的是iphone5s,所以,保留arm64的平台。

从ios上将debugserver拷贝到mac上,然后,用下面的命令给debugserver瘦身。

lipo -thin arm64 ./debugserver -output ./debugserver
给debugserver添加task_for_pid权限,需要先下载ent.xml, 然后,用下面的命令:
ldid -Sent.xml debugserver

然后,将瘦身的debugserver再拷贝到iphone的/user/bin目录下,可以直接执行

 

在iOS上用debugserver来attach进程

 

调试器常用的两种方式,一种是attach process,另外一种是start process,下面分别介绍:

attach process

启动debugserver,并attach SpringBoard,开放端口25026给LLDB客户端连接

debugserver *:25026 -a "SpringBoard"

在MacOS的终端上,先做端口转发,将本地25026端口转发到iphone的25026端口上

nohup iproxy 25026 25026 > /dev/null 2>&1 &

在LLDB中用下面的命令连接:

process connect connect://localhost:25026

参考:iOS应用逆向工程

 

start process

debugserver -x backboard *:25026 path-to-application
网上有些说法是用posix代替backboard,个人实验以后,发现下面的情况:
1) backboard可以看到用户界面
2)posix看不到UI
具体使用哪种,视情况而定

 

对抗反调试问题

对于有反调试保护的APP,需要绕开反调试,目前反调试的方法主要还是以后ptrace,所以,只要跳过ptrace即可。

实现方法多样,可以是调试器的command,也可以是script,也可以自己编写tweak。

用command的话,下面的命令可供参考:

# set breakpoint at ptrace
b ptrace

# continue and trigger breakpoint
c

# modify $pc to return address
register write pc `$lr`

# continue to run
c

更多细节可以参考https://segmentfault.com/a/1190000012199291

也可以使用我写的lldb script: https://github.com/michaelpdu/lldb_scripts/blob/master/aadebug.py

 

LLDB+Python

LLD内置Python解释器,这样就可以做很多事了。

详细可以参考官方文档:https://lldb.llvm.org/python-reference.html

 

使用IDA-Server调试

暂时还没有玩过,以后玩过了再补上。

 

使用Frida调试

Frida是跨平台插桩工具,支持多种平台,iOS和Android都支持,具体的内容可以参考官网:https://www.frida.re/

Frida可以直接使用JavaScript来hook iOS应用的函数,最方便的是可以做到在Objective-C++语言级别上的函数调用。

下面的代码片段是通过Frida的ObjC.classes来完成应用程序中的函数调用,方便探测对应函数的结果是什么

[iPhone::PID::843]-> var rootPath = ObjC.classes.APDataCenter["+ preferencesRootPath"]()
[iPhone::PID::843]-> console.log(rootPath)
/var/mobile/Containers/Data/Application/AB8040C3-FCDF-4E01-98E1-9EC3414C8867/Documents/Preferences

[iPhone::PID::843]-> var dataCenter = ObjC.classes.APDataCenter["+ defaultDataCenter"]()
[iPhone::PID::843]-> var commonPerf = dataCenter["- commonPreferences"]()
[iPhone::PID::843]-> console.log(commonPerf.path())
/var/mobile/Containers/Data/Application/AB8040C3-FCDF-4E01-98E1-9EC3414C8867/Documents/Preferences/9c7c560b34de477b.db

[iPhone::PID::843]-> var userPerf = dataCenter["- userPreferences"]()
[iPhone::PID::843]-> console.log(userPerf.path())
/var/mobile/Containers/Data/Application/AB8040C3-FCDF-4E01-98E1-9EC3414C8867/Documents/Preferences/eacb882264825e7d.db

[iPhone::PID::843]-> var lruPerf = ObjC.classes.APLRUDiskCache["+ sharedPreferences"]()
[iPhone::PID::843]-> console.log(lruPerf.path())
/var/mobile/Containers/Data/Application/AB8040C3-FCDF-4E01-98E1-9EC3414C8867/Documents/Preferences/LRU.db

 

使用Objection调试

Objection是基于Frida做的一个高层API,可以很方便地Hook class,这对动态分析非常有帮助。

可以使用下面的命令进入objection的交互界面,这样,就可以利用其强大的功能了。

objection --gadget xxx explore

 

其他分析方法

 

BurpSuite截获网络流量

参考官方网站的介绍:

https://support.portswigger.net/customer/portal/articles/1841108-configuring-an-ios-device-to-work-with-burp

 

流量中,可能会有些被gzip压缩,需要安装一个插件:

Extender --> BApp Store --> Decompressor

 

Reveal -- UI分析利器

对于大型的客户端程序,里面包含的ViewController数以千计,想要快速地定位到程序逻辑,从UI入手最简单,这是,就需要Reveal的帮助。具体使用,可以参考:

http://wiki.jikexueyuan.com/project/ios-security-defense/reveal.html

 

其中,安装Reveal以后,找不到libReveal.dylib,可以将RevealServer重命名为libReveal.dylib,拷贝过去即可

scp -P 25025 /Applications/Reveal.app//Contents/SharedSupport/iOS-Libraries/RevealServer.framework/RevealServer root@localhost:/Library/MobileSubstrate/DynamicLibraries/libReveal.dylib

修改libReveal.plist,将要分析的APP bundles添加到filter中。

{   
    Filter = {  
         Bundles = ("com.apple.AppStore");   
    };   
}

重启设备(或者killall SpringBoard),然后,就可以看到相应的应用程序了。

这篇文章上说的方法:https://www.jianshu.com/p/45dc72ec9499

是直接使用Cydia,安装Reveal Loader(新版本可以用Reveal2Loader),不过,这里封装的Reveal版本未必与当前机器上安装的版本一致,如果较低的话,会出现下面这样的错误。

 

重打包技术

使用MonkeyDev中的MonkeyApp,可以简单地完成应用程序重打包的目的。具体可以参考下面wiki:

https://github.com/AloneMonkey/MonkeyDev/wiki/%E9%9D%9E%E8%B6%8A%E7%8B%B1App%E9%9B%86%E6%88%90

(1)创建MonkeyApp

(2)使用frida-ios-dump对应用程序砸壳以后,会产生一个IPA文件,将其copy到TargetApp目录中。

(3)在build settings的最下面User-Defined选项中,有几个比较重要,这里,简单介绍一下。

  • MONKEYDEV_CLASS_DUMP: 就是上面class-dump的功能
  • MONKEYDEV_DEFAULT_BUNDLEID: 使用默认的bundle ID,这个可以设置为YES
  • MONKEYDEV_RESTORE_SYMBOL: restore-symbol的功能

 

附录

iPhone与CPU架构对应关系

armv6: iPhone、iPhone 2、iPhone 3G、iPod Touch(第一代)、iPod Touch(第二代)       

armv7: iPhone 3Gs、iPhone 4、iPhone 4s、iPad、iPad 2

armv7s: iPhone 5、iPhone 5c (静态库只要支持了armv7,就可以在armv7s的架构上运行)

arm64(注:无armv64): iPhone 5s、iPhone 6、iPhone 6 Plus、iPhone 6s、iPhone 6s Plus、 iPhone 7 、iPhone 7 Plus、iPad Air、iPad Air2、iPad mini2、iPad mini3、iPad mini4、iPad Pro

 

LLDB Cheatsheet

LLDB Cheatsheet

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章