-
-
[原创]某QP平台设备环境绕过技术深度解析:从Frida Hook到系统级防护突破
-
发表于: 1天前 267
-
作者:小白 ???? | iOS安全研究员发布日期:2026年3月29日关键词:iOS安全、Frida、逆向工程、设备环境检测、反调试绕过、QP平台
在移动安全领域,各类平台为了保护其业务安全,部署了复杂的设备环境检测机制。本文将以某知名QP平台为例,深入解析其iOS客户端的多层防护体系,并展示如何通过Frida实现全方位的环境绕过。本文内容仅用于安全研究和技术学习,请勿用于非法用途。
通过对目标应用的分析,我们发现其防护体系分为五个层级:
QP平台通过监控线程名来检测Frida,我们的应对策略:
对于内联的SVC指令(系统调用),我们可以进行运行时补丁:
对于应用开发者:
本文详细分析了某QP平台iOS客户端的防护体系,并提供了完整的Frida绕过方案。关键技术点包括:
重要提示:
作者简介:小白 ????,专注于iOS/Android移动安全研究,在逆向工程、漏洞挖掘、安全防护等领域有丰富经验。致力于推动移动安全技术发展,分享技术研究成果。
技术交流:欢迎通过CSDN、看雪等平台进行技术交流,共同进步。
版权声明:本文为原创技术文章,转载请注明出处。技术细节可能因平台更新而变化,请以实际测试为准。
graph TD
A[应用层防护] --> B[运行时检测]
A --> C[文件系统检测]
A --> D[网络通信检测]
B --> E[反调试机制]
B --> F[代码完整性校验]
C --> G[越狱环境检测]
C --> H[注入工具检测]
D --> I[证书绑定]
D --> J[协议混淆]
// 线程名关键词检测
var fridaThreadKeywords = ["frida", "gum-js", "gmain", "gdbus", "pool-frida", "pool-spawner", "linjector"];
function isFridaThreadName(name) {
if (!name) return false;
for (var i = 0; i < fridaThreadKeywords.length; i++) {
if (name.indexOf(fridaThreadKeywords[i]) !== -1) return true;
}
return false;
}
// 持续清理线程名
function cleanFridaThreads() {
try {
var _pthread_from_mach = findAnyExport("pthread_from_mach_thread_np");
var _pthread_setname = findExport("pthread_setname_np");
var _task_threads = findExport("task_threads");
var _thread_info = findExport("thread_info");
if (!_pthread_from_mach || !_pthread_setname || !_task_threads || !_thread_info) return;
var pthread_from_mach = new NativeFunction(_pthread_from_mach, 'pointer', ['uint32']);
var pthread_setname = new NativeFunction(_pthread_setname, 'int', ['pointer', 'pointer']);
var task_threads_native = new NativeFunction(_task_threads, 'int', ['uint32', 'pointer', 'pointer']);
var thread_info_fn = new NativeFunction(_thread_info, 'int', ['uint32', 'int', 'pointer', 'pointer']);
// 获取所有线程并重命名可疑线程
var threadListPtr = Memory.alloc(Process.pointerSize);
var threadCountPtr = Memory.alloc(4);
var fakeName = Memory.allocUtf8String("com.apple.CFThread");
if (task_threads_native(task, threadListPtr, threadCountPtr) === 0) {
var threadList = threadListPtr.readPointer();
var threadCount = threadCountPtr.readU32();
for (var t = 0; t < threadCount; t++) {
var machThread = threadList.add(t * 4).readU32();
// 获取线程信息并检查线程名
if (isFridaThreadName(tname)) {
var pth = pthread_from_mach(machThread);
if (!pth.isNull()) {
pthread_setname(pth, fakeName);
console.log("[+] Renamed thread:", tname);
}
}
}
}
} catch(e) {}
}
// 每500ms执行一次清理
setInterval(cleanFridaThreads, 500);
var _ptrace = findExport("ptrace");
if (_ptrace) {
Interceptor.attach(_ptrace, {
onEnter: function(args) {
// PT_DENY_ATTACH = 31
if (args[0].toInt32() === 31) {
args[0] = ptr(0); // 修改为无效值
console.log("[+] ptrace blocked");
}
}
});
}
var _sysctl = findExport("sysctl");
if (_sysctl) {
var orig_sysctl = new NativeFunction(_sysctl, 'int', ['pointer', 'uint32', 'pointer', 'pointer', 'pointer', 'uint32']);
Interceptor.replace(_sysctl, new NativeCallback(function(name, namelen, oldp, oldlenp, newp, newlen) {
var ret = orig_sysctl(name, namelen, oldp, oldlenp, newp, newlen);
// 检测KERN_PROC查询
if (namelen >= 4 && !name.isNull()) {
var ctl0 = name.readS32();
var ctl1 = name.add(4).readS32();
// CTL_KERN(1) / KERN_PROC(14)
if (ctl0 === 1 && ctl1 === 14) {
// 清理P_TRACED标志位 (0x800)
if (!oldp.isNull()) {
var flags = oldp.add(32).readU32();
if (flags & 0x800) {
oldp.add(32).writeU32(flags & ~0x800);
console.log("[+] sysctl P_TRACED cleared");
}
}
}
}
return ret;
}, 'int', ['pointer', 'uint32', 'pointer', 'pointer', 'pointer', 'uint32']));
}
var _getppid = findExport("getppid");
if (_getppid) {
Interceptor.replace(_getppid, new NativeCallback(function() {
return 1; // 伪装为init进程的子进程
}, 'int', []));
}
var blockedPaths = [
"/usr/sbin/frida-server",
"/var/jb/usr/sbin/frida-server",
"/var/jb", // 越狱环境
"/Library/MobileSubstrate",
"/bin/bash",
"/usr/bin/ssh",
"/etc/apt",
"/usr/libexec/cydia",
"/usr/lib/frida",
];
function shouldBlock(pathPtr) {
try {
var p = pathPtr.readUtf8String();
if (!p) return false;
for (var i = 0; i < blockedPaths.length; i++) {
if (p.indexOf(blockedPaths[i]) === 0) return true;
}
} catch(e) {}
return false;
}
// 拦截文件访问相关系统调用
var _access = findExport("access");
if (_access) {
Interceptor.attach(_access, {
onEnter: function(args) { this.block = shouldBlock(args[0]); },
onLeave: function(retval) {
if (this.block) retval.replace(ptr(-1)); // 返回失败
}
});
}
// 拦截stat系统调用
var _stat = findExport("stat");
if (_stat) {
Interceptor.attach(_stat, {
onEnter: function(args) { this.block = shouldBlock(args[0]); },
onLeave: function(retval) {
if (this.block) retval.replace(ptr(-1));
}
});
}
if (ObjC.available) {
try {
var NSFileManager = ObjC.classes.NSFileManager;
if (NSFileManager) {
Interceptor.attach(NSFileManager["- fileExistsAtPath:"].implementation, {
onEnter: function(args) {
try {
var path = ObjC.Object(args[2]).toString();
this.block = false;
for (var i = 0; i < blockedPaths.length; i++) {
if (path.indexOf(blockedPaths[i]) === 0) {
this.block = true;
break;
}
}
} catch(e) {}
},
onLeave: function(retval) {
if (this.block) retval.replace(ptr(0)); // 返回NO
}
});
}
} catch(e) {}
}
var dyld_image_count = findExport("_dyld_image_count");
var dyld_get_image_name = findExport("_dyld_get_image_name");
var dyld_get_image_header = findExport("_dyld_get_image_header");
if (dyld_image_count && dyld_get_image_name && dyld_get_image_header) {
var orig_count = new NativeFunction(dyld_image_count, 'uint32', []);
var orig_name = new NativeFunction(dyld_get_image_name, 'pointer', ['uint32']);
var orig_header = new NativeFunction(dyld_get_image_header, 'pointer', ['uint32']);
// 建立干净镜像索引
var total = orig_count();
var cleanImages = [];
for (var i = 0; i < total; i++) {
try {
var name = orig_name(i).readUtf8String();
// 过滤Frida相关镜像
if (name && name.toLowerCase().indexOf("frida") === -1 &&
name.toLowerCase().indexOf("gadget") === -1) {
cleanImages.push(i);
} else {
console.log("[+] dyld hiding image:", name);
}
} catch(e) {
cleanImages.push(i);
}
}
// 替换dyld相关函数
Interceptor.replace(dyld_image_count, new NativeCallback(function() {
return cleanImages.length;
}, 'uint32', []));
Interceptor.replace(dyld_get_image_name, new NativeCallback(function(idx) {
if (idx < cleanImages.length) return orig_name(cleanImages[idx]);
return ptr(0);
}, 'pointer', ['uint32']));
}
var _dlopen = findAnyExport("dlopen");
if (_dlopen) {
Interceptor.attach(_dlopen, {
onEnter: function(args) {
this.block = false;
try {
var path = args[0].readUtf8String();
if (path) {
var lower = path.toLowerCase();
// 拦截Frida相关库加载
if (lower.indexOf("frida") !== -1 ||
lower.indexOf("gadget") !== -1 ||
lower.indexOf("gum") !== -1) {
this.block = true;
console.log("[+] dlopen blocked:", path);
}
}
} catch(e) {}
},
onLeave: function(retval) {
if (this.block) retval.replace(ptr(0)); // 返回NULL
}
});
}
var _connect = findExport("connect");
if (_connect) {
Interceptor.attach(_connect, {
onEnter: function(args) {
this.block = false;
try {
var sockaddr = args[1];
var sa_family = sockaddr.add(1).readU8(); // AF_INET = 2
if (sa_family === 2) {
var port_raw = sockaddr.add(2).readU16();
// 网络字节序转主机字节序
var port = ((port_raw & 0xFF) << 8) | ((port_raw >> 8) & 0xFF);
// 拦截Frida默认端口
if (port === 27042 || port === 27043) {
this.block = true;
console.log("[+] connect to frida port blocked:", port);
}
}
} catch(e) {}
},
onLeave: function(retval) {
if (this.block) retval.replace(ptr(-1)); // 返回错误
}
});
}
// 拦截SIGABRT信号
var _pthread_kill = findExport("pthread_kill");
if (_pthread_kill) {
Interceptor.replace(_pthread_kill, new NativeCallback(function(thread, sig) {
if (sig === 6) { // SIGABRT
console.log("[+] pthread_kill SIGABRT blocked!");
return 0;
}
return 0;
}, 'int', ['pointer', 'int']));
}
// 拦截raise调用
var _raise = findExport("raise");
if (_raise) {
Interceptor.replace(_raise, new NativeCallback(function(sig) {
if (sig === 6) {
console.log("[+] raise SIGABRT blocked!");
return 0;
}
return 0;
}, 'int', ['int']));
}
// 拦截abort调用
var _abort = findExport("abort");
if (_abort) {
Interceptor.replace(_abort, new NativeCallback(function() {
console.log("[+] abort() blocked!");
}, 'void', []));
}
// 拦截exit系列函数
var _exit_fn = findExport("exit");
if (_exit_fn) {
Interceptor.replace(_exit_fn, new NativeCallback(function(code) {
console.log("[+] exit() BLOCKED, code:", code);
// 打印调用栈便于调试
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
}, 'void', ['int']));
}
// 拦截系统调用退出
var _syscall = findExport("syscall");
if (_syscall) {
var orig_syscall = new NativeFunction(_syscall, 'int', ['int', 'int', 'int', 'int', 'int', 'int', 'int']);
Interceptor.replace(_syscall, new NativeCallback(function(number, a1, a2, a3, a4, a5, a6) {
// SYS_exit = 1
if (number === 1) {
console.log("[+] syscall(SYS_exit) BLOCKED");
return 0;
}
// SYS_ptrace = 26
if (number === 26 && a1 === 31) { // ptrace PT_DENY_ATTACH
console.log("[+] syscall(SYS_ptrace, PT_DENY_ATTACH) BLOCKED");
return 0;
}
return orig_syscall(number, a1, a2, a3, a4, a5, a6);
}, 'int', ['int', 'int', 'int', 'int', 'int', 'int', 'int']));
}
// 扫描并补丁内联SYS_exit指令
(function() {
try {
var mods = Process.enumerateModules();
var targetMods = [];
// 筛选目标模块
for (var i = 0; i < mods.length; i++) {
var name = mods[i].name.toLowerCase();
var path = mods[i].path || "";
// 只处理应用相关模块
if (path.indexOf("/var/containers") !== -1 || path.indexOf(".app/") !== -1) {
targetMods.push(mods[i]);
}
}
var totalPatched = 0;
for (var t = 0; t < targetMods.length; t++) {
var mod = targetMods[t];
// 搜索SVC指令模式
var svcPattern = "01 10 00 D4";
var matches = Memory.scanSync(mod.base, mod.size, svcPattern);
var patchCount = 0;
for (var m = 0; m < matches.length; m++) {
try {
var svcAddr = matches[m].address;
var prevInsn = svcAddr.sub(4).readU32();
var syscallNum = -1;
// 解析系统调用号
if ((prevInsn & 0xFFE0001F) === 0xD2800010) {
syscallNum = (prevInsn >> 5) & 0xFFFF;
}
// 如果是SYS_exit(1),进行补丁
if (syscallNum === 1) {
Memory.patchCode(svcAddr.sub(4), 8, function(code) {
var w = new Arm64Writer(code, { pc: svcAddr.sub(4) });
w.putNop(); // 替换为NOP指令
w.putNop();
w.flush();
});
patchCount++;
}
} catch(e) {}
}
if (patchCount > 0) {
console.log("[*] " + mod.name + ": patched", patchCount, "inline SYS_exit");
}
totalPatched += patchCount;
}
console.log("[*] svc scan done, total patched:", totalPatched);
} catch(e) {
console.log("[-] svc scan failed:", e.message);
}
})();
// 设置全局异常处理器
Process.setExceptionHandler(function(details) {
var pc = details.context.pc;
console.log("\n[!!!] Exception caught!");
console.log(" type:", details.type);
console.log(" pc:", pc);
// 如果是非法指令异常,进行补丁
if (details.type === "illegal-instruction") {
console.log("[+] Patching illegal instruction...");
try {
Memory.patchCode(pc, 4, function(code) {
var w = new Arm64Writer(code, { pc: pc });
w.putNop();
w.flush();
});
console.log("[+] Patched at:", pc);
return true; // 继续执行,不崩溃
} catch(e) {
console.log("[-] Patch failed:", e.message);
}
}
return false;
});
# 1. 准备越狱iOS设备
# 2. 安装Frida
apt-get install frida
# 3. 启动Frida-server
/usr/sbin/frida-server &
# 4. 运行绕过脚本
frida -U -f com.qp.platform -l bypass.js --no-pause
// 1. 多维度交叉验证
func comprehensiveCheck() -> Bool {
let debugCheck = !isDebuggerAttached()
let jailbreakCheck = !isJailbroken()
let injectionCheck = !isCodeInjected()
let runtimeCheck = !hasRuntimeTampering()
// 加权评分机制
let score = (debugCheck ? 25 : 0) +
(jailbreakCheck ? 25 : 0) +
(injectionCheck ? 25 : 0) +
(runtimeCheck ? 25 : 0)
return score >= 75
}
// 2. 动态混淆技术
func dynamicObfuscation() {
// 定期更换检测逻辑
let randomSeed = Int.random(in: 0..<1000)
switch randomSeed % 5 {
case 0: checkMethodA()
case 1: checkMethodB()
case 2: checkMethodC()
case 3: checkMethodD()
default: checkMethodE()
}
}
// 3. 服务端协同验证
func serverSideValidation() {
let deviceFingerprint = generateDeviceFingerprint()
let timestamp = Int(Date().timeIntervalSince1970)
let signature = signData(deviceFingerprint + "\(timestamp)")
// 发送到服务端验证
validateWithServer(fingerprint: deviceFingerprint,
timestamp: timestamp,
signature: signature)
}
作者:小白 ???? | iOS安全研究员发布日期:2026年3月29日关键词:iOS安全、Frida、逆向工程、设备环境检测、反调试绕过、QP平台
- ptrace反调试:使用
PT_DENY_ATTACH阻止调试器附加 - sysctl进程检测:检查
P_TRACED标志位 - 线程名监控:检测Frida相关线程
- 文件系统扫描:检查越狱文件和Frida组件
- 动态库加载监控:拦截可疑动态库加载
- 网络端口检测:扫描Frida默认端口
- CPU占用:持续线程清理增加约2-3%的CPU使用率
- 内存占用:脚本本身占用约5-10MB内存
- 启动延迟:应用启动延迟增加约100-200ms
- 稳定性:经过72小时连续测试,无崩溃或异常退出
- 技术验证:验证了现有防护技术的有效性边界
- 攻防演进:推动安全防护技术的持续改进
- 知识共享:促进安全社区的技术交流和发展
- 线程名检查:使用
pthread_getname_np验证线程名是否被伪装 - 进程状态检查:通过
sysctl验证P_TRACED标志位是否被清理 - 文件系统检查:尝试访问越狱相关路径验证拦截效果
- 动态库检查:使用
dyld相关API验证镜像隐藏效果 - 网络连接检查:尝试连接Frida端口验证拦截效果
- 时序检测:检测函数调用时间异常
- 代码完整性校验:定期校验关键函数代码
- 行为分析:基于机器学习的行为异常检测
- 硬件级防护:利用Secure Enclave等硬件安全特性
- 多层次Hook覆盖:从系统调用到Objective-C方法的全面拦截
- 主动防御机制:持续清理线程名、实时补丁指令
- 异常处理:全局异常捕获和恢复机制
- 性能优化:最小化对应用性能的影响
- AI驱动的检测与绕过:利用机器学习进行更智能的攻防对抗
- 硬件辅助安全:探索TEE、SE等硬件安全技术的应用
- 跨平台统一防护:研究iOS/Android/Web的统一安全解决方案
- 动态信任评估:基于行为分析的动态信任评分机制
- 本文所有技术内容仅用于安全研究和技术学习
- 请勿将本文技术用于非法用途或侵犯他人权益
- 技术研究应在合法授权范围内进行
- 作者不对任何滥用本文技术的行为负责
PT_DENY_ATTACH阻止调试器附加赞赏记录
参与人
雪币
留言
时间
顽劣
感谢你的积极参与,期待更多精彩内容!
3小时前
令狐双
感谢你的积极参与,期待更多精彩内容!
7小时前
mb_rjdrqvpa
感谢你的积极参与,期待更多精彩内容!
12小时前
huangyalei
谢谢你的细致分析,受益匪浅!
17小时前
Ot²
感谢你分享这么好的资源!
18小时前
赞赏
他的文章
赞赏
雪币:
留言: