第8章 实战场景
8.1 SSL Pinning 绕过
通用 TrustManager 绕过
Java.perform(function() {
// 创建宽容的 TrustManager
var TrustManager = Java.registerClass({
name: 'com.frida.TrustManager',
implements: [Java.use('javax.net.ssl.X509TrustManager')],
methods: {
checkClientTrusted(chain, authType) {},
checkServerTrusted(chain, authType) {},
getAcceptedIssuers() { return []; }
}
});
// 替换 SSLContext
var SSLContext = Java.use('javax.net.ssl.SSLContext');
SSLContext.init.overload(
'[Ljavax.net.ssl.KeyManager;',
'[Ljavax.net.ssl.TrustManager;',
'java.security.SecureRandom'
).implementation = function(km, tm, sr) {
console.log('[*] SSLContext.init 被拦截');
this.init(km, [TrustManager.$new()], sr);
};
});OkHttp CertificatePinner 绕过
Java.perform(function() {
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List')
.implementation = function(hostname, peerCerts) {
console.log('[*] OkHttp3 pinning 绕过: ' + hostname);
return;
};
// Kotlin 变体
CertificatePinner['check$okhttp'].overload(
'java.lang.String', 'kotlin.jvm.functions.Function0')
.implementation = function(hostname, peerCerts) {
console.log('[*] OkHttp3 check$okhttp 绕过: ' + hostname);
return;
};
} catch(e) {
console.log('[!] OkHttp3 未找到: ' + e);
}
});Android 系统 TrustManagerImpl 绕过
Java.perform(function() {
try {
var TrustManagerImpl = Java.use(
'com.android.org.conscrypt.TrustManagerImpl');
TrustManagerImpl.verifyChain.implementation = function(
untrustedChain, trustAnchorChain, host,
clientAuth, ocspData, tlsSctData) {
console.log('[*] TrustManagerImpl 绕过: ' + host);
return untrustedChain;
};
} catch(e) {}
});Android 14/15 Network Security 绕过
Android 14+ 强化了网络安全策略,增加了对证书透明度(CT)的验证:
Java.perform(function() {
// Android 14+ NetworkSecurityConfig 绕过
try {
var NetworkSecurityTrustManager = Java.use(
'android.security.net.config.NetworkSecurityTrustManager');
NetworkSecurityTrustManager.checkServerTrusted.overload(
'[Ljava.security.cert.X509Certificate;',
'java.lang.String',
'java.lang.String'
).implementation = function(chain, authType, host) {
console.log('[*] NetworkSecurityTrustManager 绕过: ' + host);
return Java.use('java.util.Arrays').asList(chain);
};
} catch(e) {
console.log('[!] NetworkSecurityTrustManager 不可用: ' + e);
}
// Certificate Transparency 绕过(Android 14+)
try {
var CTVerifier = Java.use(
'android.net.http.X509TrustManagerExtensions');
CTVerifier.checkServerTrusted.overload(
'[Ljava.security.cert.X509Certificate;',
'java.lang.String',
'java.lang.String'
).implementation = function(chain, authType, host) {
console.log('[*] X509TrustManagerExtensions 绕过: ' + host);
return Java.use('java.util.Arrays').asList(chain);
};
} catch(e) {}
// Conscrypt Platform 绕过(Android 14+ 内部实现变更)
try {
var ConscryptPlatform = Java.use(
'com.android.org.conscrypt.Platform');
ConscryptPlatform.checkServerTrusted.overload(
'javax.net.ssl.X509TrustManager',
'[Ljava.security.cert.X509Certificate;',
'java.lang.String',
'com.android.org.conscrypt.AbstractConscryptSocket'
).implementation = function(tm, chain, authType, socket) {
console.log('[*] Conscrypt Platform 绕过');
return Java.use('java.util.Collections')
.emptyList();
};
} catch(e) {}
});Flutter / BoringSSL 绕过(Native 层)
var m = Process.findModuleByName("libflutter.so");
if (m) {
// ARM64 ssl_verify_peer_cert 特征码
var patterns = [
"FF 03 05 D1 FD 7B 0F A9", // 旧版 Flutter
"F4 4F 02 A9 FD 7B 03 A9", // Flutter 3.x+
];
patterns.forEach(function(pattern) {
Memory.scan(m.base, m.size, pattern, {
onMatch(address, size) {
console.log('[*] SSL verify @ ' + address);
Interceptor.attach(address, {
onLeave(retval) {
retval.replace(0x0); // 返回 ssl_verify_ok
}
});
},
onComplete() {}
});
});
}一体化 SSL 绕过(推荐方案)
对于 Android 14/15,建议使用 httptoolkit/frida-interception-and-unpinning 工具包,覆盖主流场景:
# 克隆最新版本
git clone https://github.com/httptoolkit/frida-interception-and-unpinning
# 使用(自动处理多种 pinning 实现 + 混淆回退)
frida -U -f com.target.app \
-l frida-interception-and-unpinning/frida-script.js该工具包特性:
- 自动流量重定向到代理
- 系统证书注入
- 主流库 pinning 绕过(OkHttp、Volley、Flutter、Conscrypt)
- 混淆实现的自动回退修补
- Root 检测绕过
- HTTP/3 阻断强制 HTTP/2 回退
- 支持 Android 14/15 的新证书验证链
8.2 反检测与绕过
常见检测方法
| 检测方式 | 原理 | Android 14/15 新增 |
|---|---|---|
| 端口扫描 | 检查 TCP 27042 是否开放 | - |
| 进程名扫描 | 扫描 /proc/*/cmdline 找 “frida-server” | - |
| 内存映射扫描 | 检查 /proc/self/maps 中的 frida-agent*.so | 更严格的 SELinux 限制 |
| 字符串扫描 | 搜索内存中 “LIBFRIDA”、“frida:rpc” 等 | - |
| 线程名检测 | 查找 “gmain”、“gdbus”、“gum-js-loop” 线程 | - |
| ptrace 自检 | ptrace(PTRACE_TRACEME) 失败说明已被附加 | - |
| D-Bus 协议检测 | Frida 内部使用 D-Bus | - |
| 匿名内存 setArgV0 检测 | 检查匿名内存区域标记 | 17.8.2 已修复 |
| Key Attestation | 设备完整性远程验证 | Android 14+ 强制 |
| 异常 fd 检测 | 检查 /proc/self/fd 中的异常 socket | - |
绕过端口检测
// 方式1: Java 层拦截
Java.perform(function() {
var Socket = Java.use("java.net.Socket");
Socket.$init.overload("java.lang.String", "int")
.implementation = function(host, port) {
if (port === 27042 || port === 27043) {
console.log("[*] 阻止连接 Frida 端口: " + port);
throw Java.use("java.net.ConnectException")
.$new("Connection refused");
}
return this.$init(host, port);
};
});
// 方式2: 17.9.0+ 使用自定义端口(推荐)
// 服务端: ./frida-server -l 0.0.0.0:8888
// 客户端: 使用 Droidy backend 的 control-endpoint 选项
// 或 abstract socket: ./frida-server -l localabstract:my-frida绕过 /proc/self/maps 扫描
// 完整的 maps 过滤方案
var fopen = Module.findExportByName("libc.so", "fopen");
var fgets = Module.findExportByName("libc.so", "fgets");
var filterActive = false;
var filteredFp = null;
Interceptor.attach(fopen, {
onEnter(args) {
var path = args[0].readUtf8String();
if (path && path.indexOf("/proc/") !== -1 &&
path.indexOf("/maps") !== -1) {
this.isMaps = true;
}
},
onLeave(retval) {
if (this.isMaps) {
filteredFp = retval;
filterActive = true;
}
}
});
Interceptor.attach(fgets, {
onEnter(args) {
this.buf = args[0];
this.fp = args[2];
},
onLeave(retval) {
if (filterActive && this.fp && this.fp.equals(filteredFp)) {
var line = this.buf.readUtf8String();
if (line && (
line.indexOf("frida") !== -1 ||
line.indexOf("gadget") !== -1 ||
line.indexOf("gum-js") !== -1
)) {
// 跳过这行,读取下一行
retval.replace(ptr(0));
}
}
}
});绕过字符串检测
Interceptor.attach(Module.findExportByName("libc.so", "strstr"), {
onEnter(args) {
this.needle = args[1].readUtf8String();
},
onLeave(retval) {
if (this.needle && (
this.needle.indexOf("frida") !== -1 ||
this.needle.indexOf("LIBFRIDA") !== -1 ||
this.needle.indexOf("gum-js-loop") !== -1 ||
this.needle.indexOf("gmain") !== -1 ||
this.needle.indexOf("linjector") !== -1
)) {
retval.replace(ptr(0)); // 返回 NULL(未找到)
}
}
});
// 同时 hook strcmp/memcmp
Interceptor.attach(Module.findExportByName("libc.so", "strcmp"), {
onEnter(args) {
var s1 = args[0].readUtf8String();
var s2 = args[1].readUtf8String();
if ((s1 && s1.indexOf("frida") !== -1) ||
(s2 && s2.indexOf("frida") !== -1)) {
this.shouldSpoof = true;
}
},
onLeave(retval) {
if (this.shouldSpoof) {
retval.replace(ptr(-1)); // 不匹配
}
}
});绕过线程名检测(Android 14/15 强化)
// Android 14+ 使用更严格的线程名扫描
Interceptor.attach(Module.findExportByName("libc.so", "pthread_getname_np"), {
onEnter(args) {
this.buf = args[1];
this.tid = args[0];
},
onLeave(retval) {
if (retval.toInt32() === 0) {
var name = this.buf.readUtf8String();
if (name && (
name === "gmain" ||
name === "gdbus" ||
name === "gum-js-loop" ||
name === "pool-frida" ||
name.indexOf("frida") !== -1
)) {
// 替换为无害的线程名
this.buf.writeUtf8String("pool-thread-" +
this.tid.toString().slice(-2));
}
}
}
});
// Hook opendir + readdir 隐藏 /proc/self/task 中的线程
Interceptor.attach(Module.findExportByName("libc.so", "openat"), {
onEnter(args) {
var path = args[1].readUtf8String();
if (path && path.indexOf("/proc/self/task") !== -1) {
this.isTask = true;
}
}
});隐蔽部署技巧(17.9.11 推荐方案)
# 1. 重命名 frida-server(基本)
mv frida-server-17.9.11-android-arm64 hluda-server
chmod 755 hluda-server
# 2. 使用 abstract socket(不暴露 TCP 端口,17.9.0+ 支持)
./hluda-server -l localabstract:my-hidden-service &
# 3. 客户端通过 ADB 转发连接
adb forward tcp:27042 localabstract:my-hidden-service
frida -H 127.0.0.1:27042 -f com.target.app
# 4. 或使用完全自定义端口
./hluda-server -l 0.0.0.0:31337 &
frida -H 192.168.1.100:31337 -f com.target.app
# 5. Gadget 注入模式(免 Root,最隐蔽)
# 见第10章 objection patchapkAndroid 14/15 特有防护绕过
// Android 14+ 引入了更严格的 SELinux 和进程隔离
// 以下处理 restricted file access 检测
Java.perform(function() {
// 绕过 Play Integrity API(替代 SafetyNet)
try {
var IntegrityManager = Java.use(
'com.google.android.play.core.integrity.IntegrityManager');
// 注意:Play Integrity 使用远程验证,客户端绕过效果有限
// 推荐配合 Magisk + Shamiko 使用
} catch(e) {}
// 绕过 PackageManager 检测(检查已安装的逆向工具)
var PackageManager = Java.use('android.app.ApplicationPackageManager');
PackageManager.getInstalledPackages.overload('int')
.implementation = function(flags) {
var packages = this.getInstalledPackages(flags);
var filtered = Java.use('java.util.ArrayList').$new();
var iter = packages.iterator();
while (iter.hasNext()) {
var pkg = iter.next();
var name = pkg.packageName.value;
if (name.indexOf("frida") === -1 &&
name.indexOf("xposed") === -1 &&
name.indexOf("magisk") === -1) {
filtered.add(pkg);
}
}
return filtered;
};
});8.3 系统调用追踪
libc 层追踪
// 文件操作
Interceptor.attach(Module.findExportByName("libc.so", "open"), {
onEnter(args) {
this.path = args[0].readUtf8String();
},
onLeave(retval) {
console.log("[OPEN] " + this.path + " => fd=" + retval.toInt32());
}
});
// 网络操作
Interceptor.attach(Module.findExportByName("libc.so", "connect"), {
onEnter(args) {
var fd = args[0].toInt32();
var addr = args[1];
var family = addr.readU16();
if (family === 2) { // AF_INET
var port = (addr.add(2).readU8() << 8) | addr.add(3).readU8();
var ip = addr.add(4).readU8() + '.' +
addr.add(5).readU8() + '.' +
addr.add(6).readU8() + '.' +
addr.add(7).readU8();
console.log("[CONNECT] fd=" + fd + " " + ip + ":" + port);
}
}
});
// ioctl(Binder IPC)
Interceptor.attach(Module.findExportByName("libc.so", "ioctl"), {
onEnter(args) {
var fd = args[0].toInt32();
var request = args[1].toInt32();
console.log("[IOCTL] fd=" + fd + " request=0x" + request.toString(16));
}
});使用 frida-trace 快速追踪
# 文件操作
frida-trace -U -f com.target.app -i "open*" -i "read" -i "write" -i "close"
# 网络操作
frida-trace -U -f com.target.app -i "connect" -i "send*" -i "recv*" -i "socket"
# 内存操作
frida-trace -U -f com.target.app -i "mmap*" -i "mprotect" -i "munmap"使用 frida-strace 系统调用追踪(17.8.0+ 新功能)
Frida 17.8.0 引入了基于 eBPF 的 frida-strace 工具,提供类似 strace 的系统调用追踪能力:
# 追踪目标应用的所有系统调用
frida-strace -U -f com.target.app
# 追踪正在运行的进程
frida-strace -U -n com.target.app
# 适用场景:
# - 检测 RASP(运行时应用自我保护)机制
# - 分析反调试系统调用(ptrace, prctl)
# - 监控文件/网络访问模式
# - 检测异常进程间通信8.4 Android Framework Hook
Activity 生命周期
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activity.onCreate.overload("android.os.Bundle")
.implementation = function(savedInstanceState) {
console.log("[*] onCreate: " + this.getClass().getName());
this.onCreate(savedInstanceState);
};
Activity.onResume.implementation = function() {
console.log("[*] onResume: " + this.getClass().getName());
this.onResume();
};
Activity.startActivity.overload("android.content.Intent")
.implementation = function(intent) {
console.log("[*] startActivity: " + intent.getComponent());
this.startActivity(intent);
};
});View 渲染性能监控
Java.perform(function() {
var View = Java.use("android.view.View");
View.draw.overload("android.graphics.Canvas")
.implementation = function(canvas) {
var start = Date.now();
this.draw(canvas);
var elapsed = Date.now() - start;
if (elapsed > 16) {
console.log("[JANK] View.draw " + elapsed + "ms: " +
this.getClass().getName());
}
};
});Binder 事务监控
Java.perform(function() {
var Binder = Java.use("android.os.Binder");
Binder.transact.overload(
"int", "android.os.Parcel", "android.os.Parcel", "int")
.implementation = function(code, data, reply, flags) {
console.log("[*] Binder.transact code=" + code +
" from " + this.getClass().getName());
return this.transact(code, data, reply, flags);
};
});8.5 加密函数监控
Java.perform(function() {
// 监控所有 Cipher 操作
var Cipher = Java.use('javax.crypto.Cipher');
Cipher.doFinal.overload('[B').implementation = function(input) {
console.log('[Cipher] doFinal 输入 (' + input.length + ' bytes):');
console.log(' ' + bytesToHex(input));
var result = this.doFinal(input);
console.log('[Cipher] doFinal 输出 (' + result.length + ' bytes):');
console.log(' ' + bytesToHex(result));
return result;
};
// 监控 SecretKeySpec(捕获密钥)
var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
SecretKeySpec.$init.overload('[B', 'java.lang.String')
.implementation = function(key, algorithm) {
console.log('[Key] algorithm=' + algorithm +
' key=' + bytesToHex(key));
this.$init(key, algorithm);
};
// 监控 MessageDigest(Hash 操作)
var MessageDigest = Java.use('java.security.MessageDigest');
MessageDigest.digest.overload('[B').implementation = function(input) {
var algo = this.getAlgorithm();
console.log('[Hash] ' + algo + ' input (' + input.length + ' bytes)');
var result = this.digest(input);
console.log('[Hash] ' + algo + ' output: ' + bytesToHex(result));
return result;
};
});
function bytesToHex(bytes) {
var hex = [];
for (var i = 0; i < bytes.length; i++) {
hex.push(('0' + (bytes[i] & 0xFF).toString(16)).slice(-2));
}
return hex.join(' ');
}8.6 SharedPreferences 监控
Java.perform(function() {
var SharedPreferencesImpl = Java.use(
'android.app.SharedPreferencesImpl$EditorImpl');
SharedPreferencesImpl.putString.implementation = function(key, value) {
console.log('[SP] putString("' + key + '", "' + value + '")');
return this.putString(key, value);
};
SharedPreferencesImpl.putInt.implementation = function(key, value) {
console.log('[SP] putInt("' + key + '", ' + value + ')');
return this.putInt(key, value);
};
SharedPreferencesImpl.putBoolean.implementation = function(key, value) {
console.log('[SP] putBoolean("' + key + '", ' + value + ')');
return this.putBoolean(key, value);
};
});8.7 Android 14/15 特定场景
绕过 Credential Manager(Android 14+)
Java.perform(function() {
// Android 14 引入的 CredentialManager API
try {
var CredentialManager = Java.use(
'android.credentials.CredentialManager');
console.log('[*] CredentialManager 可用,监控中...');
// 监控凭据请求
CredentialManager.getCredential.overload(
'android.content.Context',
'android.credentials.GetCredentialRequest',
'android.os.CancellationSignal',
'java.util.concurrent.Executor',
'android.os.OutcomeReceiver'
).implementation = function(ctx, request, cancel, executor, callback) {
console.log('[Credential] getCredential 请求');
this.getCredential(ctx, request, cancel, executor, callback);
};
} catch(e) {}
});监控 Android 15 预测性返回手势
Java.perform(function() {
try {
var OnBackAnimationCallback = Java.use(
'android.window.OnBackAnimationCallback');
// 监控返回手势预测动画
console.log('[*] 预测性返回手势监控已启用');
} catch(e) {}
});ContentProvider 安全访问监控(Android 14+ 强化)
Java.perform(function() {
var ContentResolver = Java.use('android.content.ContentResolver');
ContentResolver.query.overload(
'android.net.Uri',
'[Ljava.lang.String;',
'android.os.Bundle',
'android.os.CancellationSignal'
).implementation = function(uri, projection, queryArgs, cancel) {
console.log('[ContentProvider] query: ' + uri.toString());
return this.query(uri, projection, queryArgs, cancel);
};
});