iOS逆向开发(4):注入目标函数 | iOSOpenDev | MSHookFunction

从获得APP的所有类声明,到锁定目标类与函数,现在是时候注入函数了。

所谓“注入函数”,小程的意思是让APP执行到小程写的代码中,跟“钩子”的概念一致。小程把个叫作iOS上的hook的技术。

本文介绍iOS注入函数的办法。

在借助框架之前,先介绍一个简单的注入办法,你可以“感性”地认识到“动态绑定”所带来的注入。


(一)动态绑定的一个示例

(1)锁定注入点

随便找一个APP,classdump拿到所有类的结构信息。

比如,“微信”有一个类是这样声明的:
viewcontroller的继承

这个类继承于UIViewController,也就是有viewDidLoad这个消息处理函数。这里演示把MMUIViewController::viewDidLoad函数给替换掉,让它执行到新的函数中。

(2)写注入代码

先找一个熟悉的编辑器,创建一个文件,命名为hookwx.m,然后在里面添加这样的代码:
hookwx的代码

然后是编译的事。可以直接使用xcode来编译出来.o文件,也可以用clang来编译出来.o文件。比如,小程演示时使用的是iphone4手机,也就是armv7指令集,所以可以这样编译出obj文件:

clang -c hookwx.m -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk

再使用ld来链接成动态库(dylib):

ld -dylib -lsystem -lobjc -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/ -o hookwx.dylib hookwx.o -framework Foundation -framework UIKit -ios_version_min 6.0

以上编译链接命令的参数跟小程使用的sdk版本有关,你如果尝试的话应该选择对应的参数。

(3)拷贝dylib到DynamicLibraries

scp hookwx.dylib [email protected]:/Library/MobileSubstrate/DynamicLibraries/

这时,还要创建一个plist,来指定让哪个APP来加载这个dylib(对于ios8.0以后的系统需要指定哪个APP),具体操作参照上一篇文章--介绍reveal的使用时创建了plist,就是这个操作了。“微信”的bundleID是“com.tencent.xin”或“com.tencent.xin1”,指定让它加载这个dylib(可指定若干个bundleID)。

记得把plist文件也拷贝到DynamicLibraries目录中。

(4)验证效果

启动“微信”,使用socat观察log输出,可以看到:

Dec  2 11:22:05 810 MicroMessenger[974] <Warning>: =======in initialize=================
...
Dec  2 11:24:48 810 MicroMessenger[974] <Warning>: -------------in new_viewDidLoad----------

也就是,“微信”加载了小程写的dylib,而且也执行到新的函数中。


以上的例子,只是“感性地”知道注入的办法,而在实际使用场景,更应该借助一些成熟的可以做到注入的框架。

小程较常见的两个框架,一个叫fishhook,一个叫MobileSubstrate。

fishhook,是facebook的一个开源工具,可以在运行时修改目标函数的地址,让控制点执行到自己的代码。因为需要知道目标函数的名字,这对于c运行时库的函数来说是适用的,或者对于能定位到函数名的情况也是适用的,但对于连名字都拿不到的情况(比如只能定位到代码地址)就不适用。如果只能拿到函数的地址,那可以考虑用MobileSubstrate的MSHookFunction来做到注入。

MobileSubstrate(也叫CydiaSubstrate,以下简称为MS),最大的一个作用,是可以动态绑定新的执行函数,这个功能已经能满足我们大部分的需求。比如,MS提供的函数MSHookMessageEx,可以用来对oc代码进行hook,原理上利用了oc的runtime特性(运行时替换执行函数)。

MS提供的函数MSHookFunction,可以用来对c代码进行hook,比如很多APP在写文件时都会用到write或fwrite函数,那通过对这两个函数进行hook,就能看到写入文件的数据,可以这样写代码:
MSHookFunction示例

但直接使用MS的函数,并不是本文介绍的重点。从“实用”的角度,小程要介绍的是iOSOpenDev的使用。

(二)iOSOpenDev的使用

theos跟iOSOpenDev,都是对MS库进行封装的开发工具包,这样的工具包可以简化开发的操作。这里介绍iOSOpenDev的使用。

安装iOSOpenDev后,就可以使用xcode来完成插件的开发,或者简单地生成dylib库。

(1)安装iOSOpenDev

包装包地址:

http://iosopendev.com/download/

如果你安装成功,则不用参考小程失败的例子。

以下是小程安装失败并动手解决的例子。


安装时失败,/var/log/system.log里面记录着“安装器遇到了一个错误,导致安装失败。请联系软件制造商以获得帮助。”。

虽然安装失败,但是在/opt下面还是创建了三个目录(红框内):
iosopendev目录

在iOSOpenDevSetup/bin里面已经有一个shell脚本:iod-setup,这个是安装的脚本。

直接运行iod-setup来安装:sudo ./iod-setup base

发现总是在下载某个东西时失败,打开iod-setup来定位,发现有三个downloadGithubTarball的地方,
直接注释掉,然后手动去下载这三个东西,并拷贝到iOSOpenDev目录:

分别下载下面三个地址的zip包:
https://github.com/kokoabim/iOSOpenDev
https://github.com/kokoabim/iOSOpenDev-Xcode-Templates
https://github.com/kokoabim/iOSOpenDev-Framework-Header-Files

解压上面下载的zip包,拷贝:
sudo cp -r iosopendev-master/* /opt/iosopendev/

在iosopendev目录里面,sudo mkdir templates,然后:
sudo cp -r iosopendev-xcode-templates-master/* /opt/iosopendev/templates

在iosopendev目录里面,sudo mkdir frameworks,然后:
sudo cp -r iosopendev-framework-header-files-master/* /opt/iosopendev/frameworks

再次安装:

sudo ./iod-setup base

指定最新xcode sdk:

sudo ./iod-setup sdk -sdk iphoneos


小程还遇到另一种情况:在一台imac上,xcode8.3.2,安装包失败后,直接sudo ./iod-setup base,成功。
所以,上面不成功的情况,有可能是从github下载时网络上失败导致。

最终安装成功,表现为:

1.
~/library/developer/xcode 里面会多出
Templates/iosopendev

2. 
打开 ~/.bash_profile
会看到:
export iOSOpenDevPath=/opt/iOSOpenDev
export iOSOpenDevDevice=
export PATH=/opt/iOSOpenDev/bin:$PATH

3.
启动xcode,新建工程,多出一个“iOSOpenDev”的模板。

就算使用iOSOpenDev,也有必要安装theos,否则编译时会有提示:

Preparing to run Xcode Build Phase for Logos Processor...
Failed to locate Logos Processor. Is Theos installed? If not, see http://iphonedevwiki.net/index.php/Theos/Getting_Started.

安装theos很简单(可以安装完iOSOpenDev后,再安装theos):

brew install dpkg ldid
sudo Git clone --recursive https://github.com/theos/theos.git /opt/theos
(2)使用iOSOpenDev的示例

创建项目,iOSOpenDev -> Logos Tweak (安装后会有图标)。

在项目中,可以找到一个后缀为xm的文件,这个文件就是写代码的地方。iOSOpenDev会根据xm的内容编译到mm中(xm不是必须要有的,但xm的语法比mm中的好懂多了)。

xm文件里面的#error会提示你拷贝个libsubstrate.dylib过来。到/opt/iosopendev/lib里面把libsubstrate.dylib拉到项目的Frameworks目录。

再拉进一个UIKit.framework,因为SpringBoard在UIKit里面声明,而这个例子就是对SpringBoard进行hook。

SpringBoard是系统的组件,在启动机子时加载。

清空xm文件,写代码:
注入SpringBoard的一个例子

小程这里用的UIAlertView是旧sdk支持的,如果是新版本的sdk,应该使用新的“提示框”类。

编译,成功的话,会生成对应的动态链接库,即xx.dylib。然后是plist文件,在项目中找到xx.plist,对它进行修改,指定让哪一个APP启动时加载这个dylib。

然后,把dylib与plist拷贝到DynamicLibraries目录(小程有多次提到了)。其实,xcode可以在编译后自行拷贝到手机,只需要这样配置下项目(当然也要保证电脑可以ping到手机):

在build settings页面,查找iOSOpenDevDevice,把内容设置为IP,比如:192.168.1.101 ,让xcode知道往哪台手机安装应用。然后编译并安装到手机:Project->Build For->Profiling。

注意,编译时,目标设备哪一项,应该选择Generic iOS Device, 否则会遇到一堆错误(选择真机或模拟器都可能一堆编译错误)。

安装后可以到cydia的“已安装”中看有没有你的应用,也可以ssh到手机后查看:

dpkg -l

重启机子(killall springboard),启动时会看到弹出的alertview。


总结一下,本文内容较多,但主体是iOSOpenDev的使用,这个是注入APP的有效的工具。


hello world

猜你喜欢

转载自blog.51cto.com/13136504/2376119