首页
社区
课程
招聘
[分享] [calleng的逆向日记] iOS crackMe and Frida(Objection) Get Started (Oct,16th)
发表于: 2023-10-10 17:28 7815

[分享] [calleng的逆向日记] iOS crackMe and Frida(Objection) Get Started (Oct,16th)

2023-10-10 17:28
7815

入门学习逆向的个人笔记,预览(欢迎探讨)

  • C/C++的学习和数据结构

[原创][calleng的逆向日记] 22y11m-23y3m29d 实现macOS编辑, iOS端编译和调试C/C++
[原创] [calleng的逆向日记] 23/03/30 (C++概念构建篇01) 补充完毕
[分享][calleng的逆向日记] 22y11m-23y6m7d Win10Arm下的 gdb调试.[数据结构/严蔚敏-之迷宫问题]

  • iOS的学习和逆向

[分享] IOS软件安全工程师技能表(2017.7by非虫) (为自己学习导航) 图片不清楚下面有导图下载
[分享] Frida-Tool的一些 介绍, 和在 iOS下的一些用法 [个人笔记汇总]
[原创] [calleng的逆向日记] 弹窗的修改原理-OC篇 [源码学习和HOOK实践]23/09/24 --待续
[讨论] [calleng的逆向日记] 自学iOS逆向时候,如何自己解决问题.
[分享] [calleng逆向日记] iOS crackMe的破解 与 Frida(Objection) 的入门使用(thanks to roysue)
[分享] (iOS Hook原理,OC底层实现)Frida前置知识的(royuse)的一些知识注解(图片三次压缩失真,详情见附件)
[原创] (calleng逆向日记)Frida前置知识, ObjC runtime的"反射"-KVC-实例代码理解和分析
[分享] [calleng的逆向日记] Frida 前置知识, 类与方法的底层实现, 逻辑批注, (参考AloneMonkey的书)
[原创] (calleng逆向日记)Frida前置知识, ObjC runtime的"反射" KVC实例Demo分析第二部(Demo底部下载)
[分享] [calleng的逆向日记] iOS crackMe and Frida(Objection) Get Started (Oct,16th)
[分享] [calleng的逆向日记] Frida在iOS上内存漫游与黑盒调用 Get Started Section 4


学到的内容

  • iOS hooking search 源码解析
  • ApiResolver搜刮内存中的所有符号
  • 枚举搜索所有类/所有方法/所有重载
  • hook所有类/所有方法/所有重载
  • 输出(修改)解析参数/调用栈/返回值

ios hooking search classes ViewController // search classes name which have .
ios hooking list class_methods ViewController // search all ViewController's method
ios hooking search methods buttonClick:
ios hooking search methods "- buttonClick:"
ios hooking search methods "buttonClick"
ios hooking search methods "[- buttonClick:]"
git clone https://github.com/sensepost/objection.git
code objection


"new ApiResolver(type): create a new resolver of the given type, allowing you to quickly find functions by name, with globs permitted."
(新建ApiResolver(type):创建一个给定类型的新解析器,允许您通过名称快速查找函数,支持通配符。)

"Precisely which resolvers are available depends on the current platform and runtimes loaded in the current process."
(可用的解析器取决于当前平台和当前进程中加载的运行时。)

"As of the time of writing, the available resolvers are:"
(截止到写作时,可用的解析器如下:)

"module: Resolves exported and imported functions of shared libraries currently loaded. Always available."
(module: 解析当前加载的共享库的导出和导入函数。始终可用。)

"objc: Resolves Objective-C methods of classes currently loaded. Available on macOS and iOS in processes that have the Objective-C runtime loaded. Use ObjC.available to check at runtime, or wrap your new ApiResolver('objc') call in a try-catch."
(objc: 解析当前加载的类的Objective-C方法。在具有加载了Objective-C运行时的macOS和iOS进程中可用。在运行时使用ObjC.available进行检查,或将您的new ApiResolver('objc')调用包装在try-catch中。)

"The resolver will load the minimum amount of data required on creation, and lazy-load the rest depending on the queries it receives. It is thus recommended to use the same instance for a batch of queries, but recreate it for future batches to avoid looking at stale data."
(解析器在创建时将加载所需的最少数据,并根据收到的查询进行延迟加载其余数据。因此,建议对一批查询使用相同的实例,但对未来的批次重新创建实例,以避免查看过期数据。)


  • "ObjC.available: a boolean specifying whether the current process has an Objective-C runtime loaded. Do not invoke any other ObjC properties or methods unless this is the case."
    (ObjC.available:一个布尔值,指示当前进程是否已加载Objective-C运行时。除非是这种情况,否则不要调用任何其他ObjC属性或方法。)

  • "ObjC.api: an object mapping function names to NativeFunction instances for direct access to a big portion of the Objective-C runtime API."
    (ObjC.api:一个将函数名称映射到NativeFunction实例的对象,用于直接访问Objective-C运行时API的大部分内容。)

  • "ObjC.classes: an object mapping class names to ObjC.Object JavaScript bindings for each of the currently registered classes. You can interact with objects by using dot notation and replacing colons with underscores, i.e.: [NSString stringWithString:@"Hello World"] becomes const { NSString } = ObjC.classes; NSString.stringWithString_("Hello World");. Note the underscore after the method name. Refer to iOS Examples section for more details."
    (ObjC.classes:一个将类名称映射到当前已注册类的每个ObjC.Object JavaScript绑定的对象。您可以使用点表示法与对象交互,并用下划线替换冒号,例如:[NSString stringWithString:@"Hello World"] 变成 const { NSString } = ObjC.classes; NSString.stringWithString_("Hello World");。请注意方法名称后面的下划线。有关更多详细信息,请参阅iOS示例部分。)

  • "ObjC.protocols: an object mapping protocol names to ObjC.Protocol JavaScript bindings for each of the currently registered protocols."
    (ObjC.protocols:一个将协议名称映射到当前已注册协议的每个ObjC.Protocol JavaScript绑定的对象。)

  • "ObjC.mainQueue: the GCD queue of the main thread"
    (ObjC.mainQueue:主线程的GCD队列)

  • "ObjC.schedule(queue, work): schedule the JavaScript function work on the GCD queue specified by queue. An NSAutoreleasePool is created just before calling work, and cleaned up on return."
    (ObjC.schedule(queue, work):在由queue指定的GCD队列上安排JavaScript函数work。在调用work之前,会创建一个NSAutoreleasePool,并在返回时进行清理。)


ApiResolver搜刮内存中的所有符号

枚举搜索所有类/所有方法/所有重载


Using ApiResolver come true code search

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[ViewController *]');  //-[NSURL* *HTTP*] left section is classname, r is method name
  // const first = matches[0];
  // console.log(JSON.stringify(first))
  matches.forEach((match)=>{
    console.log(JSON.stringify(match))
  })
})
 
// above this is searching by class name do it ,will get the result.
 
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[* *buttonClick:]');  // [* buttonClick:] or [* *buttonClick:] is okay working
  matches.forEach((match)=>{
    console.log(JSON.stringify(match))
  })
})
// about is searching by method name , do it will get result.
*/
 
 
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[* theLabel]');  // searching by Property
  matches.forEach((match)=>{
    console.log(JSON.stringify(match))
  })
})

hook所有类/所有方法/所有重载

ios hooking watch class ViewController
jobs list
jobs kill 232233
ios hooking list class_methods ViewController
ios hooking watch method "*[ViewController buttonClick:]"
--dump-args
--dump-backtrace
--dump-return
// (classname and method name )must type completely. add , [Parameters , CallStacks, Return Value.]at the tail.

new ObjC.Object(handle[, protocol]): create a JavaScript binding given the existing object at handle (a NativePointer). You may also specify the protocol argument if you’d like to treat handle as an object implementing a certain protocol only."

new ObjC.Object(handle[, protocol]): 基于指定的 NativePointer(句柄),创建一个 JavaScript 绑定。如果需要将该句柄视为仅实现特定协议的对象,则还可以指定 protocol 参数。"

Definition new ObjC.Object(handle[, protocol]):

1
2
3
4
5
6
7
Interceptor.attach(myFunction.implementation, {
  onEnter(args) {
    // ObjC: args[0] = self, args[1] = selector, args[2-n] = arguments
    const myString = new ObjC.Object(args[2]);
    console.log("String argument: " + myString.toString());
  }
});

Objection hooking.ts Source Code about watchInvocation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const watchInvocation: InvocationListener = Interceptor.attach(matchedMethod.address, {
  // tslint:disable-next-line:object-literal-shorthand
  onEnter: function (args) {
    // how many arguments do we have in this selector?
    const argumentCount: number = (selector.match(/:/g) || []).length;
    const receiver = new ObjC.Object(args[0]);
    send(
      c.blackBright(`[${job.identifier}] `) +
      `Called: ${c.green(`${selector}`)} ${c.blue(`${argumentCount}`)} arguments` +
      `(Kind: ${c.cyan(receiver.$kind)}) (Super: ${c.cyan(receiver.$superClass.$className)})`,
    );
 
    // if we should include a backtrace to here, do that.
    if (dbt) {
      send(
        c.blackBright(`[${job.identifier}] `) +
        `${c.green(`${selector}`)} Backtrace:\n\t` +
        Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n\t"),
      );
    }
 
    if (dargs && argumentCount > 0) {
      const methodSplit = ObjC.selectorAsString(args[1]).split(":").filter((val) => val);
      const r = methodSplit.map((argName, position) => {
        // As this is an ObjectiveC method, the arguments are as follows:
        // 0. 'self'
        // 1. The selector (object.name:)
        // 2. The first arg
        //
        // For this reason do we shift it by 2 positions to get an 'instance' for
        // the argument value.
        const t = new ObjC.Object(args[position + 2]);
        return `${argName}: ${c.greenBright(`${t}`)}`;
      });
 
      send(c.blackBright(`[${job.identifier}] `) +
        `Argument dump: [${c.green(receiver.$className)} ${r.join(" ")}]`);
    }
  },
  onLeave: (retval) => {
    // do nothing if we are not expected to dump return values
    if (!dret) { return; }
    send(c.blackBright(`[${job.identifier}] `) + `Return Value: ${c.red(retval.toString())}`);
  },
});

Write Self Script for Hooking Function

put blew content code to 09.js
running it frida -UF -l 09.js when it UnCrakable1 running Front of SpringBoard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[* buttonClick:*]');  // searching by Property
  matches.forEach((match)=>{
    console.log(JSON.stringify(match))
    Interceptor.attach(match.address,{
      onEnter:function(args){
        const receiver = new ObjC.Object(args[0]);
        console.log("receiver is =>",receiver.$className," => ",JSON.stringify(receiver));
 
      },onLeave:function(ret){
        console.log("ret=>",ret)
      }
    })
  })
})

and touch screen input some characters.then click Verify will disappear, below messages.

then , go to food delivery and finish it , go on ~ (40:24 Lesson09)

官网的案例也有问题,

缺少 args 参数

看参数, 调用栈(不看了,非常麻烦.), 返回值 ,.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[* isEqualToString:*]');  // 
  matches.forEach((match) => {
    console.log(JSON.stringify(match))
    Interceptor.attach(match.address, {
      onEnter: function(args){
        const receiver = new ObjC.Object(args[0]);
        console.log("receiver is =>", receiver.$className," => ", receiver.toString());
      }, onLeave: function (ret) {
        console.log("ret=>", ret)
      }
    })
    })
  })

这是一个自己, 是一个对象. receiver.toString()); 转换成字符串, 而非地址,使用这个函数后. 入上图 , =》 便是

修改返回值成功了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[* isEqualToString:*]');  // 
  matches.forEach((match) => {
    console.log(JSON.stringify(match))
    Interceptor.attach(match.address, {
      onEnter: function(args){
        this.change = false;
        const receiver = new ObjC.Object(args[0]);
        console.log("receiver is =>", receiver.$className," => ", receiver.toString());
        if(receiver.toString().indexOf("aaaabbbb")>=0) {
          this.change = true;
          console.log("need change")
        }
      }, onLeave: function (ret) {
        console.log("ret=>", ret)
        if(this.change){
          ret.replace(new NativePointer(0x1))
        }
      }
    })
    })
  })
// modify the return value.
// using frida -UF -l 09.js -o 09.txt


//只是 hook了 isEqualToString 让他在参数里面带4个a, 4个b ,返回,修改通过.
以上代码的解释

  • 检查是否有Objective-C运行环境
  • 通过ApiResolver枚举所有符合特定条件的函数
  • 对于每个符合条件的函数,使用Interceptor进行拦截
  • 在函数进入时,检查接收者的类名和字符串表示中是否包含"aaaabbbb"
  • 如果接收者满足条件(包含"aaaabbbb"),则修改该函数返回值

// 以上是修改返回值的例子.

Output (modify) parsing parameters

ObjC.classes: an object mapping class names to ObjC.Object JavaScript bindings for each of the currently registered classes. You can interact with objects by using dot notation and replacing colons with underscores, i.e.: [NSString stringWithString:@"Hello World"] becomes const { NSString } = ObjC.classes; NSString.stringWithString_("Hello World");. Note the underscore after the method name. Refer to iOS Examples section for more details.

key code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
setImmediate(() => {
  console.log("hello world! calleng! ObjC => ", ObjC.available) // test it whether there is a running environment
  const resolver = new ApiResolver('objc');
  const matches = resolver.enumerateMatches('*[* isEqualToString:*]');  // 
  matches.forEach((match) => {
    console.log(JSON.stringify(match))
    Interceptor.attach(match.address, {
      onEnter: function(args){
        this.change = false;
        const receiver = new ObjC.Object(args[0]);
        console.log("receiver is =>", receiver.$className," => ", receiver.toString());
        if(receiver.toString().indexOf("aaaabbbb")>=0) {
          this.change = true;
          console.log("need change")
          const { NSString } = ObjC.classes;
          var newString = NSSting.stringWithString_("aaaabbbb");
          args[2] = newString;
        }
      }, onLeave: function (ret) {
        console.log("ret=>", ret)
        // if(this.change){
        //   ret.replace(new NativePointer(0x1))
        // }
      }
    })
    })
  })

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-11-8 00:23 被calleng编辑 ,原因: 修改大纲,填充内容
收藏
免费 1
支持
分享
最新回复 (6)
雪    币: 3070
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-10-11 09:15
1
雪    币: 2119
活跃值: (1890)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-10-11 11:01
1
雪    币: 31
活跃值: (3254)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学习了 json ,stringFacy ? 
object c , objct,  hook all class method and  use ApiResolver to get the address , directly hook this address. 
the course is simple , the skill form the Objection get it. 
if have some question ask roysue. 
2023-10-16 19:43
0
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
NSString  类型 可以转换为NSConcreteMutableData参数类型
2023-11-10 14:22
0
雪    币: 714
活跃值: (1547)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
你这写得比看肉丝文章还痛苦
2023-12-21 10:54
0
雪    币: 31
活跃值: (3254)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
寻梦之璐 你这写得比看肉丝文章还痛苦[em_65]
肉丝内容混过 10 年 ,我呢, 3 个月而已。
2024-1-4 03:40
0
游客
登录 | 注册 方可回帖
返回
//