作者:ChatGPT(GPT-4) & iHTCboy
摘要:本文介绍了怎么防止iOS App 被dump,包含代码稠浊、加密、完整性检查等多层防护战略,以及服务器端验证、动态加载、API安全性和多要素认证等方案。此外,监控与告警、守时安全审计和安全练习等后置方案也可以行进 App 的安全性。终究,还介绍了阻止越狱设备的施行方案,以及 DeviceCheck 和 App Attest API 等新技术方案。
一、前语
在 iOS 渠道上,保护 App 的源代码安满是开发者的一项重要任务。因为 App 或许包含活络信息和重要算法,防止源代码被不合法获取和篡改显得尤为重要。了解防止 App 的源代码被不合法反编译或许 dump,有必要采用必定的安全战略。本文将对 iOS SDK 的防 Dump 技术进行调研,并提出一些建议和可行的方案。
本陈说将从四个方面临 iOS SDK 防 dump 的技术方案进行探讨:
- 能防 dump 的技术方案
- 不能防 dump 状况下的防护方案
- 不能防 dump 且无法完全防止的状况下的安全战略
- 其他新技术方案的未来展望
二、常见 iOS dump 技术
需求防,首要需求先了解有那些侵犯技术。所以我们先介绍常见 iOS dump 技术。
在 iOS 渠道上,侵犯者或许选用多种技术方法对 App 进行破解、分析和侵犯。以下是一些常见的 iOS dump 技术方案:
1.反编译: 反编译是将二进制文件转换回源代码的进程。关于 iOS App ,侵犯者可以运用如 Hopper, IDA Pro, Ghidra 等反编译东西对 App 进行静态分析,然后获取源代码、资源文件等活络信息。
2.动态分析: 动态分析是在 App 工作时进行的分析进程。侵犯者可以运用东西,如 Frida、Cycript、GDB 等,对工作中的 App 进行实时分析、批改和调试,然后打破安全防护方法。
3.反调试: 反调试是防止调试器附加到 App 的进程。侵犯者或许会运用反调试技术,如 ptrace、sysctl 等,来检测和绕过 App 的调试防护。
4.内存 dump: 内存 dump 是从工作中的 App 中提取内存数据的进程。侵犯者可以运用如 Clutch、Fridump 等东西从 App 的内存中提取活络数据和要害信息。
5.二进制破解: 二进制破解是批改 App 的二进制文件以打破安全约束的进程。侵犯者可以运用东西,如 Hex Fiend、MachOView 等,直接批改 App 的二进制文件以完结特定目的。
6.代码注入: 代码注入是将恶意代码刺进到 App 中以完结特定功用的进程。侵犯者可以运用如 Theos、MobileSubstrate 等技术将恶意代码注入到 App 中,完结代码实行、功用批改等目的。
7.交叉编译: 侵犯者或许会运用如 LLVM、clang 等交叉编译器,将 App 编译为其他渠道的可实行文件,以便在其他渠道上进行分析和调试。
8.虚拟化: 侵犯者可以运用虚拟化技术,如 QEMU、Corellium 等,在虚拟环境中工作 iOS App ,完结对 App 的分析和调试,防止被实践设备的安全方法检测到。
下面,针对几个不太熟悉的技术进行介绍。
2.1 动态分析
Frida、Cycript 和 GDB 是常见的动态分析东西,侵犯者可以运用这些东西在工作时对 iOS App 进行实时分析、批改和调试。
接下来我们详细介绍这三种东西:
Frida
Frida 是一个跨渠道的动态代码插桩结构,支撑多种操作系统,包含 iOS。它容许开发者和安全研讨员在工作时注入自己的代码片段,以便对政策程序进行实时分析和批改。侵犯者可以运用 Frida 对 iOS App 进行以下操作:
- 检测和阻拦函数调用
- 批改函数参数和回来值
- 调用和掩盖原生函数
- 查找和读写内存
- 遍历政策和类结构
Frida 供应了丰厚的 API 和脚本言语支撑,如 Python、JavaScript 和 Swift,使得侵犯者可以轻松地编写自定义脚本,以完结特定目的。
Cycript
Cycript 是一个用于 iOS 渠道的动态分析东西,容许在工作时探查和批改 Objective-C 和 JavaScript App 。侵犯者可以运用 Cycript 进行以下操作:
- 在工作时实行 Objective-C 和 JavaScript 代码
- 检查和批改 App 的政策和变量
- 调用和重写方法
- 动态加载和卸载结构
Cycript 的交互式指令行界面使得侵犯者可以轻松地实时探查和批改政策 App 。
GDB
GDB(GNU Debugger)是一个功用健壮的源代码级调试器,支撑多种渠道,包含 iOS。侵犯者可以运用 GDB 对 iOS App 进行以下操作:
- 设置断点和单步实行
- 检查和批改内存、寄存器和变量
- 跟踪函数调用和回来
- 监控失常和信号
- 检查和批改汇编代码
GDB 供应了丰厚的指令和扩展接口,使得侵犯者可以对政策 App 进行深化的分析和调试。
2.2 反调试
ptrace 和 sysctl 是两种与调试和进程办理相关的系统调用。它们在底层操作系统中完结,并为用户级程序供应了必定程度的控制和信息。
ptrace
ptrace(process trace)是一种 UNIX 和类 UNIX 系统中的进程跟踪和调试功用。它容许一个进程观察和控制另一个进程的实行。通过 ptrace,调试器可以捕获政策进程的系统调用、信号处理和其他工作,以及检查和批改政策进程的内存和寄存器。
原理:当调试器运用 ptrace 附加到政策进程时,操作系统会将调试器的 ID 与政策进程相关。调试器可以运用 ptrace 央求来控制和监控政策进程。当政策进程遇到相关工作(如系统调用、信号处理等)时,操作系统会将工作奉告给调试器,调试器可以根据需求进行相应操作。
sysctl
sysctl 是一种用于获取和设置内核参数的接口。它用于访问内核中的数据结构,以获取和批改系统的工作时装备。sysctl 主要用于系统办理和监控任务,但在某些状况下,它也可用于检测和绕过 App 的调试防护。
原理:sysctl 通过内核和用户空间之间的通讯接口完结。用户空间的程序可以通过 sysctl 系统调用或特定的虚拟文件系统(如 /proc 和 /sys)访问内核参数。在 iOS 中,例如开发者可以运用 sysctl 函数查询进程信息,如进程列表、内存运用状况等。此外,通过检查 sysctl 回来的数据,侵犯者或许会检测到调试器的存在,然后采用相应方法绕过调试防护。
dlopen / dlsym
dlopen 和 dlsym 是动态链接库加载和符号解析的函数。它们容许工作时动态加载同享库并解析库中的符号(如函数和变量)。这些功用可以用于完结插件系统、动态代码实行和工作时代码替换等。
mmap / munmap
mmap 和 munmap 是用于内存映射办理的系统调用。它们容许进程将文件或其他资源映射到虚拟内存空间,以便直接访问和操作。mmap 可用于完结内存同享、文件 I/O 优化和动态代码加载等。
getpid / getppid
getpid 和 getppid 是用于获取进程 ID 和父进程 ID 的系统调用。它们可以用于进程办理和监控,以及分析程序的工作环境和上下文。
fork / exec
fork 和 exec 是用于创建新进程并实行程序的系统调用。fork 用于创建其时进程的副本,而 exec 用于替换其时进程的映像并实行新程序。这些功用可用于完结多任务、并发实行和进程间通讯等。
kqueue / epoll
kqueue(BSD 系统)和 epoll(Linux 系统)是用于异步 I/O 工作奉告的高效接口。它们容许进程在没有阻塞的状况下监控文件描述符、信号和其他工作。这些功用可用于完结高性能的网络服务器、工作驱动程序和异步任务处理等。
2.3 调试技术
1. 断点
断点容许调试器在特定方位暂停程序的实行。当程序到达断点时,调试器会间断程序实行,容许开发者或侵犯者检查其时状况(例如变量值和调用仓库),并逐步实行代码。断点一般通过替换政策方位的原始指令(例如运用 INT 3 指令)来设置,当处理器实行该指令时,将触发软件间断,将控制权交还给调试器。
2.单步实行
单步实行容许调试器逐行或逐指令地实行程序,这有助于开发者或侵犯者了解程序的实行进程。单步实行的原理是在每一步都设置暂时断点,并在实行完一条指令后将控制权回来给调试器。
3.函数跟踪
函数跟踪容许调试器记录程序中的函数调用次第。这关于分析程序的实行流程和了解函数之间的依赖关系十分有用。函数跟踪可以通过在函数进口处设置断点并捕获调用仓库信息来完结。
4.内存读写监控
调试器可以监控程序的内存访问,以便查找和分析程序中的数据存储和传输。内存读写监控的原理是将政策内存页面设置为不行访问,当程序访问这些页面时,触发硬件或软件失常。调试器捕获此失常,并分析引起失常的访问,然后将内存页面的访问权限康复,以便程序继续实行。
5.反汇编和代码分析
调试器可以将程序的机器代码反汇编为汇编言语标明,以便更好地了解程序的实行进程。通过对反汇编代码进行分析,开发者或侵犯者可以辨认感兴趣的代码区域,例如加密算法、密钥存储和验证逻辑等。
6.动态插桩
动态插桩容许在程序工作时刺进额定的代码,以便捕获和批改程序的行为。这可以通过批改程序的指令指针或运用特定的插桩结构(如 Frida)来完结。动态插桩可以用于实时分析和批改程序的数据和实行流程。
7.符号解析
调试器可以运用符号表(假设可用)将程序的内部地址解析为更具可读性的函数名和变量名。这有助于开发者或侵犯者更容易地了解程序的结构和功用。符号解析的原理是通过查找程序的符号表(假设可用)或运用其他可用的调试信息,将程序的内部地址与源代码中的变量名、函数名等相相关。这有助于开发者或侵犯者更容易地了解程序的结构和功用。在 iOS 开发中,调试器如 LLDB 可用于解析符号信息。
iOS 实践
在 iOS 中,这些调试技术一般结合专用的调试器和东西运用。以下是一些在 iOS 中运用这些调试技术的方法和东西:
1.断点: 在 Xcode 中,开发者可以方便地设置断点。Xcode 集成了一个健壮的调试器(LLDB),可以在 Objective-C 和 Swift 代码中设置和办理断点。
2.单步实行: 在 Xcode 的 LLDB 调试器中,开发者可以逐行或逐指令地实行代码。Xcode 供应了“Step Over”、“Step Into”和“Step Out”按钮,以便在调试进程中控制代码的实行。
3.函数跟踪: 在 LLDB 调试器中,可以运用“bt”(backtrace)指令获取其时线程的调用仓库。这有助于分析函数调用次第以及辨认潜在问题。
4.内存读写监控: LLDB 支撑内存读写监控。可以运用“watchpoint set variable”指令为特定内存地址设置监督点。当该地址被访问或批改时,LLDB 会间断程序实行并奉告开发者。
5.反汇编和代码分析: 在 LLDB 中,可以运用“disassemble”指令检查反汇编的汇编代码。其他,还可以运用第三方东西,如 Hopper Disassembler 和 IDA Pro,进行更深化的代码分析。
6.动态插桩: 在 iOS 中,可以运用 Frida、Cycript 等东西进行动态插桩。这些东西容许开发者和安全研讨员在工作时注入自定义脚本,以实时分析和批改 App 的行为。
7.符号解析: 在 LLDB 调试器中,可以运用“image lookup”指令查找符号信息。这有助于将内部地址解析为更具可读性的函数名和变量名。
三、能防 dump 的技术方案
能防 dump 的技术方案,意思是做了就可以 “防止” dump,并不是真能防止 dump 操作。
1.代码稠浊:通过对源代码进行稠浊处理,使得源代码难以阅读和了解,增加侵犯者分析代码的难度。
2.加密技术:对要害数据和代码进行加密处理,确保在被 dump 时,侵犯者无法直接获取活络信息。
3.完整性检测:对 App 代码进行完整性检测,如发现代码被篡改,则触发相应的安全战略。
4.工作环境检测:检测其时 App 工作环境是否安全,如发现越狱设备或调试环境,则触发相应的安全战略。
3.1 代码稠浊
对源代码进行稠浊处理,包含变量名、函数名、类名等的替换,以及控制流稠浊等。这使得源代码难以阅读和了解,增加侵犯者分析代码的难度。
一个简略的稠浊示例:
class HelloWorld {
func greeting() {
print("Hello, World!")
}
}
let helloWorld = HelloWorld()
helloWorld.greeting()
稠浊后的代码:
class A1B2C3 {
func D4E5F6() {
print("Hello, World!")
}
}
let a1b2c3 = A1B2C3()
a1b2c3.D4E5F6()
3.2 加密技术
对要害数据和代码进行加密处理,确保在被 dump 时,侵犯者无法直接获取活络信息。
一个运用 AES 加密的示例:
import CryptoSwift
let key = "1234567890123456" // 16 字节的密钥
let iv = "abcdefghijklmnop" // 16 字节的初始化向量
let plaintext = "Sensitive Data"
do {
let encrypted = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .pkcs7).encrypt(plaintext.bytes)
let encryptedData = Data(encrypted)
print("Encrypted data: \(encryptedData)")
let decrypted = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .pkcs7).decrypt(encrypted)
let decryptedData = Data(decrypted)
print("Decrypted data: \(String(data: decryptedData, encoding: .utf8)!)")
} catch {
print("Error: \(error)")
}
3.3 完整性检测
对 App 代码进行完整性检测,如发现代码被篡改,则触发相应的安全战略。
一个简略的完整性检测示例:
func verifyIntegrity() -> Bool {
// 预先核算的 App 代码哈希值
let expectedHash = "f0e4c2f76c58916ec258f246851bea0918b26a25"
// 实践核算的 App 代码哈希值
let actualHash = calculateHash()
return expectedHash == actualHash
}
func calculateHash() -> String {
// 核算 App 代码哈希值的逻辑,可以运用 SHA1、SHA256 等哈希算法
// ...
}
3.4 工作环境检测
检测其时 App 工作环境是否安全,如发现越狱设备或调试环境,则触发相应的安全战略。
一个简略的工作环境检测示例:
// 越狱设备
func isJailbroken() -> Bool {
let fileManager = FileManager.default
let paths = ["/Applications/Cydia.app",
"/Library/MobileSubstrate/MobileSubstrate.dylib",
"/bin/bash", "/usr/sbin/sshd", "/etc/apt"]
for path in paths {
if fileManager.fileExists(atPath: path) {
return true
}
}
return false
}
// 调试环境
func isBeingDebugged() -> Bool {
var info = kinfo_proc()
var size = MemoryLayout<kinfo_proc>.size
var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
if sysctl(&mib, 4, &info, &size, nil, 0) == -1 {
print("Error: Could not get process info.")
return false
}
return (info.kp_proc.p_flag & P_TRACED) != 0
}
func checkEnvironment() {
if isJailbroken() {
print("Warning: Running on a jailbroken device.")
// 触发相应的安全战略
}
if isBeingDebugged() {
print("Warning: Running in a debugging environment.")
// 触发相应的安全战略
}
}
checkEnvironment()
3.5 ptrace 反调试
ptrace 是一种用于跟踪和操作其他进程的系统调用。侵犯者可以运用 ptrace 附加到政策进程,以便在工作时读写内存、设置断点和单步实行等。为了防止这种调试行为,开发者可以在 App 中运用 ptrace,使其在检测到调试器时拒绝附加。这种方法一般称为 “anti-ptrace
“。
一个简略的反 ptrace 示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <signal.h>
void anti_ptrace() {
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1) {
printf("Debugger detected! Exiting...\n");
// Kill the process when a debugger is detected
kill(getpid(), SIGKILL);
}
}
int main() {
anti_ptrace();
printf("Hello, World!\n");
return 0;
}
ptrace(PTRACE_TRACEME, 0, NULL, NULL) 是一个运用 ptrace 系统调用的特殊用法。在这种状况下,它的目的是让其时进程( App )被其父进程(调试器)跟踪。下面是各个参数的含义:
-
PTRACE_TRACEME
:这是 ptrace 系统调用的一个央求类型。PTRACE_TRACEME 用于奉告内核,让其时进程的父进程跟踪其时进程。换句话说,它容许调试器控制和监督 App 的实行。 -
0
:这是 ptrace 调用的第二个参数,标明要跟踪的政策进程的 ID。在 PTRACE_TRACEME 的状况下,我们设置为 0,标明其时进程( App )是要跟踪的政策。 -
NULL
:这是 ptrace 调用的第三个参数,一般标明要读/写的地址或数据。在 PTRACE_TRACEME 的状况下,此参数不运用,因此设置为 NULL。 -
NULL
:这是 ptrace 调用的第四个参数,一般用于传递附加信息或数据。在 PTRACE_TRACEME 的状况下,此参数不运用,因此设置为 NULL。
在这个例子中,我们运用 PTRACE_TRACEME 央求调用 ptrace。正常状况下,只需父进程(即调试器)才干对子进程(即 App )宣告 PTRACE_TRACEME 央求。但是,假设 App 本身宣告 PTRACE_TRACEME 央求并成功,那么意味着没有调试器附加到 App 。假设 PTRACE_TRACEME 央求失利(回来 -1),则阐明已有调试器附加到 App 。这时,我们可以采用相应方法,如输出正告信息、间断进程或实行其他安全战略。
需求留意的是,虽然反 ptrace 可以行进 App 的安全性,但它并不是必定可靠的。经验丰厚的侵犯者或许会运用更杂乱的技术来绕过反 ptrace 保护,例如通过批改 ptrace 函数的完结或运用其他调试接口。
绕过反 ptrace 保护:
批改 ptrace 函数的完结:侵犯者可以运用动态链接器(如 LD_PRELOAD)将自定义版其他 ptrace 函数加载到 App 中。自定义版其他 ptrace 函数可以在检测到 PTRACE_TRACEME 央求时不实行任何操作,然后绕过反 ptrace 保护。以下是一个简略的示例:
#include <sys/ptrace.h>
#include <errno.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data) {
if (request == PTRACE_TRACEME) {
// 当检测到 PTRACE_TRACEME 央求时,不实行任何操作
return 0;
}
// 关于其他 ptrace 央求,调用原始的 ptrace 函数
return syscall(SYS_ptrace, request, pid, addr, data);
}
要运用此自定义 ptrace 函数,侵犯者可以将其编译为同享库(如 libcustom_ptrace.so),然后在发动 App 时设置 LD_PRELOAD 环境变量,以便在 App 中运用自定义版其他 ptrace 函数。
$ gcc -shared -fPIC custom_ptrace.c -o libcustom_ptrace.so
$ LD_PRELOAD=./libcustom_ptrace.so ./target_app
因此,为了确保 App 的安全,最好选用多层防护战略,结合其他安全方法,如代码稠浊、加密和完整性检查等。
3.6 sysctl 反调试
sysctl 是一个用于查询和批改内核参数的系统调用。它供应了许多用于获取进程相关信息的选项,其间一些选项可以用来检测调试状况。
在 macOS 和 iOS 上,可以运用 sysctl 系统调用检查进程标志(例如 P_TRACED),以确认政策进程是否正在被调试。
以下是一个简略的示例:
#include <stdio.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <unistd.h>
// 运用 sysctl 检测其时进程是否正在被调试
bool is_being_debugged() {
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
struct kinfo_proc info;
size_t info_size = sizeof(info);
if (sysctl(mib, 4, &info, &info_size, NULL, 0) == -1) {
perror("sysctl");
return false;
}
return (info.kp_proc.p_flag & P_TRACED) != 0;
}
int main() {
if (is_being_debugged()) {
printf("This process is being debugged!\\n");
// 在检测到调试行为时,采用方法,如间断 App
return 1;
} else {
printf("This process is not being debugged.\\n");
}
// App 正常实行
return 0;
}
在供应的代码示例中,bool is_being_debugged() 函数用于检测其时进程是否正在被调试。这个函数没有参数。
以下是对这个函数中触及的每个变量和过程的详细解释:
-
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};:mib 是一个整数数组,包含 4 个元素,用于 sysctl 系统调用。这些元素别离标明:
a. CTL_KERN:标明我们要查询的是内核相关的参数。
b.KERN_PROC:标明我们要查询的是进程相关的参数。
c.KERN_PROC_PID:标明我们要根据进程 ID 查询特定进程的信息。
d.getpid():这是一个系统调用,用于获取其时进程的 ID。这意味着我们将查询其时进程的信息。 -
struct kinfo_proc info;:声明一个 kinfo_proc 结构体变量 info,用于存储 sysctl 回来的进程信息。
-
size_t info_size = sizeof(info);:声明一个 size_t 类型的变量 info_size,用于存储 info 结构体的大小。sysctl 函数需求这个信息来填充 info 结构体。
-
if (sysctl(mib, 4, &info, &info_size, NULL, 0) == -1) {…}:调用 sysctl 函数来获取进程信息。sysctl 函数的参数如下:
a.mib:标明查询的参数数组。
b.4:标明 mib 数组的长度。
c.&info:指向 kinfo_proc 结构体的指针,sysctl 将把查询效果存储到这个结构体中。
d.&info_size:指向 info_size 变量的指针,奉告 sysctl 函数 info 结构体的大小。sysctl 函数还会通过这个指针回来实践填充的数据大小。
e.NULL, 0:这两个参数标明我们不需求设置任何内核参数,只需求获取进程信息。
假设 sysctl 函数回来 -1,标明发生了过错。在这种状况下,函数通过 perror(“sysctl”) 输出过错信息,并回来 false。 -
return (info.kp_proc.p_flag & P_TRACED) != 0;:检查进程标志中的 P_TRACED 标志。info.kp_proc.p_flag 包含进程的标志,我们运用按位与运算符(&)检查 P_TRACED 标志是否被设置。假设该标志被设置(效果不等于 0),则标明该进程正在被调试,函数回来 true;不然,回来 false。
这段代码通过 sysctl 查询其时进程的 kinfo_proc 结构体,然后检查 P_TRACED 标志。假设 P_TRACED 标志被设置,则标明该进程正在被调试。
请留意,这种检测方法或许会遭到侵犯者的绕过,因为经验丰厚的侵犯者或许会运用更高档的技术,如批改 sysctl 的完结或运用其他调试接口。
绕过反 sysctl 保护
批改 sysctl 的完结:侵犯者可以运用动态库注入或其他代码注入技术,以便在工作时替换或批改 sysctl 函数的完结。这样,即使 App 运用 sysctl 来检测调试行为,侵犯者仍然可以控制其输出,然后防止被检测。例如,侵犯者可以运用以下代码片段来完结自定义的 sysctl 函数,将 P_TRACED 标志设置为 0:
int custom_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
// 调用原始的 sysctl 函数
int result = original_sysctl(name, namelen, oldp, oldlenp, newp, newlen);
// 批改回来的进程标志,铲除 P_TRACED 标志
if (result == 0 && name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID) {
struct kinfo_proc *info = (struct kinfo_proc *)oldp;
info->kp_proc.p_flag &= ~P_TRACED;
}
return result;
}
然后,侵犯者可以运用动态库注入或 Tweak 等将此自定义 sysctl 函数替换为 App 中的原始 sysctl 函数。
反反调试(Tweak)
这儿针对ptrace、sysctl、syscall来反反调试,做法就很简略了,hook函数,判别参数,回来效果。
#import <substrate.h>
#import <sys/sysctl.h>
static int (*orig_ptrace) (int request, pid_t pid, caddr_t addr, int data);
static int my_ptrace (int request, pid_t pid, caddr_t addr, int data){
if(request == 31){
NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH");
return 0;
}
return orig_ptrace(request,pid,addr,data);
}
static void* (*orig_dlsym)(void* handle, const char* symbol);
static void* my_dlsym(void* handle, const char* symbol){
if(strcmp(symbol, "ptrace") == 0){
NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol");
return (void*)my_ptrace;
}
return orig_dlsym(handle, symbol);
}
static int (*orig_sysctl)(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize);
static int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){
int ret = orig_sysctl(name,namelen,info,infosize,newinfo,newinfosize);
if(namelen == 4 && name[0] == 1 && name[1] == 14 && name[2] == 1){
struct kinfo_proc *info_ptr = (struct kinfo_proc *)info;
if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){
NSLog(@"[AntiAntiDebug] - sysctl query trace status.");
info_ptr->kp_proc.p_flag ^= P_TRACED;
if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){
NSLog(@"[AntiAntiDebug] trace status reomve success!");
}
}
}
return ret;
}
static void* (*orig_syscall)(int code, va_list args);
static void* my_syscall(int code, va_list args){
int request;
va_list newArgs;
va_copy(newArgs, args);
if(code == 26){
request = (long)args;
if(request == 31){
NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH");
return nil;
}
}
return (void*)orig_syscall(code, newArgs);
}
%ctor{
MSHookFunction((void *)MSFindSymbol(NULL,"_ptrace"),(void*)my_ptrace,(void**)&orig_ptrace);
MSHookFunction((void *)dlsym,(void*)my_dlsym,(void**)&orig_dlsym);
MSHookFunction((void *)sysctl,(void*)my_sysctl,(void**)&orig_sysctl);
MSHookFunction((void *)syscall,(void*)my_syscall,(void**)&orig_syscall);
NSLog(@"[AntiAntiDebug] Module loaded!!!");
}
因此,最好选用多层防护战略,并与其他安全方法(如代码稠浊、加密、完整性检查等)相结合,以增强 App 的安全性。
3.7 信号反调试
失常处理
通过设置失常处理函数,我们可以捕获调试器引发的失常(如断点、单步实行等),然后完结反调试功用。
#include <signal.h>void signal_handler(int signal) {
// 处理失常信号,如退出程序
exit(1);
}
void setup_signal_handler() {
signal(SIGTRAP, signal_handler); // 断点信号
signal(SIGSTOP, signal_handler); // 间断信号
}
在 App 进口点调用 setup_signal_handler() 函数,即可设置失常处理函数。
四、不能防 dump 状况下的防护方案
对防止 dump 或许无直接效果,但可以行进 App 的安全性。
-
服务器端验证: 将要害功用和活络数据存储在服务器端,通过 API 央求的方法进行访问,减少客户端的侵犯面。
-
动态加载: 在工作时动态加载要害代码和资源,使侵犯者无法直接从静态文件中获取活络信息。
-
API 安全性: 选用 HTTPS 通讯,对 API 央求进行签名验证,防止中间人侵犯和 API 篡改。
-
多要素认证: 在要害操作中引入多要素认证机制,下降单一认证方法被破解的风险。例如短信验证码、人脸辨认等。
五、不能防 dump 且无法完全防止的状况下的安全战略
对防止 dump 或许无直接效果,且对安全性不起效果,归于后置的方案战略。
1.监控与告警: 实时监控 App 的工作状况,如发现失常行为或安全工作,及时触发告警,奉告开发者进行处理。守时监控 SDK 的安全状况,收集安全工作和威胁情报。结合实时数据,对防护战略进行调整和优化。
2.守时安全审计: 守时进行安全审计,检查 App 的安全状况,发现潜在的安全问题,并采用相应的方法进行批改。
3.安全练习: 行进开发团队的安全意识和技术,确保在开发进程中可以充分考虑到安全要素,然后下降 App 被侵犯的风险。守时进行安全练习,以便团队成员了解最新的安全威胁和防护方法。
六、其他新技术方案的未来展望
跟着科技的不断开展和行进,一直不断呈现立异的安全技术方案,需求时间注重行业动态,以便在安全应战时更好地保护 App 的安全。
1.人工智能与机器学习: 运用人工智能和机器学习技术自动检测代码中的安全问题,行进安全检测的功率和准确性。
2.差分隐私核算: 隐私核算技术,如同态加密、安全多方核算等,可以在不解密数据的状况下进行数据处理和核算,然后在保护数据隐私的一起,完结数据的有效运用。
3.自适应安全: 凭仗人工智能和机器学习技术,完结自适应安全系统,可以根据实时的安全状况和威胁情报,动态调整 App 的安全战略,更有效地防护侵犯。
七、可行性方案
针对 App 或 SDK 安全,分析那些技术我们或许协助我们行进安全性和防备篇安全风险。
7.1 越狱环境
以上一切 dump 方案,都是因为越狱导致可以破解,所以不能越狱就防止99%黑产。
- 越狱 ==> 拿到系统权限
- 重签 ==> 拿到 app 的权限
建议:阻止越狱设备运用 App !!!
假设检测到越狱设备,您可以选择禁用某些功用或许约束 App 的运用。如间断app、删去活络数据、躲藏某些功用等等。
施行方案
在 App 中增加越狱检测代码,以判别设备是否现已越狱。
- 检查越狱相关文件和目录:越狱设备一般包含一些特定的文件和目录,例如Cydia、MobileSubstrate等。检查这些文件和目录的存在可以协助判别设备是否越狱。
- 检查运用沙箱保护:越狱设备的运用沙箱保护或许会被损坏。检验访问受保护的系统目录,例如“/private”,假设可以访问,则或许是越狱设备。
- 检查不合法设备的运用:越狱设备答运用户设备不合法的运用。检查已设备的运用列表,寻觅来自非官方来历的运用,或许有助于发现越狱设备。
- 检查进程权限:越狱设备上的进程或许具有更高的权限。比较 App 的实践权限和预期权限,假设权限失常,则或许是越狱设备。
- 运用私有API:iOS的私有API在越狱设备上可用。检验调用这些API,假设成功实行,则或许是越狱设备。
- 检查动态链接库:越狱设备或许运用动态链接库(如MobileSubstrate)来注入代码。检查工作时环境中加载的动态链接库,寻觅失常的库文件,或许有助于发现越狱设备。
其他,针对新的环境改动,如 Mac Catalyst 或 Designed for iPad 等环境,都或许工作 iOS App,需求开发者自行判别是否容许。
检查设备越狱的代码许多,以下是 GitHub 开源仓库 DTTJailbreakDetection 代码示例:
+ (BOOL)isJailbroken
{
#if !(TARGET_IPHONE_SIMULATOR)
if (@available(iOS 14.0, *)) {
if ([NSProcessInfo processInfo].isiOSAppOnMac)
{
return NO;
}
}
FILE *file = fopen("/Applications/Cydia.app", "r");
if (file) {
fclose(file);
return YES;
}
file = fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r");
if (file) {
fclose(file);
return YES;
}
file = fopen("/bin/bash", "r");
if (file) {
fclose(file);
return YES;
}
file = fopen("/usr/sbin/sshd", "r");
if (file) {
fclose(file);
return YES;
}
file = fopen("/etc/apt", "r");
if (file) {
fclose(file);
return YES;
}
file = fopen("/usr/bin/ssh", "r");
if (file) {
fclose(file);
return YES;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:@"/Applications/Cydia.app"]) {
return YES;
} else if ([fileManager fileExistsAtPath:@"/Library/MobileSubstrate/MobileSubstrate.dylib"]) {
return YES;
} else if ([fileManager fileExistsAtPath:@"/bin/bash"]) {
return YES;
} else if ([fileManager fileExistsAtPath:@"/usr/sbin/sshd"]) {
return YES;
} else if ([fileManager fileExistsAtPath:@"/etc/apt"]) {
return YES;
} else if ([fileManager fileExistsAtPath:@"/usr/bin/ssh"]) {
return YES;
}
// Check if the app can access outside of its sandbox
NSError *error = nil;
NSString *string = @".";
[string writeToFile:@"/private/jailbreak.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!error) {
[fileManager removeItemAtPath:@"/private/jailbreak.txt" error:nil];
return YES;
}
// Check if the app can open a Cydia's URL scheme
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]]) {
return YES;
}
#endif
return NO;
}
7.2 DeviceCheck 和 App Attest API
DeviceCheck 和 App Attest 是 Apple 供应的两个用于设备验证和 App 验证的 API。它们旨在行进 App 的安全性和保护用户隐私。
DeviceCheck API
DeviceCheck API 容许开发者在苹果服务器上存储每台设备的少数数据(两个位)。这可以用于辨认设备是否从前与您的服务器进行过交互,而无需获取设备的仅有标识符。
DeviceCheck 数据在 App 被删去和从头设备后仍然坚持不变。这关于辨认设备的仅有性十分有用。
为了运用 DeviceCheck API,您需求在开发者帐户中启用 DeviceCheck 功用,并在您的 App 和服务器端代码中集成相应的 API。
DeviceCheck 服务回来的两个位(bit0 和 bit1)是针对一台详细的 iOS 设备(iPhone 或 iPad)的,而不是与 Apple ID 账号相关的。这意味着,关于同一台设备上的不同 App ,这两个位都是相同的,而不是针对特定的 Apple ID 账号。这样,开发者可以运用这两个位来存储与特定设备相关的信息,如符号设备是否现已兑换过优惠券或是否参加过活动。
App Attest API
App Attest API 用于验证 iOS App 的完整性和真实性。它可以检测 App 是否被篡改或替换,并确认它是由可信赖的开发者发布的。通过运用 App Attest API,您可以确保您的服务器与真实、未经篡改的 App 进行通讯。
App Attest API 为 App 供应了一个签名密钥,用于在 App 与开发者服务器之间的通讯中生成签名。开发者服务器可以运用 Apple 供应的验证服务来验证签名,确保收到的央求来自于真实且未被篡改的 App 。
要运用 App Attest API,您需求在开发者帐户中启用 App Attest 功用,并在您的 App 和服务器端代码中集成相应的 API。
八、总结
本陈说探讨了防止 iOS dump 的可行性,议论了几种行进 iOS App 安全性的战略,并侧重了监测、审计和安全练习的重要性。陈说还研讨了一些新式技术,如人工智能和差分隐私核算,这些技术有或许行进 iOS App 的安全性。终究,陈说议论了这些方法的局限性和应战,并侧重了需求进行继续的研讨和开发,以进一步增强 iOS App 的安全性。
在应对 iOS SDK dump 的进程中,开发者需求注重多个方面的技术和战略,从防护到曲线救国,再到行进安全性,都需求采用综合性的方法。此外,跟着科技的开展,未来将会呈现更多立异的安全技术方案,为开发者供应更健壮的安全确保。
要保护好运用程序的安全,开发者需求不断行进本身的安全意识和技术,注从头技术的开展,并将安全融入运用程序的开发、工作和保护全进程。一起,与安全范畴的其他从业者坚持严密协作,共同应对不断改动的安全应战,为用户供应安全、可靠的运用程序。
终究,需求侧重的是,本陈说的内容仅供参考,实践运用时或许需求根据详细需求进行恰当的调整和优化。一起,侵犯者或许会采用更杂乱的方法绕过这些防护方法,因此开发者需求坚持对安全范畴的注重,继续改进和完善安全战略。
总归,本陈说全面概述了iOS dump 防备,并供应了一系列行进 iOS App 安全性的战略。虽然这些方法的有效性存在必定局限性,但是显着,在安全技术范畴进行继续的研讨和开发将继续是未来 iOS App 安全的要害。
欢迎我们议论区一同议论交流~
我们是37手游移动客户端开发团队,致力于为游戏行业供应高质量的SDK开发服务。
欢迎注重我们,了解更多移动开发和游戏 SDK 技术动态~
技术问题/交流/进群等可以加官方微信 MobileTeam37
参考引用
- 凭仗新的 App Attest API 来验证您 app 的完整性 – Apple Developer
- 安全性概览 – Apple Developer
- DeviceCheck | Apple Developer Documentation
- Accessing and Modifying Per-Device Data | Apple Developer Documentation
- Establishing your app’s integrity | Apple Developer Documentation
- 运用 iPhone 的内建隐私和安全性保护 – 官方 Apple 支撑 (中国)
- 细数iOS上的那些安全防护 – 知乎
- 让你的运用远离越狱:iOS 14 App Attest 防护功用-ios14防越狱检测
- 关于反调试&反反调试那些事 – 干货共享 – 睿论坛
- 一步一步在debugserver中绕过ptrace反调试 – 干货共享 – 睿论坛
注:如若转载,请注明来历。