进阶逆向技巧

进阶逆向技巧

简单介绍下一些进阶逆向技巧

Frida绕过SSL-Pinning

SSL-Pinning技术主要机制是对收到服务器发来的证书进行校验,如果不被客户端信息,则直接断开应用的网络连接

绕过证书绑定

通过Hook SSL-Pinning框架中的某些方法,改变这些方法的运行结果,使得SSL-pinning失效。

  1. Xposed框架的JustTrustMe模块
  2. Frida框架的ObjectionUnpinning模块
  3. 使用SSLContext导入自定义证书

导入自定义证书

首先通过Fiddler等抓包工具生成证书

编写Frida脚本,通过反射获取证书需要的java类

1
2
3
4
5
6
7
8
9
10
11
12
setTimeout(fuction(){
java.perform(function(){
var CertificateFactory = java.use("java.security.cert.CertficateFactory");
var FileInputStream = java.use("java.io.FileInputStream");
var BufferedInputStream = java.use("java.io.BufferedInputStream");
var X509Certificate = java.use("java.security.cert.X509Certificate");
var KeyStore = java.use("java.security.KetStore");
var TrustManagerFactory = java.use("javax.net.ssl.TrustManagerFactory");
var SSLContext = java.use("javax.net.ssl.SSLContext");
...
});
},0);

通过读取上方生成的第三方证书文件,转换成X.509证书对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
setTimeout(fuction(){
Java.perform(function(){
...
var cf = CertificateFactory.getInstance("X.509");
try{
var fileInputStream = FileInputStream.$ new("证书文件");
}catch(err){
console.log("[0]"+err)
}
var bufferedINputStream = BUfferedInputStream.$new(fileInputStream);
var ca = cf.generateCertificate(bufferedInputStream);
bufferedInputStream.close();
var cerInfo = Java.cast(ca,X509Certificate);
});
},0);

使用证书中的密钥配置TrustManager。使用Frida Hook SSLContext,修改SSLContext的构造方法,传入第三方证书生成的TrustManager构造的SSLContext,从而替代验证的证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
setTimeout(fuction(){
Java.perform(function(){
...
var keyStoreType = keyStore.getdefaultType();
var keyStore = keyStore.getInstance(keyStoreType);
ketStore.load(null,null);
keyStore.setCertificateEntry("ca",ca);
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext.init.overload("Ljavax.net.ssl.keyManager;","Ljavax.net.ssl.TrustManager;","java.security.SecureRandom").implementation = function(a,b,c){
SSLContext.init.overload("Ljavax.net.ssl.keyManager;","Ljavax.net.ssl.TrustManager;","java.security.SecureRandom").call(this,a,tmf.getTrustManagers(),c);
}
});
},0);

r0capture抓包

frida_ssl_logger项目基础上开发的,drida_ssl_logger基本原理是Hook SSL_read和SSL_write以获取收发数据包的明文数据,经过hexdump处理后输出到控制台,或者保存为pcap文件。r0capture在抓取明文数据后进一步获取收发数据包的IP的地址和端口信息,并按照SSL的格式构造数据发送给主机端,通过hexdump在控制台打印或者保存.pcap格式的文件以便后续分析。

Spawn模式

1
$ python3 r0capture.py -U -f com.qiyi.video -v

Attach模式

1
$ python3 r0capture.py -U com.qiyi.video -v -p iqiyi.pcap

抓包实践

安装hexdump工具

1
pip install hexdump

安装目标APP并运行获取目标APP的包名

1
python r0capture.py -U 三国志.战旗版 -v -p r0capture_test.pcap

使用wirshake分析包,通过追踪http流或者tcp流来分析得到请求响应数据包

Frida追踪函数调用

使用frida trace脚本追踪类对象级别和方法级别,若需要追踪的目标是Java类或方法,会调用enumerateLoadedClass()方法遍历当前进程加载的类;若追踪的目标是Java类并且该类被当前进程加载入内存,则进一步调用traceClass()函数追踪下去。

遍历类的代码如下

1
2
3
4
5
6
7
8
9
10
// trace Java Class
var found = false;
Java.enumerateLoadedClasses({
onMatch: function(aClass) {
if (aClass.match(pattern)) {
found = true;
var className = aClass.match(/[L](.*);/)[1].replace(/\//g, ".");
traceClass(className);
}
},

在traceClass()函数中,会创建被追踪类的对象,获取其中的方法,然后调用$dispose清理掉类对象。对获取到类方法进行去重,针对每一个类方法调用traceMethod()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// find and trace all methods declared in a Java Class
function traceClass(targetClass)
{
var hook = Java.use(targetClass);
var methods = hook.class.getDeclaredMethods();
hook.$dispose;

var parsedMethods = [];
methods.forEach(function(method) {
parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]);
});

var targets = uniqBy(parsedMethods, JSON.stringify);
targets.forEach(function(targetMethod) {
traceMethod(targetClass + "." + targetMethod);
});
}

traceMethod()会Hook类方法的每一个重载方法。当方法被调用时会进入到Hook逻辑,首先打印日志声明该方法被调用,然后逐个打印参数表内的参数,接着直接执行原方法逻辑,从而获取方法的返回值,最后Hook逻辑打印返回值和退出日志。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// trace a specific Java Method
function traceMethod(targetClassMethod)
{
var delim = targetClassMethod.lastIndexOf(".");
if (delim === -1) return;

var targetClass = targetClassMethod.slice(0, delim)
var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length)

var hook = Java.use(targetClass);
var overloadCount = hook[targetMethod].overloads.length;

console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]");

for (var i = 0; i < overloadCount; i++) {

hook[targetMethod].overloads[i].implementation = function() {
console.warn("\n*** entered " + targetClassMethod);

// print backtrace
// Java.perform(function() {
// var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
// console.log("\nBacktrace:\n" + bt);
// });

// print args
if (arguments.length) console.log();
for (var j = 0; j < arguments.length; j++) {
console.log("arg[" + j + "]: " + arguments[j]);
}

// print retval
var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?)
console.log("\nretval: " + retval);
console.warn("\n*** exiting " + targetClassMethod);
return retval;
}
}
}

脚本使用

首先获取设备上安装的APK应用包名

1
adb shell pm list packages
1
frida -U -l frida_trace.js -f com.example.crackme
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2024 John Doe
  • 访问人数: | 浏览次数:

让我给大家分享喜悦吧!

微信