xiaoweigege 发表于 2022-11-16 10:08

ios逆向爬虫-入门保姆级-实战某博APP

本帖最后由 xiaoweigege 于 2022-12-1 19:35 编辑

# ios逆向爬虫-入门保姆级-实战某博APP

## 设备
- iPhone11,系统14.2
- Windows11

## 工具
- Frida15.2.2
- frida-ios-dump
- Ida7.7

## 流程
1. 手机越狱
2. 爱思助手安装目标APP
3. Cydia安装Frida
4. frida-ios-dump进行脱壳
5. app分析
6. ida+frida动静态分析


## 手机越狱
采用爱思助手一键越狱

## 爱思助手安装目标APP


## Cydia安装Frida
1. Cydia添加frida源
!
2. 在cydia添加frida源后,搜索frida,根据iOS设备版本安装对应的frida服务端,如下所示
!

3. frida一些简单的使用
    - frida-ls-devices 查看电脑链接设备信息
    - frida-ps -U 查看通过USB连接设备上运行的程序
    - frida-ps -Ua 查看正在运行的程序
    - frida-ps -Uai 查看iOS设备中已经安装的应用程序
    - frida-ps -D \<UDID\> 通过iOS设备的UDID查看iOS设备中应用程序中的pid、进程名
    - frida-trace -U -f 包名 -i 'CC_MD5' 用于跟踪ios方法的调用

## frida-ios-dump进行脱壳
ios脱壳的方式有很多种:
1. frida-iod-dump
2. dumpdecrypted
3. flexdecrypt
4. Clutch
5. AppCrackr
6. Crackulous

个人觉得frida-ios-dump比较方便,快速。接下来讲解frida-ios-dump的使用步骤:
1. 拉取代码,地址: (https://github.com/AloneMonkey/frida-ios-dump)
2. 安装依赖: `pip install -r requirements.txt`
3. 手机端口转发 `iproxy 2222 22`; `iproxy 本地端口 远程目标端口`
4. ./dump.py 目标app名称, 会将ipa包拉取在本地当前目录
5. 将ipa文件中的主包文件拖进ida分析(app比较大,ida会分析好久好久好久);如图所示:
!



## app分析
### 抓包分析
!
我们的目标是得到`s`值得算法,从`s`这个值得名称来看,大概是一个签名,那么根据以往的经验签名函数大概是一个`hash`操作。

过程:
1. 合并请求数据
2. 加上盐值
3. hash计算得到签名

### frida-trace 跟踪hash函数
1. 打开目标app
2. 输入命令: `frida-trace -UF -i "CC_MD5"` 跟踪ios的md5函数
3. 在当前目录下会生成 `__headlers/xxx/CC_MD5.js` 文件
4. 修改对应js更好的显示输出结果
    ```js
    {

      onEnter(log, args, state)
      {
            log('CC_MD5():', args.readUtf8String());
      }
    ,
      onLeave(log, retval, state)
      {
            log('CC_MD5()--return--=');
            var md5_digest = hexdump(retval, {length: 16});
            var hexified = " ";
            var raw_array = md5_digest.split("\n");
            for (var a = 0; a < raw_array.length; a++) {
                var line_array = raw_array.split(" ");
                for (var b = 1; b < line_array.length - 1; b++) {
                  if (line_array.length === 2) {
                        hexified += line_array;
                        hexified = hexified.trim();
                  }
                }
            }
            log(hexified + "\n");
      }
    }


    ```
5. trace结果如下:
!

执行上述流程,并没有hook到关键数据,同理尝试 `CC_SHA1`, `CC_SHA256`, `CC_SHA512`, `CCHmac`。均没有结果

接着使用(https://github.com/houugen/FridaDev/blob/master/js/ios_trace.js)中的ios-trace.js 脚本进行跟踪。该脚本比较强大,可以模糊跟踪ios中的函数,入参,出参都有比较美观的输出。

现在我们根据经验进行一些跟踪,脑海里面想到一些关键词 `sign`,`crypt`, `Signature`等等。使用该脚本得到结果如下:
!
找到关键信息数据, 得到s的返回值。

找到目标函数,现在需要耐心等待ida分析完成,我们要去看看c的伪代码了。

## ida+frida动静态分析
### ida一些基本操作
1. `x`快捷键获取函数,变量的调用处
2. `shift + F12` 获取字符串窗口
...

### ida静态分析
1. ida静态分析目标函数
!
`sub_107717A5C` 函数是`sha256`算法,为什么我们之前trace `sha256`函数的时候没有得到结果,因为这部分算法是C写的导致hook不到。

怎么分析出是`sha256`算法的?
1. 经验
2. 推荐一个hash计算的网站 (https://1024tools.com/hash), 把加密前内容拿去计算,对比计算出来的结果,推断是什么算法

### frida hook obj-c的两种方法
1. oc方法
```js
//                      类名                方法
var hook = ObjC.classes.NSMutableURLRequest["- setHTTPBodyStream:"];
Interceptor.attach(hook.implementation, {
    onEnter: function(args) {
    // 转换 objc 对象
    var receiver = new ObjC.Object(args);
    // 将选择器转换sel为 JavaScript 字符串
    var sel = ObjC.selectorAsString(args);
    var data = ObjC.Object(args);
    var string = ObjC.classes.NSString.alloc();
    send(" HTTP Request via [ "+receiver+" " +sel+" ] => DATA: " + string.initWithData_encoding_(data,4));
    }
});
```

2. sub方法
像上图这种无符号函数,我们需要根据地址来进行hook
```js
if (ObjC.available) {

    const baseOffset = 0x100000000;
    const base = Module.findBaseAddress('主包名称');
    console.log('Base:', base);
    const idaBase = base.add(-baseOffset);
    console.log('Real Base:', idaBase);
    const sub = base.add(0x107720938 - baseOffset);

    Interceptor.attach(sub, {
      onEnter: function (args) {
            console.log('进入:' + sub.toString() +':', args, args, args)
            print_dump(args, 100)
            // console.log('args=', args.readCString())
            print_dump(args, 100)
            // console.log(args.readInt())
            // print_dump(args, 100)
      },
      onLeave: function (retval) {
            console.log('retval=', retval)
            print_dump(retval, 200)
      }
    })
} else {
    console.log('非ios环境')
}
```

## 常用的一些模板
该脚本来自[慕白](https://www.cnblogs.com/pythonywy)

1. 打印堆栈,堆栈地址相对ida无偏移
```js
function logBacktrace(context, methodName = "", threadId = "") {
    log((methodName.length > 0 ? methodName + " " : "") + "Backtrace:");
    var backtraces = Thread.backtrace(context, Backtracer.ACCURATE);
    for (var backtrace of backtraces) {
      var symbol = DebugSymbol.fromAddress(backtrace);
      var memAddr = symbol.address;
      var subAddr = memAddr.add(baseOffset - base);
      log("\t" + threadId + " " + subAddr + " " + symbol.moduleName + "!" + symbol.name + " " + symbol.fileName + " " + (symbol.lineNumber > 0 ? symbol.lineNumber : ""));
    }
}

function logInterceptor(interceptor, methodName = "") {
    var info = " " + (methodName.length > 0 ? methodName : "");
    logBacktrace(interceptor.context, info, interceptor.threadId);
}

// 使用方法
var A = eval('ObjC.classes.A["- A:"]');
Interceptor.attach(A.implementation, {
    onEnter: function (args) {
      logInterceptor(this, "A:");
    }, onLeave: function (ret) {
    }
});
```

2. json2str
```js
function jsonTostr(ocobj) {
    var NSString = ObjC.classes.NSString
    var str = NSString.alloc().initWithData_encoding_(ocobj, 4)
    return str
}
```
3. 数组转16进制字符串
```js
function print_dump(addr, size, methodName = "") {
    if (addr == null || addr == 0 || size == 0) {
      return;
    }
    var buf = Memory.readByteArray(addr, size)
    log((methodName.length > 0 ? methodName + " " : "") + ": " + addr.toString() + " " + "length: " + size.toString() + "\n")
    log(hexdump(buf, {offset: 0, length: size, header: true, ansi: false}));
    log("\n")
}
```
4. 打印对象
```js
function print_obj(obj) {
    var description = "";
    for (var i in obj) {
      description += i + " = " + obj + "\n";
    }
    log(`info:\n${description}`);
}
```
5. 打印原生bytes
```js
function print_raw_bytes(addr, size) {
    log("Reading from address: " + addr);
    var byteArray = addr.readByteArray(size);
    var int8Array = new Uint8Array(byteArray);
    var str = "";
    for (var i = 0; i < int8Array.length; i++) {
      var value = int8Array;
      str += (value > 16 ? value.toString(16) : ("0" + value.toString(16)));
      str += " ";
    }
    return str;
}
```




:
:

:


:

:

:



:

浅紫色的梦幻 发表于 2022-11-16 10:55

xiaoweigege 发表于 2022-11-16 14:57

Hmily 发表于 2022-11-16 10:41
关于图片,你如果用图传得用markdown的语句,如果你上传本地应该用discuz的插入方式,现在的img方式不能用 ...

感谢提醒,

Hmily 发表于 2022-11-16 10:41

关于图片,你如果用图传得用markdown的语句,如果你上传本地应该用discuz的插入方式,现在的img方式不能用于markdown状态下。

q410226885 发表于 2022-11-16 11:40

谢谢分享

小洲 发表于 2022-11-16 11:41

刚好要学习ios逆向编程

feather_fox 发表于 2022-11-16 11:44

是我网络问题吗,图片全部挂了?

shudong8023 发表于 2022-11-16 11:57

kyne 发表于 2022-11-16 12:16

把图片归拢一下吧,别一开帖就成太监了。

koohik 发表于 2022-11-16 12:59

刚好学习一下,感谢分享

constwm 发表于 2022-11-16 13:04

把图片归拢一下吧。
页: [1] 2 3 4 5 6
查看完整版本: ios逆向爬虫-入门保姆级-实战某博APP