从获得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. 51Nod - 1046 (附关于快速幂的讨论)

    题意: 给出3个正整数A B C,求A^B Mod C. 例如,3 5 8,3^5 Mod 8 = 3. 分析: 快速幂模板题. 快速幂: 1.自然数的拆分 对于任何的自然数, 可以把它用形如1001 ...

  2. Java集合类的底层实现探索

    List: ArrayList 首先我们来看看jdk的ArrayList的add方法的源码是如何实现的: public boolean add(E e) { ensureCapacityInterna ...

  3. Java:Copy-On-Write容器

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  4. s6-6 TCP 连接释放

    TCP 连接释放 任何一方在没有数据要传送的时候,都可以发送一个FIN置位了的 TCP 数据段 当FIN被确认的时候,该方向的连接被关闭 当双向连接都关闭了的时候,连接释放 两军队问题 两军队问题 ( ...

  5. ajax动态刷新的元素,导致绑定事件失效

    jquery事件绑定有2种方式: 1,普通事件绑定: $('元素').click(function(){}); 2, 事件代理或者叫事件委托 $('#chatPanelList').on('click ...

  6. wx 参数传值

    1: data-id 我们可以给HTML元素添加自定义的data-*属性 example:   假设页面里有下面的元素存在: <div id="myDiv" data-nam ...

  7. _ZNote_Qt_添加图标方法

    简单来说就两步: 将icns图标添加入资源文件,例如picture.icns .pro文件中添加 (图标) ICON = picture.icns 程序中添加(程序窗口上显示) setWindowIc ...

  8. 学习Python第四天

    关于剩下的数据类型:字符串 字符串是有序的,不可变的(不可变的意思是指将变量a重新赋值后不会覆盖原来的值,而是在内存中开辟了一块新的内存地址,存储变量的值) 字符串的各种方法: 1,将字符串中的大写变 ...

  9. ICO图标下载地址

    http://findicons.com/ http://www.iconfont.cn/

  10. Leetcode35 Search Insert Position 解题思路(python)

    本人编程小白,如果有写的不对.或者能更完善的地方请个位批评指正! 这个是leetcode的第35题,这道题的tag是数组,python里面叫list,需要用到二分搜索法 35. Search Inse ...