├── 机审.xmind
├── h5马甲包.md
├── 逆向必备知识.md
├── monkeyDev功能.md
├── 逆向block分析.md
├── 静态分析.md
├── 代码混淆.md
├── frida-ios-dump集成的坑.md
├── cy
├── MS.cy
└── myMd.cy
├── Theos开发.md
├── CaptainHook用法.md
├── lldb学习.md
└── Cycript用法.md
/机审.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blaceman/myRe/HEAD/机审.xmind
--------------------------------------------------------------------------------
/h5马甲包.md:
--------------------------------------------------------------------------------
1 | ### h5马甲包上线规划
2 |
3 | #### 前言: 由于前阶段提马甲包经常被拒,苹果一系列不规律行为的结果,发现主要原因并不是代码混淆,或者素材原因造成的。
4 |
5 | #### 先总结一下审查上架的流程:机审->分析报告->人审->上架。
6 |
7 | 下图完整描述整个流程:
8 |
9 | 
10 |
11 | ####
--------------------------------------------------------------------------------
/逆向必备知识.md:
--------------------------------------------------------------------------------
1 | 逆向必备知识
2 |
3 | + [ssh](https://zh.wikipedia.org/wiki/Secure_Shell):网络协议来实现身份验证。iOS8,9需要在cydia安装openssh。用法:mac电脑 与苹果手机需要在同一wifi下,打开终端:输入ssh root@192.168.1.101(手机IP地址,默认密码为alpine)
4 | + 文件目录:
5 | + 文件权限:所有者,组,其他人。r w x分别为读写执行权限。例如chmod 755 testFile设置testFile 所有者为rwx 组其他人为读rw权限
6 |
7 | + 逆向工具:dumpdecrypted、class-dump、Charles、Reveal、Cycript、LLDB、MonkeyDey等
8 | + 应用构建过程:
--------------------------------------------------------------------------------
/monkeyDev功能.md:
--------------------------------------------------------------------------------
1 | ## monkeyDev功能
2 |
3 | + # Logos Tweak
4 |
5 | + # CaptainHook Tweak
6 |
7 | + # Command-line Tool
8 |
9 | + `Config` 这个是cycript的一些脚本下载以及methodtrace配置代码。
10 |
11 | + `LLDBTools` 这个是用于LLDB调试的代码,比如`po pviews()`。
12 |
13 | + `AntiAntiDebug` 这个里面是反反调试的代码
14 |
15 | + `fishhook` 这个是自动集成的fishhook模块
16 |
17 | + Reveal
18 |
19 | + [Cycript](http://www.cycript.org/)
20 |
21 | + ## 动态库调试
22 |
23 | + ## class-dump
24 |
25 | + ## restore-symbol
26 |
27 | + ## 方法跟踪日志
28 |
29 | + ## 增加自己的库
30 |
31 | + ## 集成网络cy脚本
32 |
33 | + ## 集成Frida
34 |
35 | + ## 增加资源
36 |
37 | + ## 更改名字和bundleid
38 |
39 | + ## 生成IPA
40 |
41 | + ## 重签名
42 |
43 | + # CocoaPods
--------------------------------------------------------------------------------
/逆向block分析.md:
--------------------------------------------------------------------------------
1 | # 逆向block分析
2 |
3 | ### block的结构
4 |
5 | ```objc
6 | struct __block_impl{
7 | /**
8 | block在内存中也是类NSObject的结构体,
9 | 结构体开始位置是一个isa指针
10 | */
11 |
12 | Class isa;
13 | /** 这两个变量暂时不关心 */
14 | int flags;
15 | int reserved;
16 | /**
17 | 真正的函数指针!!
18 | */
19 | void (*invoke)(...);
20 | ...
21 | }
22 | ```
23 |
24 | + 说明下block中的isa指针,根据实际情况会有三种不同的取值,来表示不同类型的block。其中第2种block在运行时才会出现,我们只关注1、3两种,下面就分析这两种isa指针和block符号地址之间的关联
25 |
26 | + _NSConcreteStackBlock:栈上的block,一般block创建时是在栈上分配了一个block结构体的空间,然后对其中的isa等变量赋值
27 |
28 | + _NSConcreteMallocBlock:堆上的block,当block被加入到GCD或者被对象持有时,将栈上的block复制到堆上,此时复制得到的block类型变为了_NSConcreteMallocBlock
29 |
30 | + _NSConcreteGlobalBlock:全局静态的block,当block不依赖于上下文环境,比如不持有block外的变量、只使用block内部的变量的时候,block的内存分配可以在编译期就完成,分配在全局的静态常量区。
31 |
--------------------------------------------------------------------------------
/静态分析.md:
--------------------------------------------------------------------------------
1 | # 静态分析
2 |
3 | ### Hopper功能
4 |
5 | + X:查看交叉引用
6 | + G:跳转地址
7 | + Modify - Assemble Instruction
8 |
9 | ### IDA常见功能
10 |
11 | + fn + F5 :伪c
12 |
13 | + "Option + T":字符串搜索
14 |
15 | + G:跳转地址
16 |
17 | + 可重复注释:按";"键进行注释。非重复性注释:按":"进行注释
18 |
19 | + 单击目标变量,按N键:变量重命名
20 |
21 | + X:查看交叉引用
22 |
23 | + 伪代码会存在一些10进制,我们要装换为16进制才有意义,单击数字按H键。
24 |
25 | + 单击目标方法或变量,按Y:类型定义
26 |
27 | + C:被解释成数据还原成代码
28 |
29 | + D:机器码转为代码
30 |
31 | + Option -General - Disassembly:显示机器码
32 |
33 | + Control+F:方法搜索
34 |
35 |
36 | ### ARM汇编_概念
37 |
38 | + AARch64
39 |
40 | + EL0-EL3:不同的异常级别。EL为无权限级别,编写的应用一般都运行在EL0
41 | + R0-R30:31个通用寄存器,每个寄存器都有以下两种访问方式
42 | + 64位:X0-X30,其中X30用于调用程序的link register,保存程序调用完的返回地址
43 | + 32位:W0-W30
44 | +
45 |
46 | + SP:堆栈寄存器,x31访问
47 | + PC:保存当前地址的64位的程序计算器
48 | + LR:指向返回地址,对应为x30
49 | + FP:指向栈贞底部,x29看,
50 | + V0-V32:为32个SIMD&FP寄存器,主要用于浮点数运算
51 | + PSTATE:不是寄存器,进程状态的抽象
52 |
53 | ### 栈帧调用过程
54 |
55 |
--------------------------------------------------------------------------------
/代码混淆.md:
--------------------------------------------------------------------------------
1 | ##代码混淆
2 |
3 |
4 |
5 | ###llvm
6 |
7 | ####llvm定义以及原理
8 |
9 | + llvm:
10 |
11 | + 定义:The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.(模块可重用的编译链)
12 | + 主要组成:前端(如gcc,clang) pass 后端
13 | + 前端:获取源代码然后变成某种中间表示
14 | + pass:用来将程序中间表示之间的相互变化,一般情况下用来优化代码。
15 | + 后端:生成实际的机器码
16 |
17 | + 大部分编译器:源代码->前端->pass->后端->机器码
18 |
19 | 
20 |
21 | + llvm不同的是,对于不同语言都有中间表示:
22 |
23 | 
24 |
25 | 当编译器需要支持多种源代码和目标架构时,基于LLVM的架构,设计一门新的语言只需要去实现一个新的前端就行了,支持新的后端架构也只需要实现一个新的后端就行了。其它部分完成可以复用,就不用再重新设计一次了。
26 |
27 | #### 安装llvm
28 |
29 | clang作为前端:
30 |
31 | svn获取:
32 |
33 | ```objc
34 | svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
35 | cd llvm/tools
36 | svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
37 | cd ../projects
38 | svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
39 | cd ../tools/clang/tools
40 | svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
41 |
42 | ```
43 |
44 | 编译:
45 |
46 | ```go
47 | mkdir build
48 | cmake /path/to/llvm/source
49 | cmake --build .
50 | ```
51 |
52 | #### 源码到执行文件
53 |
54 | + 预处理 -> 词法分析 -> Token -> 语法分析 -> AST -> 代码生成 -> LLVM IR -> 优化 -> 生成汇编代码 -> Link -> 目标文件
55 |
56 |
57 |
58 | ### clang
59 |
60 |
--------------------------------------------------------------------------------
/frida-ios-dump集成的坑.md:
--------------------------------------------------------------------------------
1 | # frida-ios-dump集成的坑
2 |
3 |
4 |
5 | 按照http://www.alonemonkey.com/2018/01/30/frida-ios-dump/ 的文章集成frida-ios-dump发现过程并不是很顺利。
6 |
7 | ### 环境配置
8 |
9 | 首先上面也说了该工具基于frida,所以首先要在手机和mac电脑上面安装frida,安装方式参数官网的文档:
10 |
11 | 越狱手机的安装frida:
12 |
13 | + 打开cydia
14 | + 添加源:`http://build.frida.re`
15 | + 安装 [Frida](https://www.frida.re/docs/ios)
16 |
17 |
18 |
19 | mac电脑
20 |
21 | + pip install frida-tools
22 | + sudo mkdir /opt/dump && cd /opt/dump && sudo git clone https://github.com/AloneMonkey/frida-ios-dum
23 | + open ~/.zrshrc 添加 alias dump.py="/opt/dump/frida-ios-dump/dump.py"这一行
24 |
25 |
26 |
27 |
28 |
29 | 到这里一切都很顺利
30 |
31 |
32 |
33 | frida-ps -U也没问题,但dump.py **却显示 纳闷~
34 |
35 | ```
36 | Traceback (most recent call last):
37 | File "/opt/dump/frida-ios-dump/dump.py", line 10, in
38 | import frida
39 | File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/frida/__init__.py", line 24, in
40 | raise ex
41 | ImportError: No module named _frida
42 | ```
43 |
44 |
45 |
46 | 原来是pip安装到frida到python3
47 |
48 | 而mac默认是python2启动的
49 |
50 | 解决办法
51 |
52 | + which python 查看python启动路径 我的是:/usr/local/bin/python
53 | + which python3 查看python3启动路径 我的是:/usr/local/bin/python3
54 | + unlink /usr/local/bin/python
55 | + ln -s /usr/local/bin/python3 /usr/local/bin/python
56 |
57 | ok,现在可以dump.py **了,但却出现python2语法错误,修复后就可以愉快的dump了。
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/cy/MS.cy:
--------------------------------------------------------------------------------
1 | /* Cydia Substrate - Powerful Code Insertion Platform
2 | * Copyright (C) 2008-2015 Jay Freeman (saurik)
3 | */
4 |
5 | (function(ms) {
6 |
7 | let GetLibraryPath = function() {
8 | let handle = dlopen(NULL, RTLD_NOLOAD);
9 | if (handle == null)
10 | return null;
11 |
12 | try {
13 | let CYListenServer = dlsym(handle, "CYListenServer");
14 | if (CYListenServer == null)
15 | return null;
16 |
17 | let info = new Dl_info;
18 | if (dladdr(CYListenServer, info) == 0)
19 | return null;
20 |
21 | let path = info->dli_fname;
22 | let slash = path.lastIndexOf('/');
23 | if (slash == -1)
24 | return null;
25 |
26 | path = path.substr(0, slash);
27 |
28 | GetLibraryPath = function() {
29 | return path;
30 | };
31 |
32 | return GetLibraryPath();
33 | } finally {
34 | dlclose(handle);
35 | }
36 | };
37 |
38 | var libcycript = dlopen(GetLibraryPath() + "/libcycript.dylib", RTLD_NOLOAD);
39 | if (libcycript == null) {
40 | return;
41 | }
42 |
43 | var libsubstrate = dlopen(GetLibraryPath() + "/libsubstrate.dylib", RTLD_GLOBAL | RTLD_LAZY);
44 | if (libsubstrate == null) {
45 | return;
46 | }
47 |
48 | extern "C" void *MSGetImageByName(const char *);
49 | extern "C" void *MSFindSymbol(void *, const char *);
50 | extern "C" void MSHookFunction(void *, void *, void **);
51 | extern "C" void MSHookMessageEx(Class, SEL, void *, void **);
52 |
53 | var slice = Array.prototype.slice;
54 |
55 | ms.HookFunction = function(func, hook, old) {
56 | var type = typeid(func);
57 |
58 | var pointer;
59 | if (old == null || typeof old === "undefined")
60 | pointer = null;
61 | else {
62 | pointer = new (typedef void **);
63 | *old = function() { return type(*pointer).apply(null, arguments); };
64 | }
65 |
66 | MSHookFunction(func.valueOf(), type(hook), pointer);
67 | };
68 |
69 | ms.HookMessage = function(isa, sel, imp, old) {
70 | var type = sel.type(isa);
71 |
72 | var pointer;
73 | if (old == null || typeof old === "undefined")
74 | pointer = null;
75 | else {
76 | pointer = new (typedef void **);
77 | *old = function() { return type(*pointer).apply(null, [this, sel].concat(slice.call(arguments))); };
78 | }
79 |
80 | MSHookMessageEx(isa, sel, type(function(self, sel) { return imp.apply(self, slice.call(arguments, 2)); }), pointer);
81 | };
82 |
83 | for(var k in ms) {
84 | if(ms.hasOwnProperty(k)) {
85 | var f = ms[k];
86 | if(typeof f === 'function') {
87 | Cycript.all[k] = f;
88 | }
89 | }
90 | }
91 |
92 | })(exports);
93 |
--------------------------------------------------------------------------------
/Theos开发.md:
--------------------------------------------------------------------------------
1 | # Theos开发
2 |
3 | ### 语法:
4 |
5 | + %hook:hook住一个classs,必须以%end结尾。例子:
6 |
7 | ```objective-c
8 | %hook MYView
9 | - (void)buttonAction:(id)sender{
10 | %orig(@"我的button");
11 | }
12 | %end
13 | ```
14 |
15 | + %orig:执行原来的函数实现,此外,还可以利用`%orig`更改原始函数的参数。例子如上:
16 |
17 | + %log:打印
18 |
19 | + %ground:将`%hook`分组,不属于某个自定义group的`%hook`都会被隐式归类到`%group_ungrouped`中。例子:
20 |
21 | ```go
22 | group iOS1Hook
23 | %hook iOS1Class
24 | - (id)iOS1Method {
25 | id result = %orig;
26 | NSLog(@"This class & method only exist in iOS 1.");
27 | return result;
28 | }
29 | - (id)iOS2Method {
30 | id result = %orig;
31 | NSLog(@"This class & method only exist in iOS 1.");
32 | return result;
33 | }
34 | %end
35 | %end // iOS1Hook
36 |
37 | %hook SpringBoard
38 | -(void)powerDown {
39 | %orig;
40 | }
41 | %end //%group_ungrouped
42 | ```
43 |
44 | + %init:该指令用于初始化某个`%group`,必须在`%hook`或`%ctor`内调用,参数为%group名,默认是group_ungrouped。例子:
45 |
46 | ```go
47 | - (void)applicationDidFinishLaunching:(id)application {
48 | %orig;
49 | %init; // Equals to %init(_ungrouped)
50 | if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0 &&
51 | kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0)
52 | %init(iOS7Hook);
53 |
54 | if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0)
55 | %init(iOS8Hook);
56 | }
57 | %end
58 | ```
59 |
60 | + %ctor:tweak的constructor,完成初始化工作;如果不显示定义,Theos会自动生成一个`%ctor`,并在其中调用`%init(_ungrouped)`,如果需要默认调用其他%group或者MSHookFunction就要显示调用:
61 |
62 | ```go
63 | #ifndef kCFCoreFoundationVersionNumber_iOS_8_0
64 | #define kCFCoreFoundationVersionNumber_iOS_8_0 1140.10
65 | #endif
66 | %ctor
67 | {
68 | %init;
69 | if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0 &&
70 | kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0)
71 | %init(iOS7Hook);
72 | if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0)
73 | %init(iOS8Hook);
74 |
75 | MSHookFunction((void *)&AudioServicesPlaySystemSound,
76 | (void *)&replaced_AudioServicesPlaySystemSound,
77 | (void **)&original_AudioServicesPlaySystemSound);
78 | }
79 | ```
80 |
81 |
82 | + %c :生成一个对象。例子:
83 |
84 | ```go
85 | MYView *myView = [[%c(MYView) alloc]init];
86 | ```
87 |
88 | + %new:给一个类增加方法。 其中v@:@代表v:void @:调用者 (:):SEL @:参数类型。例子:
89 |
90 | ```go
91 | %new(v@:@)
92 | - (void)printMessage:(NSString )message{
93 |
94 | };
95 |
96 | ```
97 |
98 | + 如果需要用到源代码的属性或者方法,可以自己新建一个类的.h文件,把属性和方法申明到.h文件,就可以愉快的用啦。
99 |
100 | + 其他的参考[wifi](http://iphonedevwiki.net/index.php/Logos)
101 |
102 | ### 安装:[iOS逆向工程之Theos](https://www.cnblogs.com/ludashi/p/5714095.html)
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/cy/myMd.cy:
--------------------------------------------------------------------------------
1 | (function(utils) {
2 |
3 | utils.constants = {
4 | APPID: NSBundle.mainBundle.bundleIdentifier, //id
5 | APPPATH: NSBundle.mainBundle.bundlePath, //资源路径
6 | APPHOME: NSHomeDirectory(), //沙盒
7 | APPDOC: NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0],
8 | APPLIBRARY: NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0],
9 | APPCACHE: NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]
10 | };
11 |
12 | utils.pviews = function(){
13 | return UIApp.keyWindow.recursiveDescription().toString(); //打印视图层次
14 | };
15 |
16 | utils.pvcs = function(){ //打印当前控制器
17 | return UIWindow.keyWindow().rootViewController._printHierarchy().toString();
18 | };
19 |
20 | utils.rp = function(target){//打印响应者 nextResponder
21 | var result = "" + target.toString();
22 | while(target.nextResponder){
23 | result += "\n" + target.nextResponder.toString();
24 | target = target.nextResponder;
25 | }
26 | return result;
27 | };
28 |
29 | utils.pactions = function(target){ //打印actionsForTarget;
30 | var result = '';
31 | var objs = target.allTargets.allObjects();
32 | for(var i = 0; i < objs.length; i++){
33 | var actions = [target actionsForTarget:objs[i] forControlEvent:0];
34 | result += objs[i] + " " + [actions componentsJoinedByString:@","];
35 | }
36 | return result;
37 | }
38 |
39 |
40 | utils.loadFramework = function (target) { //加载资源路径
41 | var h="/System/Library/",t="Frameworks/"+target+".framework";
42 | return [[NSBundle bundleWithPath:h+t]||
43 | [NSBundle bundleWithPath:h+"Private"+t] load];
44 | }
45 |
46 |
47 | utils.tryPrintIvars = function tryPrintIvars(a){ //打印属性 或者*实例对象
48 | var x={};
49 | for(i in *a)
50 | {
51 | try{ x[i] = (*a)[i]; } catch(e){}
52 | }
53 | return x;
54 | }
55 |
56 |
57 | utils.printMethods = function printMethods(className, isa) { //打印方法,第一个传类对象字符串,第二个可不传。
58 | var count = new new Type("I");
59 | var classObj = (isa != undefined) ? objc_getClass(className)->isa :
60 | objc_getClass(className);
61 | var methods = class_copyMethodList(classObj, count);
62 | var methodsArray = [];
63 | for(var i = 0; i < *count; i++) {
64 | var method = methods[i];
65 | methodsArray.push({selector:method_getName(method),
66 | implementation:method_getImplementation(method)});
67 | }
68 | free(methods);
69 | return methodsArray;
70 | }
71 |
72 |
73 |
74 |
75 | for(var k in utils.constants) { //引入时打印对象变量
76 | Cycript.all[k] = utils.constants[k];
77 | }
78 |
79 | for(var k in utils) {//引入时打印对象方法
80 | if(utils.hasOwnProperty(k)) {
81 | var f = utils[k];
82 | if(typeof f === 'function') {
83 | Cycript.all[k] = f;
84 | }
85 | }
86 | }
87 | })(exports);
88 |
--------------------------------------------------------------------------------
/CaptainHook用法.md:
--------------------------------------------------------------------------------
1 | # CaptainHook用法
2 |
3 |
4 |
5 | ### 基础设置
6 |
7 | + ## #import 就可以用啦,很方便
8 |
9 |
10 |
11 | ### 用法
12 |
13 | + 声明一个类:在你使用CaptainHook之前必须先声明一个类。例子:
14 |
15 | ```objc
16 | #import //导入头文件
17 | CHDeclareClass(NSString); //声明NSString类
18 | CHConstructor { //CHConstructor 表示在二进制被加载后,立即执行CHConstructor代码块的内容
19 | CHLoadLateClass(NSString);//加载NSString 类
20 | }
21 | ```
22 |
23 |
24 |
25 | ### 方法挂钩:
26 |
27 | + 先使用**CHMethod**声明一个函数,然后再用**CHHook**钩挂。例子:
28 |
29 | ```objective-c
30 | //标准方法挂钩
31 | #import //导入头文件
32 | CHDeclareClass(NSString); //声明类
33 | CHMethod(2, void, NSString, writeToFile, NSString *, path, atomically, BOOL, flag)//声明一个方法来挂钩。参数1:代表两个参数相当于于CHMethod2(),参数2:为返回类型,参数3:为哪个类的方法,参数4:方法名,参数5:参数的类型,参数6:参数类型名字,参数7:第2个参数的方法名,参数7:参数类型,参数8:参数类型的名字
34 | {
35 | NSLog(@"Writing string to %@: %@", path, self);
36 | CHSuper(2, NSString, writeToFile, path, atomically, flag);//调用原来的实现
37 | }
38 |
39 | CHConstructor //
40 | {
41 | CHLoadClass(NSString);
42 | CHHook(2, NSString, writeToFile, atomically);//挂钩方法。
43 | }
44 |
45 |
46 | ```
47 |
48 |
49 | + CHDeclareMethod挂钩
50 |
51 | ```objective-c
52 | //覆盖,简单挂钩,无法控制挂钩的时机,也可以作为增加方法使用
53 | #import
54 | CHDeclareClass(NSString);
55 | CHDeclareMethod(2, void, NSString, writeToFile, NSString *, path, atomically, BOOL, flag)
56 | {
57 | NSLog(@"Writing string to %@: %@", path, self);
58 | CHSuper(2, NSString, writeToFile, path, atomically, flag);
59 | }
60 | ```
61 |
62 |
63 | + 运行时注入新类:
64 |
65 | ```objc
66 | //可以使用CHRegisterClass宏在运行时创建新类:
67 | #import
68 | CHDeclareClass(NSObject);
69 | CHDeclareClass(MyNewClass);
70 | CHMethod(0, id, MyNewClass, init)
71 | {
72 | if ((self = CHSuper(0, MyNewClass, init))) {
73 | NSLog(@"Initted MyNewClass");
74 | }
75 | return self;
76 | }
77 |
78 | CHConstructor
79 | {
80 | CHAutoreleasePoolForScope();
81 | CHLoadClass(NSObject);
82 | CHRegisterClass(MyNewClass, NSObject) {
83 | CHHook(0, MyNewClass, init);
84 | }//创建新类
85 | [CHAlloc(MyNewClass) autorelease];
86 | }
87 | ```
88 |
89 | + 其他
90 |
91 | + CHOptimizedMethod():挂钩实例方法
92 |
93 | + CHOptimizedClassMethod():挂钩类方法
94 |
95 | + CHPropertyRetainNonatomic()增加属性
96 |
97 | ```objective-c
98 | //增加属性
99 | @interface ViewController : NSObject
100 | @property (nonatomic,retain)NSString *newProperty;
101 | @end
102 | CHDeclareClass(ViewController)
103 | CHPropertyRetainNonatomic(ViewCOntroller,NSString*,newProperty,setNewProperty);
104 |
105 | CHConstructor{
106 | CHLoadLateClass(ViewController);
107 | CHHook0(ViewController,newProperty);
108 | CHHook1(ViewController,setNewProperty);
109 | }
110 |
111 | ```
112 |
113 |
114 | ### 简单用法总结:
115 |
116 | + 1.导入#import 头文件
117 | + 2.声明使用的类:CHDeclareClass()
118 | + 3.CHConstructor{}来写加载的类(CHLoadLateClass())
119 |
120 | + 4.CHMethod()、CHOptimizedMethod()、CHOptimizedClassMethod()声明新函数
121 | + 5.CHConstructor{}下挂钩子(CHHook(),)
122 | + 6.CHSuper():调用原方法实现。
--------------------------------------------------------------------------------
/lldb学习.md:
--------------------------------------------------------------------------------
1 | ---
2 | 勿管世间纷闹,勿管处境。静心做人,静心做事。感谢师傅alonemonkey,感谢同行之人的无私奉献。
3 | ---
4 |
5 | # lldb动态调试学习
6 |
7 |
8 |
9 | ### 准备工作(越狱)
10 |
11 | + 越狱真机调试后在/Developer/usr/bin下找到debugserver
12 |
13 | + 复制debugserver到mac上
14 |
15 | + x新建entitlements.plist文件,签名权限:codesign -s - --entiltilements.plist -f debugserver
16 |
17 | ```plist
18 |
19 | ```
20 |
21 |
22 |
23 | com.apple.springboard.debugapplications
24 |
25 | get-task-allow
26 |
27 | task_for_pid-allow
28 |
29 | run-unsigned-code
30 |
31 |
32 |
33 | ```
34 |
35 | + 将debugserver复制回手机 /usr/bin/debugserver
36 | + 打开应用 ps -aux找到进程;
37 | + 附加:根据进程名或id:debugserver *:1234 -a Snapchat(731)
38 | + 然后mac终端输入lldb进去lldb界面
39 | + 然后(iproxy 1234 1234)process connect connect://localhost:1234或process connect connect:手机ip地址:1234 进行连接就ok
40 |
41 |
42 |
43 | + 启动:debugserver -x backboard *:1234 /Applications/MobileSMS.app/MobileSMS
44 |
45 |
46 |
47 | ### lldb常用命令
48 |
49 | + image list -o -f: [序列号] + 模块基地址 + 路径(真正加载的地址)
50 | + 这里说明一下: 内存的真实地址 = 模块的基地址 + ida或hopper查看的地址
51 | + b 内存地址: 或 br s -a 内存地址: (符号还原后: b 方法名): 下断点
52 | + "Control + C" 暂停,终端支持。
53 | + c: 继续
54 | + po :打印对象
55 | + x/s \$x1:将寄存器x1以字符串的方式打印出来
56 | + \$x0 - \$x7: 为寄存器调用的参数, 如果是OC对象\$x0为调用对象,$x1为调用方法。
57 | + memory read -force -f \$sp $fp: 栈参数
58 | + bt: 查看堆栈信息
59 | + register read: 读取寄存器的所有值
60 | + register read \$x0:读取某个寄存器的值
61 | + register write \$x4: 修改寄存器的值
62 | + si:跳到当前指令内部
63 | + ni:跳到当前指令
64 | + finish:返回上层调用栈
65 | + thread return:不用执行下面的代码,之前从当前调用栈返回一个值
66 | + br list: 查看当前列表断点
67 | + br del:删除当前的所有断点
68 | + br del 1.1.1:删除指定编码的断点
69 | + br dis 2.1 使断点2.1失效
70 | + br enable 2.1: 使断点2.1生效
71 | + thread info:输出线程当前信息
72 | + b ptrace -c xxx 满足某个条件后才会中断
73 |
74 | + help "命令名" : 查看命令的详细用法
75 | + apropos "相关命令信息": 搜索相关的命令信息
76 |
77 | ### 高级调试技巧
78 |
79 | + 断点添加命令:在打完断点后,可以添加:br com add "断点编号" ,添加断点触发时执行的命令,以DONE结束。
80 |
81 | + Xcode也可以在以下界面设置
82 |
83 | 
84 |
85 | 
86 |
87 | + 使用Python脚本:
88 |
89 | + [chisel](https://github.com/facebook/chisel):Facebook的开源的LLDB命令工具,支持pviews,pvc等等命令。[wifi](https://github.com/facebook/chisel/wiki)
90 | + [LLDB](https://github.com/DerekSelander/LLDB):Derek Selander开源工具。
91 | + 脚本使用参考官方:http://lldb.llvm.org/python_reference/index.html
92 |
93 | + Xcode的Debug View Hierarchy:找到所在视图或者视图控制器的Address,再结合 chisel 的 methods "Adderss" 命令找到所要的方法Adress,就可以用br s -a Adress对方法下断点了。省略了,pviews、pvc 、presponder、hide、show等命令,是不是简单了许多~
94 |
95 | 
96 |
97 | 
98 |
99 |
100 |
101 | + Xcode 的Debug Memory Graph:查看对象的内存引用信息
102 |
103 | 
104 |
105 | + 可以查看对象的内存分配对象,需要在Xcode的Edit Scheme Diagnostics Malloc stack 上打勾。
106 |
107 | 
108 |
109 | + 可以得到内存的实例对象
110 |
111 | + 可以得到内存地址所有被引用的地方,黑色线就是被引用的地方啦(理解程序的逻辑就一目了然呀)
112 |
113 | 
114 |
115 |
116 |
117 | + 像Cycript一样调用函数,但前面得加e , 例如: e [(MYView \*)0x103d05be0 setHidden:YES],输入c继续,然后就会看到MYView被隐藏掉啦。
118 | + 其他:
119 | + 查看当前模块:Debug - Debug Workflow - Shared Libraries选项
120 | + 查看地址的内存信息:Debug - Debug Workflow - View Momery选项
121 | + 动态调试中,要查看某个函数给别的函数调用的位置,可以先hook住这个函数,然后断言。就可以看到奔溃位置的函数调用啦,很方便~
122 |
123 |
124 | ### lldb使用思路
125 |
126 | + 用Cycript等工具找到方法内存地址,打断点,确认内存地址是否是正确的。
127 | + 找到想要的方法内存地址,也可以使用Cycript等工具。由[chisel](https://github.com/facebook/chisel)提供的脚本支持
128 | + 查看参数传递,或者引用关系,调用堆栈等执行流程。
--------------------------------------------------------------------------------
/Cycript用法.md:
--------------------------------------------------------------------------------
1 | # cycript 用法大全
2 |
3 | ### Cycript的介绍、原理
4 |
5 | + Cycript是由Cydia创始人[Saurik](:https://git.saurik.com/cycript.git)推出的一款脚本语言,Cycript 混合了Objective-C与javascript语法的解释器,这意味着我们能够在一个命令中用Objective-C或者javascript,或者两者兼用。
6 |
7 | + 利用Libffi、JavaScriptCore实现native代码和解释代码的桥接
8 |
9 |
10 |
11 |
12 | ### Cycript使用
13 |
14 | + 根据new Instance根据地址获取对象,和直接使用#号获取对象
15 |
16 | ```javascript
17 | cy# var btn = #0x10102e630
18 | #">"
19 | cy# var bt1 = new Instance(0x10102e630)
20 | #">"
21 | ```
22 |
23 |
24 | + choose传递一个类,可以在内存中找出属于这个类的对象
25 |
26 | ```javascript
27 | cy# choose(UIButton)
28 | [#">"]
29 | ```
30 |
31 |
32 |
33 | + 使用NSLog
34 |
35 | ```javascript
36 | NSLog_ = dlsym(RTLD_DEFAULT, "NSLog")
37 | NSLog = function() {
38 | var types = 'v', args = [], count = arguments.length;
39 | for (var i = 0; i != count; ++i) {
40 | types += '@';
41 | args.push(arguments[i]);
42 | }
43 | new Functor(NSLog_, types).apply(null, args);
44 | }
45 | ```
46 |
47 |
48 | + 还有许多集成等等集成到一个[文件](https://raw.githubusercontent.com/blaceman/myRe/master/cy/myMd.cy)
49 |
50 | ```javascript
51 | (function(utils) {
52 |
53 | utils.constants = {
54 | APPID: NSBundle.mainBundle.bundleIdentifier, //id
55 | APPPATH: NSBundle.mainBundle.bundlePath, //资源路径
56 | APPHOME: NSHomeDirectory(), //沙盒
57 | APPDOC: NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0],
58 | APPLIBRARY: NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0],
59 | APPCACHE: NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]
60 | };
61 |
62 | utils.pviews = function(){
63 | return UIApp.keyWindow.recursiveDescription().toString(); //打印视图层次
64 | };
65 |
66 | utils.pvcs = function(){ //打印当前控制器
67 | return UIWindow.keyWindow().rootViewController._printHierarchy().toString();
68 | };
69 |
70 | utils.rp = function(target){//打印响应者 nextResponder
71 | var result = "" + target.toString();
72 | while(target.nextResponder){
73 | result += "\n" + target.nextResponder.toString();
74 | target = target.nextResponder;
75 | }
76 | return result;
77 | };
78 |
79 | utils.pactions = function(target){ //打印actionsForTarget;
80 | var result = '';
81 | var objs = target.allTargets.allObjects();
82 | for(var i = 0; i < objs.length; i++){
83 | var actions = [target actionsForTarget:objs[i] forControlEvent:0];
84 | result += objs[i] + " " + [actions componentsJoinedByString:@","];
85 | }
86 | return result;
87 | }
88 |
89 |
90 | utils.loadFramework = function (target) { //加载资源路径
91 | var h="/System/Library/",t="Frameworks/"+target+".framework";
92 | return [[NSBundle bundleWithPath:h+t]||
93 | [NSBundle bundleWithPath:h+"Private"+t] load];
94 | }
95 |
96 |
97 | utils.tryPrintIvars = function tryPrintIvars(a){ //打印属性 或者*实例对象
98 | var x={};
99 | for(i in *a)
100 | {
101 | try{ x[i] = (*a)[i]; } catch(e){}
102 | }
103 | return x;
104 | }
105 |
106 |
107 | utils.printMethods = function printMethods(className, isa) { //打印方法,第一个传类对象字符串,第二个可不传。
108 | var count = new new Type("I");
109 | var classObj = (isa != undefined) ? objc_getClass(className)->isa :
110 | objc_getClass(className);
111 | var methods = class_copyMethodList(classObj, count);
112 | var methodsArray = [];
113 | for(var i = 0; i < *count; i++) {
114 | var method = methods[i];
115 | methodsArray.push({selector:method_getName(method),
116 | implementation:method_getImplementation(method)});
117 | }
118 | free(methods);
119 | return methodsArray;
120 | }
121 |
122 |
123 |
124 |
125 | for(var k in utils.constants) { //引入时打印对象变量
126 | Cycript.all[k] = utils.constants[k];
127 | }
128 |
129 | for(var k in utils) {//引入时打印对象方法
130 | if(utils.hasOwnProperty(k)) {
131 | var f = utils[k];
132 | if(typeof f === 'function') {
133 | Cycript.all[k] = f;
134 | }
135 | }
136 | }
137 | })(exports);
138 | ```
139 |
140 | + 越狱手机cycript挂钩进程:
141 |
142 | ```javascript
143 | cycript -p 进程id(ps ax | grep Cycript 查看进程id)
144 | ```
145 |
146 | + cycript支持加载自己的脚本,把cy文件放进/var/root/下
147 |
148 | + cycript -p 进程id(名) /var/root/utils.cy
149 | + cycript -p 进程id(名)
150 |
151 | + monkeyDev Cycript挂钩,monkeyDev运行成功后会打印挂钩信息。
152 |
153 | + **./cycript -r 192.168.1.105(手机IP):6666(端口)**
154 |
155 | + monkeyDev 网络加载cy文件
156 |
157 | + 
158 | + LoadAtLaunch:是否默认加载到cycript坏境中,对于monkeyDev的ms、md文件起作用,自己的的网络cy文件没有效果,要自己@import myMD(key名)导入。
159 | + priority:优先级
160 | + url:网络的cy文件
161 | + content:cy脚本
162 |
163 | + cycript逆向思路(本地验证):
164 |
165 | + pviews()查看视图层次
166 | + (#0x10102e630(内存地址)).hidden = YES 确定按钮位置
167 | + pactions(#0x10102e630) 打印targetAction
168 | + 手动调用targetAction查看效果
169 | + ....
170 | + rp(#0x10102e630)打印响应者 nextResponder
171 | + 然后printMethods(@"类名")查找方法名
172 | + 找到可疑的方法,调用,查看是否是想要的效果(要猜)
--------------------------------------------------------------------------------