从获得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/

这时,还要创建一个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,就能看到写入文件的数据,可以这样写代码:

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

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

清空xm文件,写代码:

小程这里用的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的有效的工具。


iOS逆向开发(4):注入目标函数 | fishhook | MobileSubstrate | MSHookFunction | iOSOpenDev的更多相关文章

  1. iOS逆向开发(8):微信自动添加好友

    这一次,小程演示怎么让一个APP自动地运行,从而代替手工的操作.同样以"微信"以例,实现在一个微信群里面,对所有的成员,自动地一个一个地发出添加好友的请求. 知识点还是之前介绍的东 ...

  2. iOS逆向开发(1):基础工具 | ssh | scp | socat

    小白:小程,我一直想问,什么是逆向来着?是逆向行驶吗? 小程:理解为逆向行驶也没错.一般的项目是从无到有,而逆向是从已有的状态入手,分析出已有的流程与结构的手段. iOS上的逆向开发,是一件有趣的事情 ...

  3. iOS逆向开发(6):微信伪造位置

    仍然以微信为例,实战地练习一下使用Reveal.iOSOpenDev等工具注入APP的流程,积累经验.这一系列的文章都是学习过程的总结,不带任何商业目的. 本文解决一个问题:如何伪造一个经纬度,在微信 ...

  4. iOS逆向开发(5):微信强制升级的突破 | 多开 | 微信5.0

    接下来的几篇文章,小程以微信为例,实战地演示一下:如何注入iOS的APP.其中使用到的知识,基本在前面的文章中都有介绍到. 小白:小程,我想用回旧版本的微信! 小程:为什么要用旧版本微信呢? 小白:你 ...

  5. iOS逆向开发(3):锁定APP的目标类与函数 | reveal | lldb | debugserver | 远程调试

    之前介绍了怎么获取APP的所有类的结构信息,这个有什么用呢?用处大了,比如以这一步为基础,下一步通过注入来做更多研究工作. 注入的最小单位是函数,实际上,编译执行的程序在编译后,类就不复存在了,留下来 ...

  6. iOS逆向开发(0):修改二进制代码与重签名 | hopper | codesigh

    小白:小程,你知道有些iOS程序是没人性的吗?老是不按我的意愿来运行! 小程:我怎么知道你的意愿就是有人性的? 本文解决一个问题:修改别人的二进制程序并运行起来. 让别人的程序按你的意愿来运行,文明一 ...

  7. iOS逆向开发(2):获取APP的类声明 | class-dump | dumpdecrypted

    之前介绍了怎么操作越狱的iOS设备(以下简称为手机),但简单操作手机并不是目标,小程的目标是手机上特定的APP,比如微信.淘宝.QQ音乐等等,因为小程可以从这些APP上拿到一些有用的信息或资源--比如 ...

  8. iOS逆向开发(7):微信伪装他人

    上一节小程介绍了微信在进入"附近的人"时修改位置信息的办法,这一次,小程来修改"自己"的信息,伪装成别人. 但是,这里的伪装只是"本地的伪装" ...

  9. Hook原理--逆向开发

    今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解.Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术.按照如下过程进行讲解 Hook概述 Hook技术方式 f ...

随机推荐

  1. py3.0第五天,常用模块

    本节大纲: 模块介绍 time &datetime模块 random os sys shutil json & picle shelve xml处理 yaml处理 configpars ...

  2. 1123. Is It a Complete AVL Tree (30)

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  3. k8s初始化搭建方法

    http://www.cnblogs.com/cocowool/p/kubeadm_install_kubernetes.html https://www.kubernetes.org.cn/doc- ...

  4. Code First的实体继承模式

    Entity Framework的Code First模式有三种实体继承模式 1.Table per Type (TPT)继承 2.Table per Class Hierarchy(TPH)继承 3 ...

  5. spring的一个小例子(二)--解析前面的小例子

    接上篇:http://www.cnblogs.com/xuejupo/p/5236448.html 首先应该明白,一个web项目,web.xml是入口. 然后下面来分析上篇博客中出现的web.xml: ...

  6. HTML的Tomcat

    修改D:\software\apache-tomcat-8.0.44\webapps\ROOT\WEB-INF\web.xml: <?xml version="1.0" en ...

  7. js 控制光标到指定位置

    js控制光标到指定节点位置(适用于富文本编辑器中) function placeCaretAtEnd(el) { //传入光标要去的jq节点对象 el.focus(); if (typeof wind ...

  8. oracle创建新用户和用户表空间

    .首先,创建(新)用户: create user username identified by password; username:新用户名的用户名 password: 新用户的密码 也可以不创建新 ...

  9. sshd_config 配置文件参数详解

    sshd_config配置详解 名称sshd_config - OpenSSH SSH 服务器守护进程配置文件 大纲/etc/ssh/sshd_config 描述sshd(8) 默认从 /etc/ss ...

  10. 1.Float精度在JS的解决方法

    最近做了一个有关折扣价的计算的功能,所有的运算都是在前台通过js来做,做完之后经过手工核算发现了一个问题,当时做的一个例子是10*0.94,按照我们正常的思维,这个结果应该是9.4,但是在js中的计算 ...