Skip to content

非越狱App集成

AloneMonkey edited this page Jun 26, 2020 · 50 revisions

选真机编译运行!

准备好砸壳的ipa或者app

第一步是准备好砸壳的ipa或者app,可以从某助手下载越狱应用(下载的也有没砸壳的QAQ)。

创建MonkeyApp项目

点击File - New - Project...创建iOS项目,选择MonkeyApp

image

然后填写Product Name,对于非越狱设备可以不用管Target App,如果是越狱设备的话可以在Target App填写目标App的名字或者bundle id,工具将会自动使用frida-ios-dump提取ipa文件(注意:要先按frida-ios-dump repo的README配置好环境!),如下所示:

image

另外/opt/MonkeyDev/bin/dump.py里面可以指定ip、port以及password。

创建完成之后,你会得到一个这样的工程:

image

这里我创建的项目名字就是MonkeyApp,所以下面对应的都是MonkeyApp,你自己创建的由你的项目名字而定!

MonkeyAppDylib这个是将被注入目标App的动态库,你自己要hook的代码可以在MonkeyAppDylib.m文件里面写,我在里面写了一些Demo代码,支持OC runtime的HOOK,C函数的fishhook。还支持theos logtweak的写法! 直接写在MonkeyAppDylib.xm文件文件即可。

Config 这个是cycript的一些脚本下载以及methodtrace配置代码。

LLDBTools 这个是用于LLDB调试的代码,比如po pviews()

AntiAntiDebug 这个里面是反反调试的代码。

fishhook 这个是自动集成的fishhook模块。

创建的项目已经自动集成了RevealServer.frameworklibcycript.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不识别,下的断点不会显示出来,但是断点是生效的!在右侧将文件类型改成Object C++ 重新打开文件或重启Xcode,效果如下:

Demo App

MonkeyApp不拖入App或者ipa的情况下,会有一个默认的App,以供读者自己测试,样子大概是这个样子····

image

你可以自己修改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最下面开启该功能。

image

开启后build会自动进行class-dump的操作,然后会在项目的目录下生成一个头文件的文件夹:

image

restore-symbol

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

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

方法跟踪日志

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

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

主要代码来自qhd的ANYMethodLog

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

默认集成的库

本工具会默认集成RevealServer.frameworklibcycript.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脚本,比如通过如下的配置:

image

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里面:

image

  1. 将FridaGadget.dylib链接到MonkeyDev注入动态库的依赖里面:

image

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

增加资源

把你需要嵌入的Bundle资源和storyboard拷贝到这个目录就可以了哦~

upadte: 更新增加资源方式,直接往MonkeyApp里面增加资源即可,比如新建test.plist文件选择MonkeyApp的Target,保证要增加的资源在如下列表中:

更改名字和bundleid

如果需要更改重签应用的显示名字和bundle id可以在Xcode设置即可,想使用原来的bundle id进行重签,设置build settings里面的MONKEYDEV_DEFAULT_BUNDLEID为YES。

image

生成IPA

运行之后在源代码的LatestBuild目录双击createIPA.command即可生成IPA文件。