声明: 本文中提及的APK及相关内容仅用于学习和交流目的,不涉及任何商业用途。本文不鼓励或支持任何形式的版权侵犯行为,同时也强调对软件的安全使用。我们尊重和维护开发者的权益,强烈建议读者在使用软件时遵守相关法律法规,并尊重软件的使用许可协议。对于因不当使用软件而导致的任何法律或安全问题,本文作者及发布平台不承担任何责任。如果软件开发者或权利人有任何版权或安全方面的疑虑,请及时与我们联系,我们将第一时间进行相应处理。
保存证书
此样本已经失效了,了解一下思路吧
对于VPN抓包失败的,先上一套降龙十八掌。
比如,先尝试Hook一下 KeyStore,看看情况:
function hook_KeyStore_load() {
Java.perform(function () {
var StringClass = Java.use("java.lang.String");
var KeyStore = Java.use("java.security.KeyStore");
KeyStore.load.overload('java.security.KeyStore$LoadStoreParameter').implementation = function (arg0) {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
console.log("KeyStore.load1:", arg0);
this.load(arg0);
};
KeyStore.load.overload('java.io.InputStream', '[C').implementation = function (arg0, arg1) {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
console.log("KeyStore.load2: ", arg0, arg1 ? "|" + StringClass.$new(arg1) + "|": "password is null");
if (arg0) {
saveFile(arg0, "ncsearch");
}
this.load(arg0, arg1);
};
console.log("hook_KeyStore_load...");
});
}
function saveFile(is, saveName) {
var file = Java.use("java.io.File").$new("/sdcard/Download/" + saveName + ".p12");
var out = Java.use("java.io.FileOutputStream").$new(file);
var buffer = new Array(1024);
buffer = buffer.fill(0)
buffer = Java.array('byte', buffer);
var len;
while ((len = is.read(buffer)) > 0) {
out.write(buffer, 0, len)
}
out.close()
console.log("save file success!")
}
输出如下内容:
java.lang.Throwable
at java.security.KeyStore.load(Native Method)
at com.ninemax.ncsearchnew.utils.HttpClientSslHelper.getSSLContext(HttpClientSslHelper.java:152)
at com.ninemax.ncsearchnew.utils.HttpUtils.loadData(HttpUtils.java:95)
at com.ninemax.ncsearchnew.utils.HttpUtils.loadData(HttpUtils.java:52)
at com.ninemax.ncsearchnew.ui.base.BaseActivity.loadData(BaseActivity.java:215)
at com.ninemax.ncsearchnew.ui.SpalshActivity.getWebsiteData(SpalshActivity.java:232)
at com.ninemax.ncsearchnew.ui.SpalshActivity.onApplyPrivacyFinish(SpalshActivity.java:183)
at com.ninemax.ncsearchnew.ui.SpalshActivity.showPrivacyDialog(SpalshActivity.java:698)
at com.ninemax.ncsearchnew.ui.SpalshActivity.initData(SpalshActivity.java:171)
at com.ninemax.ncsearchnew.ui.base.BaseActivity.onCreate(BaseActivity.java:96)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
KeyStore.load2: android.content.res.AssetManager$AssetInputStream@6498482 |cods.org.cn|
明显是从 asset 里面读取了一个文件,然后加载成 KeyStore,我们将这个文件直接写到 sdcard 上,使用 keystore explore 打开看看。
https://keystore-explorer.org/downloads.html
需要注意,上面我们保存文件的时候,使用的是 .p12,但是实际上不一定是 .p12 格式,具体还需要使用软件查看,使用 kse 打开证书:
输入上面打印出来的密码:
可以看到,它确实是一个 PKCS12 格式的文件,我们可以直接将它导入到charles里面去,为了简单,域名我选择了全匹配。
弄完之后,再去做请求,一般情况下会ok,如果还不行,就需要祭出 ssl pin 等hook代码了,objection 也可以一键处理,就不展开了。
SSL PIN 的处理
看另一个样本:
VPN抓包也是失败的,祭出 ssl pin 等 hook 的代码之后,发现还是走不通。这就让人比较头大了。
可以确定的是,网络请求肯定是触发了的,那么我们hook一下最底层的代码,看看调用堆栈。
比如,我们使用 objection hook 这个类 com.android.org.conscrypt.TrustManagerImpl
的所有方法,再次点击按钮,发送网络请求,就可以看到堆栈:
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(Native Method)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:335)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:113)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:133)
at java.lang.reflect.Method.invoke(Native Method)
at android.net.http.X509TrustManagerExtensions.checkServerTrusted(X509TrustManagerExtensions.java:101)
at java.lang.reflect.Method.invoke(Native Method)
at ul.b$a.a(AndroidPlatform.java:2)
at nl.f.a(CertificatePinner.java:13)
at ql.d.f(RealConnection.java:52)
at ql.d.c(RealConnection.java:22)
at ql.g.d(StreamAllocation.java:95)
at ql.g.e(StreamAllocation.java:1)
at ql.a.a(ConnectInterceptor.java:13)
at rl.f.b(RealInterceptorChain.java:11)
at pl.b.a(CacheInterceptor.java:105)
at rl.f.b(RealInterceptorChain.java:11)
at rl.a.a(BridgeInterceptor.java:37)
at rl.f.b(RealInterceptorChain.java:11)
at rl.i.a(RetryAndFollowUpInterceptor.java:12)
at rl.f.b(RealInterceptorChain.java:11)
at rl.f.a(RealInterceptorChain.java:1)
at yl.a.a(HttpLoggingInterceptor.java:4)
at rl.f.b(RealInterceptorChain.java:11)
at y8.b.a(HttpResponseInterceptor.kt:8)
at rl.f.b(RealInterceptorChain.java:11)
at y8.a.a(HttpRequestInterceptor.kt:37)
at rl.f.b(RealInterceptorChain.java:11)
at rl.f.a(RealInterceptorChain.java:1)
at nl.y.c(RealCall.java:23)
at nl.y.b(RealCall.java:16)
at lm.p.execute(OkHttpCall.java:18)
at x8.a.execute(EasyCall.kt:1)
at x8.a.c(EasyCall.kt:1)
at com.ticktick.task.helper.UserActivationHelper.sendUserActivation(UserActivationHelper.kt:2)
at com.ticktick.task.helper.UserActivationHelper.trySendUserActivation(UserActivationHelper.kt:1)
at com.ticktick.task.helper.UserActivationHelper.access$trySendUserActivation(UserActivationHelper.kt:1)
at com.ticktick.task.helper.UserActivationHelper$trySendUserActivation$$inlined$timerTask$1.run(Timer.kt:1)
at java.util.TimerThread.mainLoop(Timer.java:562)
at java.util.TimerThread.run(Timer.java:512)
这个时候,就明白了,应用层的类都被混淆了,所以我们 hook 代码失效了,我们直接hook混淆后的类:
function hook_cp() {
Java.perform(function () {
var ClassName = "nl.f";
var Platform = Java.use(ClassName);
var targetMethod = "a";
var len = Platform[targetMethod].overloads.length;
console.log(len);
for (var i = 0; i < len; ++i) {
Platform[targetMethod].overloads[i].implementation = function () {
console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);
}
}
});
}
这个时候,就可以正常抓到包了: