如何通过针对iOS的动态分析技术绕过反调试机制
在这篇文章中,我们将跟大家介绍和分析一种针对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: aX1ZWAec2024-01-24 08:50:08.234 main-allow[736:32888] PID: 7362024-01-24 08:50:08.234 main-allow[736:32888] Base Address of Main: 0x10000423c2024-01-24 08:50:08.234 main-allow[736:32888] Address of NSString: 0x16fdff2f82024-01-24 08:50:08.235 main-allow[736:32888] Address of actual NSString contents: 0x9142043a0 <--- save this for later2024-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 736debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-1400.2.13.2for 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 SIGSTOPframe #0: 0x00000001c5fe8e84 libsystem_kernel.dylib`__read_nocancel + 8libsystem_kernel.dylib`:-> 0x1c5fe8e84 <+8>: b.lo 0x1c5fe8ea4 ; <+40>0x1c5fe8e88 <+12>: pacibsp 0x1c5fe8e8c <+16>: stp x29, x30, [sp, #-0x10]!0x1c5fe8e90 <+20>: mov x29, spTarget 0: (main-allow) stopped.(lldb) x 0x9142043a00x9142043a0: 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 ptracevoid *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 == 31int 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 739debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-1400.2.13.2for arm64.Attaching to process 739...Segmentation fault: 11iphone:/ 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:4000Kernel UUID: EE3449F0-DB47-3596-B253-084A0EBDBDC5Load Address: 0xfffffff00700c000WARNING: Unable to locate kernel binary on the debugger system.Process 1 stopped* thread #1, stop reason = signal SIGINTframe #0: 0xfffffff007d2d0f0-> 0xfffffff007d2d0f0: cbz x30, -0xff82d2f080xfffffff007d2d0f4: ret 0xfffffff007d2d0f8: mov x0, #0x10xfffffff007d2d0fc: bl -0xff816d978Target 0: (No executable module.) stopped.(lldb) cProcess 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 boepacket: qRcmd,66696c7465722075736572207069643a37343520626f65response: OKProcess 1 stopped* thread #2, stop reason = signal SIGSTOPframe #0: 0x00000001c5fe8e84-> 0x1c5fe8e84: b.lo 0x1c5fe8ea40x1c5fe8e88: pacibsp 0x1c5fe8e8c: stp x29, x30, [sp, #-0x10]!0x1c5fe8e90: mov x29, spTarget 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
相关文章:
如何通过针对iOS的动态分析技术绕过反调试机制
在这篇文章中,我们将跟大家介绍和分析一种针对iOS的新型安全研究技术,该技术能够让iOS应用程序的调试过程更加轻松,并解决那些可能会延缓我们步伐的阻碍。 如果你要对一个采用了反调试技术的iOS应用程序或二进制文件进行调试的话,…...
33.Python从入门到精通—Python3 正则表达式 re.match函数 re.search方法 re.match与re.search的区别
33.从入门到精通:Python3 正则表达式 re.match函数 re.search方法 re.match与re.search的区别 Python3 正则表达式re.match函数re.search方法re.match与re.search的区别 Python3 正则表达式 在 Python3 中,可以使用 re 模块来进行正则表达式的匹配和处理…...
便携式气象站是什么
TH-BQX5便携式气象站是一种用于应对突发天气灾害和紧急情况的便携式气象监测设备。它通常包括气温、湿度、气压、风速、风向和降水量等关键气象要素的测量功能,能够快速准确地记录这些气象参数。此外,一些高级的便携式气象站还具备预警功能,当…...
AIGC重塑金融:AI大模型驱动的金融变革与实践
随着人工智能技术的飞速发展,AI大模型在金融领域的应用日益广泛,正在深刻改变着金融行业的面貌。本文将探讨AIGC(人工智能与金融结合)如何重塑金融,以及AI大模型驱动的金融变革与实践。 AIGC重塑金融的背景与意义 随着…...
TP4054替代DP4054锂电池供电电路保护方案
锂离子电池以其优良的特性,被广泛应用于:手机、摄录像机、笔记本电脑、无绳电话、电动工具、遥控或电动玩具、照相机等便携式电子设备中。 01 电池特点 1、具有更高的重量能量比、体积能量比; 2、电压高,单节锂电池电压为3.6V,等…...
前端JS商品规格组合
给定一个数组 let data [{name: "颜色",specs: ["白色", "黑色"],},{name: "尺寸",specs: ["14寸","15寸", "16寸"],},{name: "处理器",specs: ["i5", "i7", "i9&…...
⾃定义类型:联合和枚举
乐观学习,乐观生活,才能不断前进啊!!! 我的主页:optimistic_chen 我的专栏:c语言 点击主页:optimistic_chen和专栏:c语言, 创作不易,大佬们点赞鼓…...
Spring IOC控制反转、DI注入以及配置
1.使用xml的方式进行配置IOC容器,首先引入依赖 在Resource资源下配置,applicationContext.xml ,刷新mevan后可以直接选择配置spring.xml文件 <!-- spring核心用来管理bean --><dependency><groupId>org.springframework</g…...
RabbitMQ的部分模式
1发布订阅模式 发送者 package org.example; import com.alibaba.fastjson.JSON; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import ja…...
提取单选框的值,并通过ajax传值到后台
<!DOCTYPE html> <html lang"zh" xmlns:th"http://www.thymeleaf.org" xmlns:shiro"http://www.pollix.at/thymeleaf/shiro"> <head><th:block th:include"include :: header(日库存更新提示)" /> </head&…...
Django创建多app应用
目录 1. 引言 2. 多app创建的两种方式 2.1 多个app结构 2.2 单个apps多个app 3. 最后 1. 引言 在平常业务开发中,我们遇到的功能可能会有很多,单个app的应用可能无法满足我们 这个时候,我们就需要多app应用,例如:…...
如何反反爬虫
我们来讲最常见的反反爬虫方法 import requests r requests.get(网页网址) print(r.requests.headers) 一.使用简单的方法把请求头改为真的浏览器模式 import requests link网页地址 heraders{User-Agent:} rrequests.get(link,headersheaders) print(r.requsts.headers)我们…...
wireshark抓包之DNS协议
DNS协议 DNS协议的主要作用是将域名解析为对应的IP地址。当我们在浏览器中输入一个网址时,计算机需要通过DNS协议来查找该网址对应的IP地址,以便能够建立连接并访问目标资源。 DNS协议的工作流程大致如下: 用户的计算机或设备(充…...
升级到 Java 21 是值得的
升级到 Java 21 是值得的 又到了一年中的这个时候——New Relic 的年度“State of the Java Ecosystem”调查结果出来了,我一如既往地深入研究了它。虽然我认为该报告做得很好并且提出了很好的问题,但我对有多少 Java 开发人员正在使用低版本感到沮丧。…...
C# 多线程
文章目录 C# 多线程进程与线程无参数的子线程带参数的子线程运行结果 销毁线程 Abort()运行结果 ThreadPool和Task运行结果 异步与同步运行结果 lock单线程运行结果 多线程运行结果 使用lock运行结果 C# 多线程 进程与线程 进程:进程就是一个应用程序,…...
快速安装sudachipy日语包
1、前往 https://rustup.rs 下载并安装 Rustup Linux系统可直接运行以下命令 Window系统需要去网站下载exe包 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh2、安装 Rust 编译器 rustup install stable3、设置默认版本 rustup default stable4、重新安装 …...
蓝桥杯刷题day13——乘飞机【算法赛】
一、问题描述 等待登机的你看着眼前有老有小长长的队伍十分无聊,你突然想要知道,是否存在两个年龄相仿的乘客。每个乘客的年龄用一个 0 到 36500 的整数表示,两个乘客的年龄相差 365 以内就认为是相仿的。 具体来说,你有一个长度…...
大模型量化技术-BitsAndBytes
Transformers 量化技术 BitsAndBytes bitsandbytes是将模型量化为8位和4位的最简单选择。 8位量化将fp16中的异常值与int8中的非异常值相乘,将非异常值转换回fp16,然后将它们相加以返回fp16中的权重。这减少了异常值对模型性能产生的降级效果。4位量化进一步压缩了模型,并且…...
EasyExcel 复杂表头的导出(动态表头和静态表头)
问题:如图,1部分的表头是动态的根据日期变化,2部分是数据库对应的字段,静态不变的; 解决方案:如果不看1的部分,2部分内容可以根据实体类注解的方式导出,那么我们是不是可以先将动态表…...
centos7 fatal error: curl/curl.h: No such file or directory
若编译遇到此问题,可以查看环境是否libcurl库 yum list installed | grep libcurl 发现未安装libcurl库 执行libcurl库的安装命令: 1.对于Debian/Ubuntu系统: sudo apt-get install libcurl4-openssl-dev 2.对于RHEL/CentOS系统…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
Git 命令全流程总结
以下是从初始化到版本控制、查看记录、撤回操作的 Git 命令全流程总结,按操作场景分类整理: 一、初始化与基础操作 操作命令初始化仓库git init添加所有文件到暂存区git add .提交到本地仓库git commit -m "提交描述"首次提交需配置身份git c…...
Vue 实例的数据对象详解
Vue 实例的数据对象详解 在 Vue 中,数据对象是响应式系统的核心,也是组件状态的载体。理解数据对象的原理和使用方式是成为 Vue 专家的关键一步。我将从多个维度深入剖析 Vue 实例的数据对象。 一、数据对象的定义方式 1. Options API 中的定义 在 Options API 中,使用 …...
