MonkeyDev(一):官方文档

前言

今天(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 TweakLogos Tweak or Command-line Tool

    If you don’t have a jailbreak device, you can create a MonkeyApp project to debug and hook third-party application
    home.png
    Let’s start !!!

    这是一个为越狱和非越狱开发人员准备的工具,主要包括四个模块:

  • Logos Tweak(用于:越狱开发)

    使用 Theos 提供的 logify.pl 工具将 *.xm 文件转成 *.mm 文件进行编译,集成了 CydiaSubstrate,可以使用 MSHookMessageExMSHookFunctionHook OC 函数和指定地址

  • CaptainHook Tweak(用于:越狱开发)

    使用 CaptainHook 提供的头文件进行 OC 函数的 Hook 以及属性的获取

  • Command-line Tool(用于:越狱开发)

    可以直接创建运行于越狱设备的命令行工具

  • MonkeyApp(用于:越狱开发 + 非越狱开发)

    这是自动给第三方应用集成 RevealCycript 和注入 dylib 的模块,支持调试 dylib 和第三方应用,支持 Pod 给第三方应用集成 SDK,只需准备一个砸壳后的 ipa 或者 app 文件即可

安装

  • 环境要求

    使用工具前,请确保如下几点:

    1. 安装最新的 Theos

      sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
      
    2. 安装 ldid(如果在安装 Theos 的过程中安装了 ldid,则跳过)

      brew install ldid
      
    3. 配置免密码登录越狱设备(如果没有越狱设备,则跳过)

      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 提供的模块:
    script_1520948902020.png
    选择相应的项目类型,就可以创建对应的项目

  • Logos Tweak

    Logos Tweak 项目的结构如下所示(这里创建的项目名称正好为 logos):
    WX20170713-192219.png
    代码写在 logos.xm 文件中,具体语法看 Logos,写完之后脚本会自动将其转成 logos.mm 文件的内容,然后编译

    其中几个文件的解释如下:

    1. control:这个文件是用来配置生成 deb 包的一些信息,比如版本号、说明、作者等等
    2. logos.plist:这个文件是用来指定注入的目标进程,一般填入目标进程的 BundleID 即可
    3. 如果需要在安装之前或者之后进行某些操作的话,可以在 DEBIAN 文件夹下面增加 preinst 脚本(在安装之前执行)、postinst 脚本(在安装之后执行)、prerm 脚本(在卸载之前执行)、postrm 脚本(在卸载之后执行),记得要赋予脚本可执行的权限!
    4. 这里的 Package 文件夹就相当于安装到目标设备之后的根目录,所以要增加什么文件到目标设备都可以在 Package 文件夹下面创建对应的文件或者文件夹!

    项目会自动链接 CydiaSubstrate.framework,无需再手动链接

    项目相关的一些配置在 Build Settings 的最下面(User-Defined),如下:
    script_1520949131335.png
    具体含义见:配置说明

    Debug 模式安装:
    按快捷键 Command + B 就会自动安装到手机

    Release 模式安装:
    按快捷键 Command + Shift + i 即可。不过这种方式安装是不会看到 Log 的哦 ~~

    查看 Log 输出:

    1. 安装 libimobiledevice 工具:
      brew install libimobiledevice
      
    2. 使用如下命令查看 Log 输出:
      idevicesyslog | grep 'xxx'
      
    3. 或者使用自带的 console.app 程序查看
  • CaptainHook Tweak 和 Command-line Tool

    创建和配置与 Logos Tweak 差不多

    Logos Tweak 和 CaptainHook Tweak 都支持通过 CocoaPods 的方式集成 SDK,不过记得要以静态库的方式集成!

配置说明

设置项意义
MonkeyDevBuildPackageOnAnyBuild每次 Build 都生成 deb 包
MonkeyDevCopyOnBuildBuild 时将 deb 包拷贝到目标设备的 /var/root/MonkeyDevBuilds/ 目录
MonkeyDevDeviceIP目标设备的 IP 地址,默认 USB 连接,localhost
MonkeyDevDevicePort目标设备的端口,默认 22
MonkeyDevDevicePassword目标设备的 ssh 登录密码,默认为空,使用免密码登录
MonkeyDevInstallOnAnyBuild每次 Build 都将 deb 安装到目标设备
MonkeyDevInstallOnProfiling点击 Profile 才将 deb 安装到目标设备
MonkeyDevKillProcessOnInstall安装的时候杀掉指定的进程,填写进程名
MonkeyDevClearUiCacheOnInstall安装时 clear uicache
MonkeyDevPathMonkeyDev 的安装路径,默认为 opt/MonkeyDev,不用修改
MonkeyDevTheosPathTheos 的安装路径,默认为 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
    script_1520951543386.png
    然后填写 Product Name,对于非越狱设备可以不用管 Target App,如果是越狱设备的话可以在 Target App 填写目标 App 的名字或者 BundleID,工具将会自动使用 frida-ios-dump 提取 ipa 文件(注意:需要先按 frida-ios-dump repo 的 README 配置好环境!),如下所示:
    script_1520951668347.png
    另外 /opt/MonkeyDev/bin/dump.py 里面可以指定 IPPortPassword

    创建完成之后,你会得到一个这样的工程:
    monkeyapp02.png
    这里我创建的项目名字就是 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.frameworklibcycript.dylib,如果选择 Release 编译的话是不会集成的

  • 拖入编译

    我准备了一个砸壳了的 ipa 文件,然后我右键项目里面的 TargetApp 文件夹 Show in Finder,把 ipa 文件拖入下面的位置(当然拖入 app 文件也是可以的):
    putipa.png
    或者支持直接将文件拖到 Xcode 项目的 TargetApp 分组下面

    Xcode 8 需要另外指定一下依赖,选择 Build Phases,点击 Target Dependencies 增加需要注入的动态库即可。如下:
    WX20170726-142910.png
    然后编译运行,打开电脑的 Reveal,就可以看到界面了:
    script_1499874140165.png
    Cycript 下载 SDK,然后进去 SDK 目录运行如下命令,Cycript 查看界面也没有问题:
    script_1499874354169.png
    这里 Cycript 默认端口是 6666

  • 更多功能:动态库调试

    MonkeyAppDylib.m 文件中写了自己的代码之后就可以直接下断点调试,效果如下:
    script_1499876622854.png
    MonkeyAppDylib.xm 文件也支持动态调试,在文件左侧点击下断点即可,第一次由于后缀 Xcode 不识别,下的断点不会显示出来,但是断点是生效的!在右侧将 MonkeyAppDylib.xm 文件类型改成 Objective-C++,然后重新打开文件或者重启 Xcode,效果如下:
    WX20170811-163403.png

  • 更多功能:Demo App

    MonkeyApp 在不拖入 .app 或者 .ipa 的情况下,会有一个默认的 App,以供读者自己测试,大概是这个样子····
    script_1520952133766.png
    你可以自己修改 MonkeyAppDylib.m 里面的代码,这个是笔者针对 Demo 写的例子啦,另外需要注意的是 MonkeyApp 里面都是 ARC,所以网上很多 MRC 的写法是有问题的,多多参考笔者的例子:https://github.com/AloneMonkey/WeChatPod

    CHDeclareClass(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 最下面开启该功能
    script_1501338682847.png
    开启后 Build 时会自动进行 class-dump 的操作,然后会在项目的目录下生成一个头文件的文件夹:
    script_1501338850485.png

  • 更多功能:restore-symbol

    一般应用发布后调试堆栈是没有符号信息的,但是由于 OC 语言的特性,需要保存类名和方法名,所以可以根据具体方法的地址填写到符号表中,还原符号表。具体可以阅读文章 iOS 符号表恢复 & 逆向支付宝

    开启该功能的方式和开启 class-dump 一样

  • 更多功能:方法跟踪日志

    增加对方法跟踪的日志打印,代替烦人的 logify.pl,只需配置一下即可,在新建项目中找到 MDConfig.plist

    1. ENABLE:设置为 YES 开启方法跟踪,默认为 NO
    2. CLASS_LIST:设置需要跟踪的类或指定的方法,如果是对整个类进行跟踪只用写类名,对类里面特定的方法需要再加一个 Array 数组加上方法名,参考默认的写法

    methodtraceconfig.png
    主要代码来自 qhd 的 ANYMethodLog

    注意:新版已经迁移到 OCMethodTrace,请到项目主页查看相关用法

  • 更多功能:默认集成的库

    本工具会默认集成 RevealServer.frameworklibcycript.dylib,em……

    集成的 RevealServer.framework 是最新版本的,所以你可能需要最新的 Reveal,否则使用自己的 RevealServer.framework 替换掉 /opt/MonkeyDev/frameworks 下面的 RevealServer.framework

    使用 Release 编译生成将不会集成 RevealCycript

  • 更多功能:增加自己的库

    首先将需要注入的 dylib 或者 framework 按下面的方式拷贝到 frameworks 目录下:
    WX20180328-155346.png
    然后在下图的位置 add 进去,emmm… 就可以了
    script_1499874870474.png
    静态库的话,直接增加到上面,指定 search path 就可以了,和正常开发没啥区别 …

    注意动态库本身的 install_path,可以通过 install_name_tool -id 修改其为 @executable_path/Frameworks/xxxxx

  • 更多功能:集成网络 cy 脚本

    通过配置 CycriptConfig.plist 可以导入从网络下载的 cy 脚本,比如通过如下的配置:
    mdconfig02.png
    LoadAtLaunch:表示是否在启动的时候默认加载脚本,默认加载的脚本就不用再 @import xxx 导入,可以直接使用。如果不是默认加载的脚本就需要 @import xxx 导入,xxx 就是图中的 key,比如 @import md

    priority:表示加载的优先级,数字越小优先级越高,比如某些脚本需要依赖其它脚本就需要调整优先级,让被依赖的脚本先加载

    contenturl:脚本可以直接写到 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 中,但是自己集成起来也是非常简单的,就两步:

    1. FridaGadget.dylib 下载动态库,添加到 App 最后的 Copy Files 里面:
      script_1505924584169.png
    2. FridaGadget.dylib 链接到 MonkeyDev 注入动态库的依赖里面:
      script_1505924661079.png

    启动日志有:Frida: Listening on 127.0.0.1 TCP port 27042 就是集成成功

  • 更多功能:增加资源

    把你需要嵌入的 bundle 资源和 storyboard 资源拷贝到这个目录就可以了哦 ~
    WX20170717-163142.png
    upadte:更新增加资源的方式,直接往 MonkeyApp 里面增加资源即可,比如新建 test.plist 文件选择 MonkeyApp 的 Target,保证要增加的资源在如下列表中:
    WX20170906-140842.png

  • 更多功能:更改名字和 BundleID

    如果需要更改重签应用的显示名字和 BundleID 可以在 Xcode 设置即可,想使用原来的 BundleID 进行重签,设置 Build Settings 里面的 MONKEYDEV_DEFAULT_BUNDLEIDYES
    script_1516102997766.png

  • 更多功能:生成 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
    
  • 编译参数修改

    1. 如果你拖入的应用,砸壳的架构和安装设置的架构不一致的话,比如只砸了 armv7 的架构,但是要安装到 arm64 的机器,就需要把 Pod 进来的所有有源码的库的 Build SettingsBuild Active Architecture Only 的 Debug 改成 No,包括 Pods-xxxxDylib 这个 Target

    2. 直接从XX助手下载的越狱应用,不需要进行 (1) 的修改,直接运行!

  • 运行效果
    script_1500909967471.png

  • 非越狱插件 Pod 化

    既然支持 Pod,当然也支持将自己的插件传到 Pod 上,然后通过 Pod 安装,简直就是一个非越狱平台的插件商店啊!!!

    笔者这里自己弄了一个私有 Pod,编辑 Podfile

    source 'https://github.com/AloneMonkey/MonkeyDevSpecs.git'
    
    use_frameworks! 
    
    target 'MonkeyPodDylib' do
        pod 'MonkeyDevPod'
    end
    

    然后安装,修改 Pods-MonkeyPodDylib - Build SettingsBuild Active Architecture Only 的 Debug 改成 No

    注释 MonkeyPodDylib.m 文件的:

    CHConstructor{
        CHLoadLateClass(CustomViewController);
        CHClassHook(0, CustomViewController, getMyName);
    }
    

    因为 MonkeyDevPod 这个库也是修改屏幕显示的返回字符串为 MonkeyDevPod,运行即可看到效果

  • 欢迎大家往我的私有 CocoaPods 仓库提交自己的非越狱插件哦 ~~

  • https://github.com/AloneMonkey/MonkeyDevSpecs

非越狱插件 Pod

本节主要介绍如何将自己的非越狱插件上传到 CocoaPods,然后通过 Pod 一键安装!

注意:自己开发 Pod 的时候,文件命名都带上前缀,以防止多个 Pod 出现同一个头文件的情况!

  • 创建工程

    MonkeyDev 本身提供了创建 Pod 的项目,点击 File -> New -> Project,在 iOS 的最下面选择 MonkeyPod 创建新的项目如下:
    script_1501592402370.png
    创建出来的项目目录结构如下所示:
    WX20170908-203650.png
    可以将你通过 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 代码上面!
    script_1501594823649.png

  • MonkeyApp 和 MonkeyPod 结合使用

    如果我想要边写 Pod 边开发插件可不可以呢? 答案是当然可以! MonkeyApp 和 MonkeyPod 完美结合!

    首先新建一个 MonkeyApp 工程,然后新建一个 MonkeyPod 工程,然后把 MonkeyPod 工程拖到 MonkeyApp 工程,如图:
    script_1501599620053.png
    然后找到 MonkeyApp 的 Target Dependencies 增加依赖 MonkeyPod (MonkeyPod)
    并在 Embed Libraries 增加库 MonkeyPod.framework
    script_1501599713451.png
    最后在 MonkeyApp 的动态库 MonkeyAppDylibLink Binary With Libraries 里面链接 MonkeyPod.framework
    script_1501599769928.png
    运行就可以将 MonkeyPod 注入到 MonkeyApp,实现边写 Pod 边写插件!!!

    玩的开心 ~~

  • 欢迎大家往我的私有 CocoaPods 仓库提交自己的非越狱插件哦 ~~

  • https://github.com/AloneMonkey/MonkeyDevSpecs

Mac 插件

MonkeyDev 现已支持给 macOS 应用写插件啦!!!

  • ① 首先新建工程,在 macOS 模块最下面选择 MonkeyAppMac:
    script_1502381918955.png

  • ② 将需要注入的目标文件拖入 TargetApp 文件夹:
    script_1502382008577.png

  • 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 进程
    script_1502382324737.png
    然后在 new_QQMessageRevokeEngine_handleRecallNotify_isOnline 这个方法下一个断点,撤回一条消息,即可断下来看到堆栈
    script_1502382487670.png

  • 注意:本工具暂时还不支持本身有反调试的应用,比如百度网盘,如要调试可以使用 AntiAntiDebug 脚本启动时反反调试

    笔者相关文章:一篇文章走进 Mac 逆向的世界

越狱插件 Xcode 调试

之前的 Logos Tweak 和 CaptainHook Tweak 工程是不支持 Xcode 直接调试的,只能通过打印 log 看效果,后面可以通过 MonkeyApp 直接进行调试方便了很多,但是每次调试都要重新安装应用其实还是挺麻烦的,这里介绍一种使用 Xcode 直接调试 Logos Tweak 和 CaptainHook Tweak 工程的方法

由于 Xcode 使用的是默认的 /Developer/usr/bin/debugserver 进行调试的,所以被调试的应用要是自己重签名安装的,可以使用 MonkeyApp 重签安装下就好了

具体的流程如下:

  1. 重签安装被调试的应用
  2. 创建 Logos Tweak 或者 CaptainHook Tweak 工程,编写代码,指定 BundleID,设置断点
  3. 点击 Xcode 菜单栏 -> Debug -> Attach to Process by PID or Name
  4. 输入进程名或者 pid
    WX20180228-165548.png
  5. 上面填写进程名可以进行启动调试,然后打开被调试的应用,就会自动附加并且断在断点的位置(如果触发了的话)
  6. 接下来就可以进行调试开发了,修改代码之后 Command + B 安装,然后重复第 3 步

Logos Tweak Project Debug 的效果图如下:
WX20180228-170205.png
CaptainHoook Tweak Project Debug 的效果图如下:
WX20180228-170349.png

更新日志

  • 使用新的 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 下不再集成 CycriptReveal,方便个人使用

  • 增加 monkeyparser(2017/12/15)

    使用 monkeyparser 替换 restore-symboloptoolunsign

    在无法使用免密码登录的情况下,支持设置 ssh 密码

    BundleIDaaa 使用应用原来的 BundleID 进行重签

  • 增加统一的插件设置界面(2017/10/30)

    增加统一的插件设置界面,参考 WeChatPodMDSettingCenter 的使用

  • 增加方法执行追踪日志(2017/09/06)

    打印方法的调用顺序和参数

    优化增加资源的方式,直接在 MonkeyApp 增加资源

  • 增加 Mac 应用插件集成(2017/08/11)

    在 macOS 模板下增加 MonkeyAppMac,给 macOS 应用集成插件

    增加非越狱插件使用 Logos 编写

  • 去掉自带 substrate(2017/08/04)

    去掉非越狱自带 CydiaSubstrateJRSwizzle,都自己从 CocoaPods 安装

    私有 Pod 地址 https://github.com/AloneMonkey/MonkeyDevSpecs

  • 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 TweakLogos TweakCommand-line Tool

    自动链接 CydiaSubstrate.framwork

    默认设备 IP 和端口

Q & A

  • one

    Q:一个工程放了一个应用后,再放另外一个应用,第一个应用的内容没有删除?(已解决)

    A:同一个工程要放不同的应用,要先 Product - Clean 一下,快捷键是 Command + Shit + K

  • two

    Q:编译提示找不到 libxxxDylib.dylib

    A:先指定一下依赖,选择 Build Phases,点击 Target Dependencies 增加需要注入的动态库即可。如下:
    WX20170726-142910.png
    如果已增加依赖,则切换到动态库单独编译,应该是有错误还没解决

  • 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 拷贝到这个目录就可以了哦 ~
    WX20170717-163142.png

  • 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 下面哦!怎么看是静态库还是动态库呢?

    1. otool -hv xxxx(可执行文件)
    2. 静态库会显示一堆 OBJECT
    3. 动态库会显示 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
    

    或者

    1. brew install ruby@2.0
    2. /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);
    }
    
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值