前言
今天(2021.11.03)在查 MonkeyDev GitHub Wiki 的时候,发现其图片资源全部加载不出来,影响阅读
因此,根据 MonkeyDev GitHub Wiki 对其官方文档进行了整理,补全了图片资源,供自己和他人参考
原文地址:https://github.com/AloneMonkey/MonkeyDev/wiki
Home(主页)
-
Welcome to the MonkeyDev wiki !
This is a tool for Jailbreak and Non-Jailbreak developer
If you have a jailbreak device, you can use it to write a
CaptainHook Tweak
、Logos Tweak
orCommand-line Tool
If you don’t have a jailbreak device, you can create a
MonkeyApp
project to debug and hook third-party application
Let’s start !!!这是一个为越狱和非越狱开发人员准备的工具,主要包括四个模块:
-
Logos Tweak(用于:越狱开发)
使用 Theos 提供的
logify.pl
工具将*.xm
文件转成*.mm
文件进行编译,集成了CydiaSubstrate
,可以使用MSHookMessageEx
和MSHookFunction
来Hook
OC 函数和指定地址 -
CaptainHook Tweak(用于:越狱开发)
使用 CaptainHook 提供的头文件进行 OC 函数的 Hook 以及属性的获取
-
Command-line Tool(用于:越狱开发)
可以直接创建运行于越狱设备的命令行工具
-
MonkeyApp(用于:越狱开发 + 非越狱开发)
这是自动给第三方应用集成
Reveal
、Cycript
和注入dylib
的模块,支持调试dylib
和第三方应用,支持 Pod 给第三方应用集成 SDK,只需准备一个砸壳后的 ipa 或者 app 文件即可
安装
-
环境要求
使用工具前,请确保如下几点:
-
安装最新的 Theos
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
-
安装 ldid(如果在安装 Theos 的过程中安装了 ldid,则跳过)
brew install ldid
-
配置免密码登录越狱设备(如果没有越狱设备,则跳过)
ssh-keygen -t rsa -P '' ssh-copy-id -i /Users/username/.ssh/id_rsa root@ip
或者安装
sshpass
自己设置密码brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb
-
-
安装
你可以通过以下命令选择指定的 Xcode 版本进行安装:
# 修改使用的 Xcode 的版本 # sudo xcode-select --switch /Applications/Xcode-beta.app sudo xcode-select -s /Applications/Xcode-beta.app
默认安装的 Xcode 版本为:
# 查看当前正在使用的 Xcode 版本的路径 # xcode-select --print-path xcode-select -p
执行安装命令:
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)"
-
卸载
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-uninstall)"
-
更新
如果没有发布特殊说明,使用如下命令更新即可:
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)"
-
注意
在安装或者更新 MonkeyDev 之后,需要重启下 Xcode,再新建项目
开始使用
-
创建项目
安装完成之后,打开
Xcode
,点击File - New - Project...
,选择iOS
滑动到最下方就可以看到MonkeyDev
提供的模块:
选择相应的项目类型,就可以创建对应的项目 -
Logos Tweak
Logos Tweak 项目的结构如下所示(这里创建的项目名称正好为
logos
):
代码写在logos.xm
文件中,具体语法看 Logos,写完之后脚本会自动将其转成logos.mm
文件的内容,然后编译其中几个文件的解释如下:
control
:这个文件是用来配置生成deb
包的一些信息,比如版本号、说明、作者等等logos.plist
:这个文件是用来指定注入的目标进程,一般填入目标进程的BundleID
即可- 如果需要在安装之前或者之后进行某些操作的话,可以在
DEBIAN
文件夹下面增加preinst
脚本(在安装之前执行)、postinst
脚本(在安装之后执行)、prerm
脚本(在卸载之前执行)、postrm
脚本(在卸载之后执行),记得要赋予脚本可执行的权限! - 这里的
Package
文件夹就相当于安装到目标设备之后的根目录,所以要增加什么文件到目标设备都可以在Package
文件夹下面创建对应的文件或者文件夹!
项目会自动链接
CydiaSubstrate.framework
,无需再手动链接项目相关的一些配置在
Build Settings
的最下面(User-Defined
),如下:
具体含义见:配置说明Debug 模式安装:
按快捷键Command + B
就会自动安装到手机Release 模式安装:
按快捷键Command + Shift + i
即可。不过这种方式安装是不会看到 Log 的哦 ~~查看 Log 输出:
- 安装
libimobiledevice
工具:brew install libimobiledevice
- 使用如下命令查看 Log 输出:
idevicesyslog | grep 'xxx'
- 或者使用自带的
console.app
程序查看
-
CaptainHook Tweak 和 Command-line Tool
创建和配置与 Logos Tweak 差不多
Logos Tweak 和 CaptainHook Tweak 都支持通过 CocoaPods 的方式集成 SDK,不过记得要以静态库的方式集成!
配置说明
设置项 | 意义 |
---|---|
MonkeyDevBuildPackageOnAnyBuild | 每次 Build 都生成 deb 包 |
MonkeyDevCopyOnBuild | Build 时将 deb 包拷贝到目标设备的 /var/root/MonkeyDevBuilds/ 目录 |
MonkeyDevDeviceIP | 目标设备的 IP 地址,默认 USB 连接,localhost |
MonkeyDevDevicePort | 目标设备的端口,默认 22 |
MonkeyDevDevicePassword | 目标设备的 ssh 登录密码,默认为空,使用免密码登录 |
MonkeyDevInstallOnAnyBuild | 每次 Build 都将 deb 安装到目标设备 |
MonkeyDevInstallOnProfiling | 点击 Profile 才将 deb 安装到目标设备 |
MonkeyDevKillProcessOnInstall | 安装的时候杀掉指定的进程,填写进程名 |
MonkeyDevClearUiCacheOnInstall | 安装时 clear uicache |
MonkeyDevPath | MonkeyDev 的安装路径,默认为 opt/MonkeyDev ,不用修改 |
MonkeyDevTheosPath | Theos 的安装路径,默认为 opt/theos 。如果将 Theos 安装在 ~/theos ,则修改为 ~/theos |
默认的远程设备 IP 为 localhost
,端口为 22
可以在 ~/.zshrc
或者 ~/.bash_profile
配置文件中设置导出环境变量:
export MonkeyDevDeviceIP=
export MonkeyDevDevicePort=
非越狱 App 集成
注意:选真机编译运行!!!
-
准备好砸壳的 ipa 或者 app
第一步是准备好砸壳的 ipa 或者 app,可以从某助手下载越狱应用(下载的应用中,也有没砸壳的 QAQ)
-
创建 MonkeyApp 项目
点击
File - New - Project...
创建 iOS 项目,选择MonkeyApp
然后填写Product Name
,对于非越狱设备可以不用管Target App
,如果是越狱设备的话可以在Target App
填写目标 App 的名字或者BundleID
,工具将会自动使用 frida-ios-dump 提取 ipa 文件(注意:需要先按frida-ios-dump
repo 的 README 配置好环境!),如下所示:
另外/opt/MonkeyDev/bin/dump.py
里面可以指定IP
、Port
、Password
创建完成之后,你会得到一个这样的工程:
这里我创建的项目名字就是MonkeyApp
,所以下面对应的都是MonkeyApp
,你自己创建的由你的项目名字而定!MonkeyAppDylib
这个是将被注入目标 App 的动态库,你自己要 hook 的代码可以在MonkeyAppDylib.m
文件里面写,我在里面写了一些 Demo 代码,支持OC RunTime 的 HOOK,C 函数的 fishhook。还支持 Theos Logos Tweak 的写法!Theos Logos Tweak 直接写在MonkeyAppDylib.xm
文件中即可Config
这个里面是Cycript
的一些脚本下载以及 MethodTrace 配置代码LLDBTools
这个里面是用于 LLDB 调试的代码,比如po pviews()
AntiAntiDebug
这个里面是反反调试的代码fishhook
这个里面是自动集成的 fishhook 模块创建的项目已经自动集成了
RevealServer.framework
和libcycript.dylib
,如果选择 Release 编译的话是不会集成的 -
拖入编译
我准备了一个砸壳了的 ipa 文件,然后我右键项目里面的
TargetApp
文件夹 Show in Finder,把 ipa 文件拖入下面的位置(当然拖入 app 文件也是可以的):
或者支持直接将文件拖到 Xcode 项目的TargetApp
分组下面Xcode 8 需要另外指定一下依赖,选择
Build Phases
,点击Target Dependencies
增加需要注入的动态库即可。如下:
然后编译运行,打开电脑的Reveal
,就可以看到界面了:
从 Cycript 下载 SDK,然后进去 SDK 目录运行如下命令,Cycript
查看界面也没有问题:
这里Cycript
默认端口是6666
-
更多功能:动态库调试
在
MonkeyAppDylib.m
文件中写了自己的代码之后就可以直接下断点调试,效果如下:
MonkeyAppDylib.xm
文件也支持动态调试,在文件左侧点击下断点即可,第一次由于后缀 Xcode 不识别,下的断点不会显示出来,但是断点是生效的!在右侧将MonkeyAppDylib.xm
文件类型改成Objective-C++
,然后重新打开文件或者重启 Xcode,效果如下:
-
更多功能:Demo App
MonkeyApp
在不拖入.app
或者.ipa
的情况下,会有一个默认的 App,以供读者自己测试,大概是这个样子····
你可以自己修改MonkeyAppDylib.m
里面的代码,这个是笔者针对Demo
写的例子啦,另外需要注意的是 MonkeyApp 里面都是 ARC,所以网上很多 MRC 的写法是有问题的,多多参考笔者的例子:https://github.com/AloneMonkey/WeChatPodCHDeclareClass(CustomViewController) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wstrict-prototypes" // add new method CHDeclareMethod1(void, CustomViewController, newMethod, NSString*, output) { NSLog(@"This is a new method : %@", output); } #pragma clang diagnostic pop CHOptimizedMethod0(self, NSString*, CustomViewController, getMyName) { // get origin value NSString* originName = CHSuper(0, CustomViewController, getMyName); NSLog(@"origin name is:%@", originName); // get property NSString* password = CHIvar(self, _password, __strong NSString*); NSLog(@"password is %@", password); [self newMethod:@"output"]; // set new property self.newProperty = @"newProperty"; NSLog(@"newProperty : %@", self.newProperty); // change the value return @"AloneMonkey"; } // add new property CHPropertyRetainNonatomic(CustomViewController, NSString*, newProperty, setNewProperty); CHConstructor{ CHLoadLateClass(CustomViewController); CHClassHook0(CustomViewController, getMyName); CHHook0(CustomViewController, newProperty); CHHook1(CustomViewController, setNewProperty); }
-
更多功能:class-dump
工程已集成
class-dump
导出可执行文件 OC 头文件的功能,可在 Build Settings 最下面开启该功能
开启后 Build 时会自动进行class-dump
的操作,然后会在项目的目录下生成一个头文件的文件夹:
-
更多功能:restore-symbol
一般应用发布后调试堆栈是没有符号信息的,但是由于 OC 语言的特性,需要保存类名和方法名,所以可以根据具体方法的地址填写到符号表中,还原符号表。具体可以阅读文章 iOS 符号表恢复 & 逆向支付宝
开启该功能的方式和开启
class-dump
一样 -
更多功能:方法跟踪日志
增加对方法跟踪的日志打印,代替烦人的
logify.pl
,只需配置一下即可,在新建项目中找到MDConfig.plist
ENABLE
:设置为YES
开启方法跟踪,默认为NO
CLASS_LIST
:设置需要跟踪的类或指定的方法,如果是对整个类进行跟踪只用写类名,对类里面特定的方法需要再加一个 Array 数组加上方法名,参考默认的写法
主要代码来自 qhd 的 ANYMethodLog注意:新版已经迁移到 OCMethodTrace,请到项目主页查看相关用法
-
更多功能:默认集成的库
本工具会默认集成
RevealServer.framework
和libcycript.dylib
,em……集成的
RevealServer.framework
是最新版本的,所以你可能需要最新的Reveal
,否则使用自己的RevealServer.framework
替换掉/opt/MonkeyDev/frameworks
下面的RevealServer.framework
使用 Release 编译生成将不会集成
Reveal
和Cycript
-
更多功能:增加自己的库
首先将需要注入的 dylib 或者 framework 按下面的方式拷贝到 frameworks 目录下:
然后在下图的位置 add 进去,emmm… 就可以了
静态库的话,直接增加到上面,指定search path
就可以了,和正常开发没啥区别 …注意动态库本身的 install_path,可以通过
install_name_tool -id
修改其为@executable_path/Frameworks/xxxxx
-
更多功能:集成网络 cy 脚本
通过配置
CycriptConfig.plist
可以导入从网络下载的 cy 脚本,比如通过如下的配置:
LoadAtLaunch
:表示是否在启动的时候默认加载脚本,默认加载的脚本就不用再@import xxx
导入,可以直接使用。如果不是默认加载的脚本就需要@import xxx
导入,xxx
就是图中的 key,比如@import md
priority
:表示加载的优先级,数字越小优先级越高,比如某些脚本需要依赖其它脚本就需要调整优先级,让被依赖的脚本先加载content
和url
:脚本可以直接写到content
里面,也可以是网络的url
,会自动下载下来➜ cycript_0.9.594 ./cycript -r 192.168.2.248:6666 cy# APPID @"com.alonemonkey.TestCycript" cy# pviews() <UIWindow: 0x105313b60; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x1c425bae0>; layer = <UIWindowLayer: 0x1c40394e0>> | <UIView: 0x1053205d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x1c403bd80>> | | <UILabel: 0x10531e7d0; frame = (102.5 45; 170 40); text = 'AloneMonkey'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1c408c0d0>> | | <UILabel: 0x1053207b0; frame = (97.5 110; 180 40); text = 'You are the best!!!'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1c408e150>> | | <UITextView: 0x105836000; frame = (26 230; 343 427); text = '/opt/MonkeyDev/bin/md ....'; clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x1c0058fc0>; layer = <CALayer: 0x1c002f1a0>; contentOffset: {0, 0}; contentSize: {343, 317}; adjustedContentInset: {0, 0, 0, 0}> | | | <<_UITextContainerView: 0x105318060; frame = (0 0; 343 317); layer = <__UITextTiledLayer: 0x1c40c42f0>> minSize = {0, 0}, maxSize = {1.7976931348623157e+308, 1.7976931348623157e+308}, textContainer = <NSTextContainer: 0x1c0105fa0 size = (343.000000,inf); widthTracksTextView = YES; heightTracksTextView = NO>; exclusionPaths = 0x1c40025e0; lineBreakMode = 0> | | | | <__UITileLayer: 0x1c0240780> (layer) | | | | <__UITileLayer: 0x1c0240720> (layer) | | | | <__UITileLayer: 0x1c0240a20> (layer) | | | <UIImageView: 0x105322260; frame = (3 421.5; 337 2.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x1c403c620>> | | | <UIImageView: 0x105322490; frame = (337.5 380; 2.5 44); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x1c403c6e0>> | | <UIButton: 0x1053163b0; frame = (127.5 175; 120 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x1c4039aa0>> | | | <UIButtonLabel: 0x10540fcf0; frame = (2 6; 116.5 18); text = 'ShowChangeLog'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1c0087b70>> | | <_UILayoutGuide: 0x105320fa0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x1c403bfe0>> | | <_UILayoutGuide: 0x1053213a0; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x1c403bee0>> cy# pvcs() "<CustomViewController 0x1053133f0>, state: appeared, view: <UIView 0x1053205d0>" cy# pactions(#0x1053163b0) "<CustomViewController: 0x1053133f0> showChangeLog:" cy# rp(#0x1053163b0) <UIButton: 0x1053163b0; frame = (127.5 175; 120 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x1c4039aa0>> <UIView: 0x1053205d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x1c403bd80>> <CustomViewController: 0x1053133f0> <UIWindow: 0x105313b60; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x1c425bae0>; layer = <UIWindowLayer: 0x1c40394e0>> <UIApplication: 0x105406120> <AppDelegate: 0x1c002b1a0> cy# ?exit
-
更多功能:集成 Frida
如果自己集成第三方现成 SDK 的库也是一样的步骤,不过需要注意修改
install path
:install_name_tool -id @executable_path/Frameworks/xxxx.dylib xxxx.dylib
由于
Frida
的动态库太大了,就没有默认集成在 MonkeyDev 中,但是自己集成起来也是非常简单的,就两步:- 从 FridaGadget.dylib 下载动态库,添加到 App 最后的 Copy Files 里面:
- 将
FridaGadget.dylib
链接到 MonkeyDev 注入动态库的依赖里面:
启动日志有:
Frida: Listening on 127.0.0.1 TCP port 27042
就是集成成功 - 从 FridaGadget.dylib 下载动态库,添加到 App 最后的 Copy Files 里面:
-
更多功能:增加资源
把你需要嵌入的 bundle 资源和 storyboard 资源拷贝到这个目录就可以了哦 ~
upadte:更新增加资源的方式,直接往 MonkeyApp 里面增加资源即可,比如新建test.plist
文件选择 MonkeyApp 的 Target,保证要增加的资源在如下列表中:
-
更多功能:更改名字和 BundleID
如果需要更改重签应用的显示名字和
BundleID
可以在 Xcode 设置即可,想使用原来的BundleID
进行重签,设置 Build Settings 里面的MONKEYDEV_DEFAULT_BUNDLEID
为YES
-
更多功能:生成 IPA
运行之后在源代码的
LatestBuild
目录双击createIPA.command
即可生成 IPA 文件
CocoaPods
-
CocoaPods
MonkeyApp 本身是支持 CocoaPods 集成第三方库的,但是可能有一些设置需要修改下
在 MonkeyApp 项目,这里假设项目名是
MonkeyPod
,在目录下新建文件Podfile
写入内容:use_frameworks! target 'MonkeyPodDylib' do pod 'FLEX' end
这里的 Target 要设置为动态库而不是 App,然后执行
Pod install
也可以使用笔者私有 CocoaPods:
source 'https://github.com/AloneMonkey/MonkeyDevSpecs.git' use_frameworks! target 'MonkeyPodDylib' do pod 'FLEX' pod 'MonkeyDevPod', '2.0.0' end
-
编译参数修改
-
如果你拖入的应用,砸壳的架构和安装设置的架构不一致的话,比如只砸了 armv7 的架构,但是要安装到 arm64 的机器,就需要把 Pod 进来的所有有源码的库的
Build Settings
下Build Active Architecture Only
的 Debug 改成 No,包括Pods-xxxxDylib
这个 Target -
直接从XX助手下载的越狱应用,不需要进行 (1) 的修改,直接运行!
-
-
运行效果
-
非越狱插件 Pod 化
既然支持 Pod,当然也支持将自己的插件传到 Pod 上,然后通过 Pod 安装,简直就是一个非越狱平台的插件商店啊!!!
笔者这里自己弄了一个私有 Pod,编辑
Podfile
:source 'https://github.com/AloneMonkey/MonkeyDevSpecs.git' use_frameworks! target 'MonkeyPodDylib' do pod 'MonkeyDevPod' end
然后安装,修改
Pods-MonkeyPodDylib
-Build Settings
下Build Active Architecture Only
的 Debug 改成 No注释
MonkeyPodDylib.m
文件的:CHConstructor{ CHLoadLateClass(CustomViewController); CHClassHook(0, CustomViewController, getMyName); }
因为
MonkeyDevPod
这个库也是修改屏幕显示的返回字符串为MonkeyDevPod
,运行即可看到效果
-
欢迎大家往我的私有 CocoaPods 仓库提交自己的非越狱插件哦 ~~
非越狱插件 Pod
本节主要介绍如何将自己的非越狱插件上传到 CocoaPods,然后通过 Pod 一键安装!
注意:自己开发 Pod 的时候,文件命名都带上前缀,以防止多个 Pod 出现同一个头文件的情况!
-
创建工程
MonkeyDev 本身提供了创建 Pod 的项目,点击
File -> New -> Project
,在 iOS 的最下面选择MonkeyPod
创建新的项目如下:
创建出来的项目目录结构如下所示:
可以将你通过CaptainHook
编写的代码直接拷贝过来即可,其中有一个xxxx.podspec
的文件就是用来上传 CocoaPods 的,右键点击在 Finder 显示,然后使用终端定位到xxxx.podspec
文件的目录,将其拖到项目的根目录下并从项目中移除并输入pod lib lint
进行本地验证➜ MonkeyPod pod lib lint --allow-warnings -> MonkeyPod (1.0.0) -WARN | xcodebuild: /Users/alonemonkey/Desktop/MonkeyPod/MonkeyPod/MonkeyPod.m:17:1: warning: undeclared selector 'getMyName' [-Wundeclared-selector] -NOTE | xcodebuild: <scratch space>:3:1: note: expanded from here -NOTE | xcodebuild: <scratch space>:5:1: note: expanded from here MonkeyPod passed validation. [!] Unable to read the license file '/private/var/folders/7q/dxk4jpyn59x40lt6p998dkg40000gn/T/CocoaPods-Lint-20170908-29497-1ys2vxr-MonkeyPod/Pods/CaptainHook/LICENSE' for the spec 'CaptainHook (2.0.0)' [!] Unable to read the license file '/Users/alonemonkey/Desktop/MonkeyPod/MonkeyPod/LICENSE' for the spec 'MonkeyPod (1.0.0)' [!] Unable to read the license file '/private/var/folders/7q/dxk4jpyn59x40lt6p998dkg40000gn/T/CocoaPods-Lint-20170908-29497-1ys2vxr-MonkeyPod/Pods/CaptainHook/LICENSE' for the spec 'CaptainHook (2.0.0)' [!] Unable to read the license file '/Users/alonemonkey/Desktop/MonkeyPod/MonkeyPod/LICENSE' for the spec 'MonkeyPod (1.0.0)'
验证成功
-
上传到 GitHub
在 GitHub 创建一个 repo,然后将本地代码上传到 repo,将代码打一个 tag
MonkeyPod git init Initialized empty Git repository in /Users/monkey/Documents/MacReverse/MonkeyDev/MonkeyPod/.git/ ➜ MonkeyPod git:(master) ✗ git add . ➜ MonkeyPod git:(master) ✗ git commit -m "first commit" [master (root-commit) ca15785] first commit 9 files changed, 1193 insertions(+) create mode 100644 MonkeyPod.xcodeproj/project.pbxproj create mode 100644 MonkeyPod.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 MonkeyPod.xcodeproj/project.xcworkspace/xcuserdata/monkey.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 MonkeyPod.xcodeproj/xcuserdata/monkey.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 MonkeyPod/CaptainHook/CaptainHook.h create mode 100644 MonkeyPod/Info.plist create mode 100644 MonkeyPod/MonkeyPod.h create mode 100644 MonkeyPod/MonkeyPod.m create mode 100644 MonkeyPod.podspec ➜ MonkeyPod git:(master) git remote add origin https://github.com/AloneMonkey/MonkeyPod.git ➜ MonkeyPod git:(master) git pull origin master --allow-unrelated-histories From https://github.com/AloneMonkey/MonkeyPod *_ branch master -> FETCH_HEAD Merge made by the 'recursive' strategy. LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 2 files changed, 203 insertions(+) create mode 100644 LICENSE create mode 100644 README.md ➜ MonkeyPod git:(master) git push -u origin master Counting objects: 22, done. Delta compression using up to 8 threads. Compressing objects: 100% (18/18), done. Writing objects: 100% (22/22), 18.58 KiB | 0 bytes/s, done. Total 22 (delta 0), reused 0 (delta 0) To https://github.com/AloneMonkey/MonkeyPod.git bb37187..51afe82 master -> master Branch master set up to track remote branch master from origin. ➜ MonkeyPod git:(master) git tag -a 1.0.0 -m "release 1.0.0" ➜ MonkeyPod git:(master) git push origin --tags Counting objects: 1, done. Writing objects: 100% (1/1), 169 bytes | 0 bytes/s, done. Total 1 (delta 0), reused 0 (delta 0) To https://github.com/AloneMonkey/MonkeyPod.git *[new tag] 1.0.0 -> 1.0.0
-
传到私有 CocoaPods
代码上传到 GitHub 后需要重新修改
xxxx.podspec
文件里面的路径为 GitHub 对应的路径,如下,tag 和刚刚打的 tag 一致!Pod::Spec.new do |spec| spec.name = "MonkeyPod" # Pod 的名字 spec.version = "1.0.0" # 版本号 spec.summary = "A example pod for MonkeyDev" # Pod 的摘要 spec.description = <<-DESC # Pod 的描述 # A example pod for MonkeyDev DESC spec.homepage = "https://github.com/AloneMonkey/MonkeyDevPod" # Pod 的地址 spec.license = { :type => "BSD", :file => "LICENSE" } # License spec.author = { "AloneMonkey" => "liupeiqing1993@163.com" } # 作者 spec.social_media_url = "http://weibo.com/xiaoqing28" # weibo spec.platform = :ios, "8.0" # 平台、版本 spec.source = { :git => "https://github.com/AloneMonkey/MonkeyPod.git", :tag => spec.version.to_s } # 代码的 git 地址以及 tag spec.source_files = "MonkeyPod/xx/x.{h,m}" # 本地验证这里填 "xx/x",表示当前目录以及子目录的所有文件。如果发布到 MonkeyPodSpec 需要填写 git clone 下来的对应的路径 spec.public_header_files = "MonkeyPod/MonkeyPod.h" # 需要对外导出的头文件,此处为本地验证 spec.requires_arc = true # ARC spec.dependency 'CaptainHook' # 由于多个 Pod 导致 CaptainHook.h 找不到,单独依赖 CaptainHook spec.pod_target_xcconfig = { "ONLY_ACTIVE_ARCH" => "No" } # 这个必须有,不要修改 end
然后需要增加私有的 Pod:
首先 fork 我的私有 CocoaPods
然后下面的https://github.com/AloneMonkey/MonkeyDevSpecs.git
换成你 fork 的链接
最后提交成功后再向我的私有 CocoaPods 提 pull request!!!➜ MonkeyPod git:(master) ✗ pod repo add MonkeyDevSpecs https://github.com/AloneMonkey/MonkeyDevSpecs.git Cloning spec repo `MonkeyDevSpecs` from `https://github.com/AloneMonkey/MonkeyDevSpecs.git`
最后提交 Pod:
➜ MonkeyPod git:(master) ✗ pod repo push MonkeyDevSpecs MonkeyPod.podspec --allow-warnings Validating spec -> MonkeyPod (1.0.0) -ARN | xcodebuild: MonkeyPod/MonkeyPod/MonkeyPod.m:17:1: warning: undeclared selector 'getMyName' [-Wundeclared-selector] -NOTE | xcodebuild: <scratch space>:4:1: note: expanded from here -NOTE | xcodebuild: <scratch space>:6:1: note: expanded from here Updating the 'MonkeyDevSpecs' repo Already up-to-date. Adding the spec to the 'MonkeyDevSpecs' repo -[Add] MonkeyPod (1.0.0) Pushing the 'MonkeyDevSpecs' repo To https://github.com/AloneMonkey/MonkeyDevSpecs.git d2cc68b..1f8d101 master -> master
提交成功后,往 MonkeyDevSpecs 提交 pull request,pull request 通过后然后继续下一步
-
集成 Pod
Pod 推送成功后就能够通过 Pod 集成非越狱插件了,新建一个 MonkeyApp 工程,然后新建一个
Podfile
文件,内容如下:source 'https://github.com/AloneMonkey/MonkeyDevSpecs.git' use_frameworks! target 'MonkeyAppDylib' do pod 'MonkeyPod' end
一定要加
use_frameworks!
以动态库的方式导入!!!pod install
安装,并打开MonkeyApp.xcworkspace
文件➜ MonkeyApp pod install Analyzing dependencies Downloading dependencies Installing MonkeyPod (1.0.0) Generating Pods project Integrating client project [!] Please close any current Xcode sessions and use `MonkeyApp.xcworkspace` for this project from now on. Sending stats Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed. [!] Automatically assigning platform ios with version 8.0 on target MonkeyAppDylib because no platform was specified. Please specify a platform for this target in your Podfile. See 'https://guides.cocoapods.org/syntax/podfile.html#platform'.
打开工程后发现 Pod 已经成功集成!运行项目也会断在集成的 Pod 代码上面!
-
MonkeyApp 和 MonkeyPod 结合使用
如果我想要边写 Pod 边开发插件可不可以呢? 答案是当然可以! MonkeyApp 和 MonkeyPod 完美结合!
首先新建一个 MonkeyApp 工程,然后新建一个 MonkeyPod 工程,然后把 MonkeyPod 工程拖到 MonkeyApp 工程,如图:
然后找到 MonkeyApp 的Target Dependencies
增加依赖MonkeyPod (MonkeyPod)
并在Embed Libraries
增加库MonkeyPod.framework
:
最后在 MonkeyApp 的动态库MonkeyAppDylib
的Link Binary With Libraries
里面链接MonkeyPod.framework
:
运行就可以将 MonkeyPod 注入到 MonkeyApp,实现边写 Pod 边写插件!!!玩的开心 ~~
-
欢迎大家往我的私有 CocoaPods 仓库提交自己的非越狱插件哦 ~~
Mac 插件
MonkeyDev 现已支持给 macOS 应用写插件啦!!!
-
① 首先新建工程,在 macOS 模块最下面选择 MonkeyAppMac:
-
② 将需要注入的目标文件拖入
TargetApp
文件夹:
-
③
Command + B
运行目标文件,将会自动注入 dylib,默认实现了 QQ 防撤回的功能:@class MQAIOChatViewController; @class QQMessageRevokeEngine; static void (*origin_MQAIOChatViewController_revokeMessages)(MQAIOChatViewController*, SEL, id); static void new_MQAIOChatViewController_revokeMessages(MQAIOChatViewController* self, SEL _cmd, id arrays) { } static void (*origin_QQMessageRevokeEngine_handleRecallNotify_isOnline)(QQMessageRevokeEngine*, SEL, void*, BOOL); static void new_QQMessageRevokeEngine_handleRecallNotify_isOnline(QQMessageRevokeEngine* self, SEL _cmd, void* notify, BOOL isOnline) { } static void __attribute__((constructor)) initialize(void) { MSHookMessageEx(objc_getClass("MQAIOChatViewController"), @selector(revokeMessages:), (IMP)&new_MQAIOChatViewController_revokeMessages, (IMP*)&origin_MQAIOChatViewController_revokeMessages); MSHookMessageEx(objc_getClass("QQMessageRevokeEngine"), @selector(handleRecallNotify:isOnline:), (IMP)&new_QQMessageRevokeEngine_handleRecallNotify_isOnline, (IMP*)&origin_QQMessageRevokeEngine_handleRecallNotify_isOnline); }
-
④ 启动完成之后,点击
Debug -> Attach to Process
,选择刚刚运行起来的 QQ 进程
然后在new_QQMessageRevokeEngine_handleRecallNotify_isOnline
这个方法下一个断点,撤回一条消息,即可断下来看到堆栈
-
注意:本工具暂时还不支持本身有反调试的应用,比如百度网盘,如要调试可以使用 AntiAntiDebug 脚本启动时反反调试
笔者相关文章:一篇文章走进 Mac 逆向的世界
越狱插件 Xcode 调试
之前的 Logos Tweak 和 CaptainHook Tweak 工程是不支持 Xcode 直接调试的,只能通过打印 log 看效果,后面可以通过 MonkeyApp 直接进行调试方便了很多,但是每次调试都要重新安装应用其实还是挺麻烦的,这里介绍一种使用 Xcode 直接调试 Logos Tweak 和 CaptainHook Tweak 工程的方法
由于 Xcode 使用的是默认的 /Developer/usr/bin/debugserver
进行调试的,所以被调试的应用要是自己重签名安装的,可以使用 MonkeyApp 重签安装下就好了
具体的流程如下:
- 重签安装被调试的应用
- 创建 Logos Tweak 或者 CaptainHook Tweak 工程,编写代码,指定
BundleID
,设置断点 - 点击
Xcode 菜单栏 -> Debug -> Attach to Process by PID or Name
- 输入进程名或者 pid
- 上面填写进程名可以进行启动调试,然后打开被调试的应用,就会自动附加并且断在断点的位置(如果触发了的话)
- 接下来就可以进行调试开发了,修改代码之后
Command + B
安装,然后重复第 3 步
Logos Tweak Project Debug 的效果图如下:
CaptainHoook Tweak Project Debug 的效果图如下:
更新日志
-
使用新的 OC 方法跟踪框架(2018/12/10)
使用新的 OC 方法跟踪框架 OCMethodTrace
-
支持 iOS 11 的 Command-line(2018/10/10)
支持 iOS 11 的
Command-line
,并且可以在这个基础上制作 iOS 11 的 daemon -
修改使用默认 BundleID 的方式(2018/08/03)
不修改
BundleID
的方式改为通过 Build Settings 里面的MONKEYDEV_DEFAULT_BUNDLEID
设置 -
统一通过 MDConfig.plist 配置,优化代码(2018/04/25)
通过
MDConfig.plist
配置,优化部分代码,增加用户提示 -
更新 Cycript,直接从网络下载 cy 脚本(2018/04/20)
通过
CycriptConfig.plist
文件配置从网络下载 cy 脚本文件,然后通过@import
导入 -
集成 frida-ios-dump 到 MonkeyApp(2018/03/12)
集成
frida-ios-dump
,在越狱设备运行自动砸壳 -
支持直接拖拽 ipa 文件到 Xcode 工程的 TargetApp 文件夹下面(2018/02/27)
支持直接拖拽 ipa 文件到 Xcode 工程的
TargetApp
分组下面,原来打开 Finder 放到TargetApp
文件夹下也可以增加使用 Xcode 调试 Logos Tweak 和 CaptainHook Tweak 项目的方法
-
Release 不集成 Cycript 和 Reveal(2018/02/04)
可以选择 Debug 和 Release,Release 下不再集成
Cycript
和Reveal
,方便个人使用 -
增加 monkeyparser(2017/12/15)
使用
monkeyparser
替换restore-symbol
、optool
、unsign
在无法使用免密码登录的情况下,支持设置 ssh 密码
BundleID
填aaa
使用应用原来的BundleID
进行重签 -
增加统一的插件设置界面(2017/10/30)
增加统一的插件设置界面,参考 WeChatPod 和 MDSettingCenter 的使用
-
增加方法执行追踪日志(2017/09/06)
打印方法的调用顺序和参数
优化增加资源的方式,直接在 MonkeyApp 增加资源
-
增加 Mac 应用插件集成(2017/08/11)
在 macOS 模板下增加 MonkeyAppMac,给 macOS 应用集成插件
增加非越狱插件使用 Logos 编写
-
去掉自带 substrate(2017/08/04)
去掉非越狱自带
CydiaSubstrate
和JRSwizzle
,都自己从 CocoaPods 安装 -
MSHookMessageEx 支持(2017/07/31)
非越狱增加
MSHookMessageEx
支持增加一键生成 ipa 支持
-
集成符号还原(2017/07/29)
集成
class-dump
集成符号还原
集成 JRSwizzle
-
Fix 多证书问题(2017/07/27)
默认导入
CaptainHook.h
头文件解决多个证书错误的问题
optool
升级到 v 0.2,增加unrestrict
功能 -
CocoaPods(2017/07/25)
增加设置 URL Scheme 支持
增加 CocoaPods 支持
Fix 一些问题
-
增加 killprocess(2017/07/19)
增加
MonkeyDevKillProcessOnInstall
,在安装时杀掉指定进程增加
MonkeyDevClearUiCacheOnInstall
, 在安装时 clear uicache增加非越狱集成时增加自己的 Storyboard 和 Bundle 资源
-
非越狱集成(2017/07/12)
增加非越狱 app 集成 SDK
修改默认设置,默认端口恢复为 22
默认 Build 安装
-
迁移 iOSOpenDev 的功能(2017/06/27)
增加
CaptainHook Tweak
、Logos Tweak
、Command-line Tool
自动链接
CydiaSubstrate.framwork
默认设备 IP 和端口
Q & A
-
one
Q:一个工程放了一个应用后,再放另外一个应用,第一个应用的内容没有删除?(已解决)
A:同一个工程要放不同的应用,要先
Product - Clean
一下,快捷键是Command + Shit + K
-
two
Q:编译提示找不到
libxxxDylib.dylib
A:先指定一下依赖,选择
Build Phases
,点击Target Dependencies
增加需要注入的动态库即可。如下:
如果已增加依赖,则切换到动态库单独编译,应该是有错误还没解决 -
three
Q:运行出现
_dyld_debugger_notification
这样的崩溃(默认注释)A:把
AntiAntiDebug.m
这个文件的这行代码注释掉rebind_symbols((struct rebinding[1]){{"sysctl", my_sysctl, (void*)&orig_sysctl}},1);
-
four
Q:本机有多个证书,报如下错误:
codesign...iPhone Developer: ambiguous(matches "iPhone Developr: xxxx@xxx.com" and "iPhone Developr: xxxx@xxx.com") in xxx login.keychain-db
A:先在 keychain 里面删除其它证书,只保留一个证书,或者关闭 auto signing,在 Build Settings 指定证书
-
five
Q:安装 Tweak 后看不到 Log 输出(默认 Build 安装)
A:设置
MonkeyDevInstallOnAnyBuild
为 YES,然后按快捷键Command + B
安装到手机,这种才是 Debug 模式,才能看到 Log -
six
Q:支持 Bundle 资源和 Storyboard 吗?
A:当然支持!把你需要嵌入的 Bundle 资源和 Storyboard 拷贝到这个目录就可以了哦 ~
-
seven
Q:CaptainHook Tweak 项目安装出现错误
MS:Error: failure to check xxx.dylib
A:把过滤
plist
文件里面没有设置过滤项的参数删除(新版只会留一个BundleID
的设置项) -
eight
Q:加了自己的 framework 之后,出现
Could not inspect the application package.
A:是不是把静态库放在
/opt/MonkeyDev/Frameworks/
下面啦?这里只能放动态库呢!静态库自己随便放哪,或者放/opt/MonkeyDev/Librarys
下面哦!怎么看是静态库还是动态库呢?otool -hv xxxx(可执行文件)
- 静态库会显示一堆
OBJECT
- 动态库会显示
DYLIB
-
nine
Q:放入 ipa 之后,报错
process launch failed : Unspecified/Disabled/xxx
A:没有砸壳!!!或者你砸的是 armv7 的,却运行在 arm64 的设备,可以通过
lipo xxx -thin armv7 -output xxx_armv7
瘦身! -
ten
Q:集成 Pod 后运行提示:
No code signature found!
A:尝试给集成的 Pod 选择一下自动签名试试,都要同一证书
-
eleven
Q:运行后出现
dyld: Library not loaded: xxxx mremap_encrypted() => -1 , errorno=1
A:framwork 没有砸壳,使用 https://github.com/AloneMonkey/frida-ios-dump 给 framwork 砸壳
-
twelve
Q:10.13 系统下用
Cycript
报错:dyld: Library not loaded: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/libruby.2.0.0.dylib Referenced from: /Users/Jveryl/Desktop/Crash/cycript_0/Cycript.lib/cycript-apl Reason: image not found Abort trap: 6
A:先关闭系统的 SIP,然后运行如下命令,把原来引用的位置创建符号链接到现在新版本的位置:
sudo mkdir -p /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ sudo ln -s /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/libruby.2.3.0.dylib /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/libruby.2.0.0.dylib
或者
brew install ruby@2.0
- 把
/usr/local/Cellar/ruby@2.0/2.0.0-p648_2/lib/libruby.2.0.0.dylib
拷贝到Cycript.lib
目录下
-
thirteen
Q:重签后因为证书不一样,导致 keychain 保存出错,
Couldn't add the Keychain Item.
A:Hook 修改 accessGroup 即可:
CHDeclareClass(KeychainItemWrapper) CHOptimizedMethod2(self, id, KeychainItemWrapper, initWithIdentifier, NSString*, identifier, accessGroup, NSString*, accessGroup) { return CHSuper2(KeychainItemWrapper, initWithIdentifier, identifier, accessGroup, nil); } CHConstructor{ CHLoadLateClass(KeychainItemWrapper); CHClassHook2(KeychainItemWrapper, initWithIdentifier, accessGroup); }