一、前言
之前在破解某个软件中碰到了SSL证书校验的问题,当时的解决方案是搜索TrustManager,SSLContext之类的关键词,模仿JustTrustMe去hook一个加固的APP。
XposedHelpers.findAndHookMethod("javax.net.ssl.SSLContext", classLoader, "init", KeyManager[].class, TrustManager[].class, SecureRandom.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); param.args[1] = new TrustManager[]{(new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0];//就是这里 原代码为return null; 即不信任任何证书 我们使他信任系统默认证书 } })}; XposedBridge.log(TAG + "geetest hook TrustManager OK"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); } });
过了一段时间,发现方法失效,猜测有所更新,可是本地代码未曾更新,一时不知所措。不慌,先看代码。
import android.util.Log; public class GT3Log { public static boolean isShowLog = false; public static boolean isShowLog() { return isShowLog; } public static void setShowLog(boolean z) { isShowLog = z; } public static void show(String str, String str2) { if (isShowLog) { Log.i(str, str2); } } }
思路清晰,直接Xposed修改isShowLog为true。同时用JADX查找setShowLog方法的引用,避免开关再被关上。很简单,没有找到引用,可以直接修改。
/**hook 极验Log*/ Class GT3Log = XposedHelpers.findClass("com.geetest.sdk.Bind.GT3Log", classLoader); XposedHelpers.setStaticObjectField(GT3Log, "isShowLog", true);
然后发现打出了Log: webview加载出错 204s ,遂寻找相关代码
善良的明文字符串 (小声)
思路清晰,往上翻找,onReceivedSslError这个方法属于一个内部类,并且一看便知这理解是SSL证书校验的问题所在。
遂对onReceivedSslError百度之,直接得到有用的信息。
再看看源码
public class SslErrorHandler extends Handler { /** * @hide Only for use by WebViewProvider implementations. */ @SystemApi public SslErrorHandler() {} /** * Proceed with the SSL certificate. */ public void proceed() {} /** * Cancel this request and all pending requests for the WebView that had * the error. */ public void cancel() {} }
看到这里就稳了,只要重写onReceivedSslError,使其直接proceed,忽略异常就可以了,使用了Xposed的MethodReplacement回调,非常简单。
XposedHelpers.findAndHookMethod("com.geetest.sdk.GT3GtWebView$O00000o", classLoader, "onReceivedSslError", WebView.class, SslErrorHandler.class, SslError.class, new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { XposedBridge.log(TAG + "极验geetest repalce handler proceed"); SslErrorHandler handler = (SslErrorHandler) methodHookParam.args[1]; handler.proceed();//跳过异常 } });
重启生效后,就可以正常的抓包了。
总结这次简单的逆向,有一个清晰的思路:
1. 打开Log开关。
2. 查看Log信息找字符串,如果没有明文就在hook代码中throw Exception,在StackTrace中定位关键代码。P.S. 如果是我自己开发,我会在proguard的O0o字典基础上,再增加一个混淆明文字符串的保护。
详参 https://github.com/Qrilee/obfuseSmaliText/
使用异或+十六进制的方式对字符串进行混淆,每个字符串解密对应一个解密key,字符串以byte数组呈现。
多一道trick总是能让人获得一些恶趣味的快乐
虽然功能已经实现了,开篇提出的问题并未解决:为什么本地代码没有更新,却又多了一道SSL校验呢?
TrustManager出现在类GT3Geetest的readContentFromGet()里,而这次遇到的是继承的WebViewClient类里的校验,WebView用来显示验证码图片和加载点击行为的js。然而,去除TrustManager的hook代码后,仍然可以绕过校验。
由于没有做过SSL相关实际开发,本文不得不虎头蛇尾,还期待有dalao能指点一二。