iOS注入目标函数

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

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

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

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


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

(1)锁定注入点

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

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

这个类继承于UIViewController,也就是有viewDidLoad这个消息处理函数。

小程在这里演示把MMUIViewController::viewDidLoad函数给替换掉,让它执行到新的函数中。

(2)写注入代码

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

然后是编译的事。可以直接使用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 root@192.168.1.100:/Library/MobileSubstrate/DynamicLibraries/

每个APP启动时都会载入/Library/MobileSubstrate/DynamicLibraries/ 目录下所有的动态库,除非动态库有用plist来指定只给哪些应用加载,否则所有应用都会加载。

其实,合理一点的做法是创建一个plist文件,指定只让“微信”加载这个动态链接库,读者可以参考上篇文章介绍的办法来创建plist,小程这里省掉这一步了。

(4)验证效果

启动“微信”,使用socat观察log输出,可以看到: Dec 2 11:22:05 810 MicroMessenger[974] : =======in initialize================= … Dec 2 11:24:48 810 MicroMessenger[974] : ————-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,就能看到写入文件的数据,可以这样写代码:

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

(二)iOSOpenDev的使用

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

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

(1)安装iOSOpenDev

包装包地址:

http://iosopendev.com/download/

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

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


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

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

在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在里面声明,而这个例子就是对SpringBoard进行hook。

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

清空xm文件,写代码:

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

编译,成功的话,会生成对应的动态链接库,即xx.dylib。也可以在项目中找到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的有效的工具。iOSOpenDev的安装与使用,难度系数为中。

原文发布于微信公众号 - 广州小程(gh_3e79faa8a715)

原文发表时间:2018-01-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券