如何通过针对iOS的动态分析技术绕过反调试机制

news/2024/7/20 22:39:39 标签: ios, cocoa, macos

在这篇文章中,我们将跟大家介绍和分析一种针对iOS的新型安全研究技术,该技术能够让iOS应用程序的调试过程更加轻松,并解决那些可能会延缓我们步伐的阻碍。

如果你要对一个采用了反调试技术的iOS应用程序或二进制文件进行调试的话,可能你会感觉困难重重。作为一名安全研究人员,你可能也需要经常面对黑盒测试的场景,而且大多数还会故意对代码进行混淆处理。这样一来,想要简化分析流程就会非常困难,而且很多调试工具和技术都会失效,将本应简单的任务变成了复杂的难题。

在这篇文章中,我们将给大家演示并详细介绍Corellium团队开发的一种新技术,这种技术可以加快iOS应用程序的代码动态分析工作,并解决代码调试过程中可能遇到的各种难题。

什么是反调试技术?

OWASP移动应用程序安全验证标准(MASVS)是一个用于确保移动应用程序安全性的综合标准框架,该标准框架由开放式Web应用程序安全项目(OWASP)设计研发,由各种级别的安全要求和建议组成,提供了移动应用程序安全的基线。在其指导标准中,MASVS解决了移动应用程序实现反逆向工程和调试措施的需要,并强调了这些活动是对应用程序安全和用户隐私的潜在威胁。

尤其是,它强调了整合调试检查机制的重要性。其中包括部署检测和响应调试器,以确保代码和敏感数据在调试会话期间不会暴露,并防止调试工具修改或篡改应用程序。通过实现这些安全实践建议,开发人员可以更好地保护其应用程序免受未经授权的分析和利用,这对于维护应用程序及其用户数据的完整性和机密性至关重要。

下面给出的是目前社区广泛采用的一些反调试技术:

1、使用sysctl检测是否设置了ptrace标志,该标志可能会导致应用程序在内省(在程序运行时确定对象类型的一种能力)状态下终止运行或表现有差异;

2、直接使用ptrace设置PTRACE_DENY_ATTACH,并防止父进程对其进行调试;

3、使用getppid()确定应用程序是否由launchd(pid 1)启动执行;

iOSSecuritySuite库就以非常简洁直接的形式实现了这些检查,并且可以轻松地将其应用到iOS应用程序中。在演示过程中,我们会将其中一个检查以简单二进制文件的形式重新编码实现,并且可以直接从iOS控制台运行。该应用程序也非常简单,其运行流程如下:

1、给一个NSString设置一个随机8字节标记;

2、打印关于用户空间进程的某些有用的调试信息,例如可执行程序的基地址和标记地址;

3、等待用户输入(主要是暂停并绑定调试器);

4、退出;

首先,我们直接运行该应用程序,并且没有启用任何调试保护机制:

iphone:/ root# ./main-allow  

2024-01-24 08:50:08.234 main-allow[736:32888] Flag value: aX1ZWAec

2024-01-24 08:50:08.234 main-allow[736:32888] PID: 736

2024-01-24 08:50:08.234 main-allow[736:32888] Base Address of Main: 0x10000423c

2024-01-24 08:50:08.234 main-allow[736:32888] Address of NSString: 0x16fdff2f8

2024-01-24 08:50:08.235 main-allow[736:32888] Address of actual NSString contents: 0x9142043a0 <--- save this for later

2024-01-24 08:50:08.235 main-allow[736:32888] Pausing for user input...

然后,直接给进程绑定一个debugserver,并给需要交互的远程lldb客户端打开一个端口:

iphone:/ root# ./debugserver16-3 0.0.0.0:3333 -a 736

debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-1400.2.13.2

 for arm64.

Attaching to process 736...

Listening to port 3333 for a connection from 0.0.0.0...

通过使用二进制代码提供的调试信息,我们可以打印出标志的内容:

(lldb) process connect connect://10.11.0.12:3333                                                                                                                                                                 Process 736 stopped

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP

    frame #0: 0x00000001c5fe8e84 libsystem_kernel.dylib`__read_nocancel + 8

libsystem_kernel.dylib`:

->  0x1c5fe8e84 <+8>:  b.lo   0x1c5fe8ea4               ; <+40>

    0x1c5fe8e88 <+12>: pacibsp  

    0x1c5fe8e8c <+16>: stp    x29, x30, [sp, #-0x10]!

    0x1c5fe8e90 <+20>: mov    x29, sp

Target 0: (main-allow) stopped.

(lldb) x 0x9142043a0

0x9142043a0: 61 58 31 5a 57 41 65 63 00 00 00 00 00 00 00 00  aX1ZWAec........

0x9142043b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

(lldb)  

没错,我们就可以查看到NSString对象的内容了(程序提供的地址右边)。

现在,我们需要在我们自己的应用程序中重新实现IOSSecuritySuite中的.denyDebugger()方法:

static void denyDebugger() {

    // Dynamic loading of ptrace

    void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);

 

    pid_t pid = getpid();

 

    if (handle) {

        typedef int (*PtraceType)(int request, pid_t pid, caddr_t addr, int data);

        PtraceType ptraceFunction = (PtraceType)dlsym(handle, "ptrace");

 

        if (ptraceFunction) {

            // PT_DENY_ATTACH == 31

            int ptraceRet = ptraceFunction(31, 0, 0, 0);

 

            if (ptraceRet != 0) {

                NSLog(@"Error occurred when calling ptrace(). Denying debugger may not be reliable");

            }

        }

        dlclose(handle);

    }

}

如果我们重新运行附加了额外功能函数的应用程序,我们将能够得到一次完全不一样的体验:

iphone:/ root# ./debugserver16-3 0.0.0.0:3333 -a 739

debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-1400.2.13.2

 for arm64.

Attaching to process 739...

Segmentation fault: 11

iphone:/ root#  

通过设置PT_DENY_ATTACH标志,debugserver/lldb将无法绑定到目标进程上。但这种技术并不是万能的,因为我们也可以通过钩子和代码修补的组合方式来绕过这种技术。然而,应用程序也可以使用一些技术方法来检测它们当前是否正在被其他工具检测,或应用程序完整性是否被破坏。

那么,我们如何在不给目标应用程序“知情”的情况下对其进行调试呢?

使用Corellium进行调试

Corellium能够提供一个内核级的gdb-stub,我们可以将其与gdb和lldb一起使用。对于想要深入了解iOS内部细节或执行安全漏洞研究的人来说,内核调试器是非常有价值的工具。如果你必须处理云环境中的潜在问题,以提供更快速的调试体验,我们也可以将其与Corellium调试加速器结合使用。

Corellium VM在service_ip:4000上会暴露公内核调试桩,我们可以使用任何适配gdb协议的东西连接到该调试桩。在下面的例子中,我们将使用lldb进行演示:

(lldb) gdb-remote 10.11.1.12:4000

Kernel UUID: EE3449F0-DB47-3596-B253-084A0EBDBDC5

Load Address: 0xfffffff00700c000

WARNING: Unable to locate kernel binary on the debugger system.

Process 1 stopped

* thread #1, stop reason = signal SIGINT

    frame #0: 0xfffffff007d2d0f0

->  0xfffffff007d2d0f0: cbz    x30, -0xff82d2f08

    0xfffffff007d2d0f4: ret     

    0xfffffff007d2d0f8: mov    x0, #0x1

    0xfffffff007d2d0fc: bl     -0xff816d978

Target 0: (No executable module.) stopped.

(lldb) c

Process 1 resuming

我们还可以使用内核调试器来调试用户空间进程,利用监控器过滤功能,我们可以通过进程名称、PID或TID来指定一个用户空间进程,而且还可以使用boe标志(可选)来中断正在进入用户空间的进程:

(lldb) process plugin packet monitor filter user pid:814 boe

接下来,我们将控制内核进入使用pid:标志指定的进程:

(lldb) process plugin packet monitor filter user pid:745 boe

  packet: qRcmd,66696c7465722075736572207069643a37343520626f65

response: OK

Process 1 stopped

* thread #2, stop reason = signal SIGSTOP

    frame #0: 0x00000001c5fe8e84

->  0x1c5fe8e84: b.lo   0x1c5fe8ea4

    0x1c5fe8e88: pacibsp  

    0x1c5fe8e8c: stp    x29, x30, [sp, #-0x10]!

    0x1c5fe8e90: mov    x29, sp

Target 0: (No executable module.) stopped.

从上述代码中我们可以看到,我们已经将调试上下文从内核切换到了用户空间进程。程序也正常运行,但我们仍然在悄悄地调试它。现在,使用程序提供的调试信息,我们可以使用lldb打印用户空间NSString对象的内容:

2024-01-24 09:31:26.294 main-deny[745:40019] Flag value: k5mLCxkR 
2024-01-24 09:31:26.295 main-deny[745:40019] PID: 745 
2024-01-24 09:31:26.295 main-deny[745:40019] Base Address of Main: 0x10000423c 
2024-01-24 09:31:26.295 main-deny[745:40019] Address of NSString: 0x16fdff2f8 
2024-01-24 09:31:26.295 main-deny[745:40019] Address of actual NSString contents: 0x7c24043e0 
2024-01-24 09:31:26.296 main-deny[745:40019] Pausing for user input... 
(lldb) x 0x7c24043e0 
0x7c24043e0: 6b 35 6d 4c 43 78 6b 52 00 00 00 00 00 00 00 00  k5mLCxkR........ 
0x7c24043f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
(lldb)  

后话

当然了,你还可以使用该技术来调试Corellium的非越狱模型。如果你想在未越狱VM中调试com.apple.WebKit.WebContent的话,可以直接绑定一个内核调试器并安装上述步骤操作即可。

参考资料

Technical Q&A QA1361: Detecting the Debugger

Mac OS X Manual Page For ptrace(2)

https://github.com/securing/IOSSecuritySuite/blob/2121b32eb967a2a27c5cf54a369a92c2e36546d3/IOSSecuritySuite/DebuggerChecker.swift

How to Debug the Kernel | Corellium Support Center

Debug Accelerator | Corellium Support Center

参考链接

Defeating debug protections with Corellium


http://www.niftyadmin.cn/n/5459029.html

相关文章

Java IO与NIO的对决:一场变革性的I/O架构较量及其实战演绎

在Java编程中&#xff0c;IO&#xff08;Input/Output&#xff09;和NIO&#xff08;New Input/Output&#xff09;是两种处理输入输出操作的关键API。虽然它们的目的都是为了进行数据的读写操作&#xff0c;但在设计理念、性能表现以及使用场景上有着显著的区别。本文将通过实…

【生活】相机/图像各参数

文章目录 专业模式图片编辑-滤镜实体滤镜软件模拟滤镜 图片编辑-增强曝光亮度对比度饱和度自然饱和度色温色调高光阴影HSL色调分离褪色颗粒锐化晕影清晰度暗角 参考 专业模式 第一个参数WB是白平衡&#xff0c;调节色彩的。 第二个是对焦F&#xff0c;近距离拍摄物体&#xf…

深入解析Windows Edge兼容性问题及其修复策略

深入解析Windows Edge兼容性问题及其修复策略 目录 深入解析Windows Edge兼容性问题及其修复策略 一、引言 二、Windows Edge浏览器概述 三、深入分析兼容性问题 四、案例研究 五、技术解决方案与最佳实践 六、数据图表与性能指标 七、编程技巧与代码示例 一、引言 随着W…

2024年MathorCup数学建模思路B题思路分享

文章目录 1 赛题思路2 比赛日期和时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

MySQL中MD5()函数加密CONCAT()函数拼接的字段

在MySQL中&#xff0c;使用CONCAT()函数来连接多个字段&#xff0c;然后对其结果应用MD5()函数进行加密。 SQL查询语句 UPDATE po_electricity SET task_code MD5(CONCAT(school_id, -, electricity_month, LOCKDATAV)) WHERE electricity_id 43;UPDATE po_water …

阿里云实时计算Flink的产品化思考与实践【下】

摘要&#xff1a;本文整理自阿里云高级产品专家黄鹏程和阿里云技术专家陈婧敏在 FFA 2023 平台建设专场中的分享。内容主要为以下五部分&#xff1a; 阿里云实时计算 Flink 产品化思考 产品化实践 SQL 产品化思考及实践 展望 接上篇&#xff1a;阿里云实时计算Flink的产品…

第八十周周报

学习目标&#xff1a; 论文 学习时间&#xff1a; 2024.3.23-2024.3.30 学习产出&#xff1a; 这周主要在改论文&#xff0c;已经改好了中文和英文版本。 实验上&#xff0c;dit的cifar10数据集试了很多参数都没调出来&#xff1b;定性实验由于ViTGAN设置随机种子的代码是…

如何保证redis里的数据都是热点数据

MySQL 里有 2000w 数据&#xff0c;Redis 中只存 20w 的数据&#xff0c;如何保证 redis 中的数据都是热点数据&#xff1f; 1.Redis 过期删除策略 1&#xff09;惰性删除:放任键过期不管&#xff0c;但是每次从键空间中获取键时&#xff0c;都检查取得的键是否过期&#xff0c…