Try   HackMD

紀錄一下攔截某銀APP的封包流量透過中間人攻擊

紀錄一下脫機的過程,因為一些因素所以,沒有追完全全部,等最近有空再說
反正主要目的就是假設一個APP 我要提取目標其中功能,我是否可以透過 HOOK的方式 將所有APP 流程轉成 API
也就是我要攔截 APP的 HTTPS 的流量 得到 請求的 request 然後在透過 攔截 app 的 簽章加密的 function 試圖找出簽這個 request 的 方法 ,這樣的步驟都做到的話基本上,你就可以偽造 這個 https 的請求了,當然有些情況可能變得更加棘手,有空再研究

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

目前整個流程就是hook call stack 的 function 看他從請求的 request 到觸發經過哪些 function ,試圖找到 簽 request 的
function 再重新構造 request 進行呼叫
這邊要透過 frida-interception-and-unpinning-main.zip

frida -U \
    -l ./config.js \
    -l ./native-connect-hook.js \
    -l ./native-tls-hook.js \
    -l ./android/android-proxy-override.js \
    -l ./android/android-system-certificate-injection.js \
    -l ./android/android-certificate-unpinning.js \
    -l ./android/android-certificate-unpinning-fallback.js \
    -f $PACKAGE_ID

按照之前的下法找個安全的地方 進行 hook就可以繞過去了

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

重新啟動就可以透過 hook 去撈取封包

Java.perform(function () { const log = (tag, message) => console.log(`[${tag}] ${message}`); const printStackTrace = () => { const Thread = Java.use("java.lang.Thread"); const stackTrace = Thread.currentThread().getStackTrace(); log("STACK", "Current Call Stack:"); stackTrace.forEach(trace => console.log("\t" + trace.toString())); }; // Hook Runtime.exec const hookRuntimeExec = () => { const Runtime = Java.use("java.lang.Runtime"); Runtime.exec.overload("java.lang.String").implementation = function (cmd) { log("HOOK", `Blocked Command: ${cmd}`); if (cmd.includes("su")) { return null; // Block 'su' commands } return this.exec(cmd); }; log("HOOK", "Runtime.exec hooked"); }; // Hook File.exists const hookFileExists = () => { const File = Java.use("java.io.File"); File.exists.implementation = function () { const path = this.getPath(); if (path.includes("/system/app/Superuser.apk") || path.includes("/su")) { log("HOOK", `Fake File.exists for path: ${path}`); return false; } return this.exists(); }; log("HOOK", "File.exists hooked"); }; // Hook URL.openConnection const hookUrlOpenConnection = () => { const URL = Java.use("java.net.URL"); URL.openConnection.overload().implementation = function () { const connection = this.openConnection(); log("HOOK", `Opening connection to URL: ${this.toString()}`); printStackTrace(); // Print call stack return connection; }; log("HOOK", "URL.openConnection hooked"); }; // Hook SSLPinningManager const hookSSLPinningManager = () => { const SSLPinningManager = Java.use("com.alipay.imobile.network.sslpinning.SSLPinningManager"); SSLPinningManager.c.implementation = function (arg1, arg2) { log("HOOK", "Bypassed SSLPinningManager.c"); printStackTrace(); return; // Skip original logic }; log("HOOK", "SSLPinningManager.c hooked"); }; // Hook TrustManagerImpl.verifyChain const hookTrustManagerImpl = () => { const TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl"); TrustManagerImpl.verifyChain.implementation = function (chain, authType, session, hostname) { log("HOOK", `Bypassed TrustManagerImpl.verifyChain for hostname: ${hostname}`); printStackTrace(); return chain; // Force return valid chain }; log("HOOK", "TrustManagerImpl.verifyChain hooked"); }; // Hook AbstractHttpTransport.signRequest const hookAbstractHttpTransport = () => { const AbstractHttpTransport = Java.use("com.alipay.imobile.network.quake.transport.http.AbstractHttpTransport"); AbstractHttpTransport.signRequest.overload( "com.alipay.imobile.network.quake.Request", "com.alipay.imobile.network.quake.util.SignUtil$SignInfo" ).implementation = function (request, signInfo) { log("HOOK", "AbstractHttpTransport.signRequest called"); log("INFO", `Request: ${request.toString()}`); log("INFO", `SignInfo: ${signInfo}`); printStackTrace(); const signedString = this.signRequest(request, signInfo); log("INFO", `Signed String: ${signedString}`); return signedString; }; log("HOOK", "AbstractHttpTransport.signRequest hooked"); }; // Hook SignUtil.a const hookSignUtil = () => { const SignUtil = Java.use("com.alipay.imobile.network.quake.util.SignUtil"); SignUtil.a.overload( "android.content.Context", "com.alipay.imobile.network.quake.util.SignUtil$SignInfo", "java.lang.String", "java.lang.String" ).implementation = function (context, signInfo, param1, param2) { log("HOOK", "SignUtil.a hooked"); log("INFO", `Context: ${context}`); log("INFO", `SignInfo: ${signInfo}`); log("INFO", `Param1: ${param1}`); log("INFO", `Param2: ${param2}`); printStackTrace(); const result = this.a(context, signInfo, param1, param2); log("INFO", `Result (Signature): ${result}`); return result; }; log("HOOK", "SignUtil.a(Context, SignInfo, String, String) hooked"); }; // Hook SignedJsonProtocolV1.serialize const hookSignedJsonProtocol = () => { const SignedJsonProtocolV1 = Java.use("com.alipay.imobile.network.quake.protocol.json.SignedJsonProtocolV1"); SignedJsonProtocolV1.serialize.implementation = function (request) { log("HOOK", "SignedJsonProtocolV1.serialize hooked"); log("INFO", `Request: ${request.toString()}`); printStackTrace(); const result = this.serialize(request); log("INFO", `Serialized Data: ${Java.use("java.lang.String").$new(result)}`); return result; }; log("HOOK", "SignedJsonProtocolV1.serialize hooked"); }; // Initialize all hooks const initializeHooks = () => { hookRuntimeExec(); hookFileExists(); hookUrlOpenConnection(); hookSSLPinningManager(); hookTrustManagerImpl(); hookAbstractHttpTransport(); hookSignUtil(); hookSignedJsonProtocol(); log("INIT", "All hooks initialized successfully"); }; initializeHooks(); }); Java.perform(function () { var SignUtil = Java.use('com.alipay.imobile.network.quake.util.SignUtil'); var SecurityGuardParamContext = Java.use('com.alibaba.wireless.security.open.SecurityGuardParamContext'); // Hook 私有静态方法 var method = SignUtil.a.overload( 'com.alibaba.wireless.security.open.SecurityGuardParamContext', 'java.lang.String', 'boolean', 'android.content.Context' ); method.implementation = function (securityGuardParamContext, stringParam, booleanParam, context) { console.log('Hooked SignUtil.a (private static method)'); console.log('String Parameter: ' + stringParam); console.log('Boolean Parameter: ' + booleanParam); console.log('Context: ' + context); // 获取 SecurityGuardParamContext 的 appKey try { var appKey = securityGuardParamContext.appKey.value; console.log('SecurityGuardParamContext.appKey: ' + appKey); } catch (e) { console.log('Failed to access appKey: ' + e); } // 调用原始方法 var result = method.call(this, securityGuardParamContext, stringParam, booleanParam, context); console.log('Result: ' + result); return result; }; }); Java.perform(function () { var SignUtil = Java.use('com.alipay.imobile.network.quake.util.SignUtil'); console.log('Methods in com.alipay.imobile.network.quake.util.SignUtil:'); var methods = SignUtil.class.getDeclaredMethods(); for (var i = 0; i < methods.length; i++) { console.log(methods[i].toString()); } }); Java.perform(function () { var AbstractHttpTransport = Java.use('com.alipay.imobile.network.quake.transport.http.AbstractHttpTransport'); // Hook executeRequest 方法 AbstractHttpTransport.executeRequest.overload('com.alipay.imobile.network.quake.Request').implementation = function (request) { console.log('[HOOwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwK] executeRequest called'); // 打印传入的 Request 对象内容 console.log('Request: ' + request.toString()); // 打印堆栈信息 console.log('[STACK] Current Call Stack:'); var stack = Java.use('java.lang.Thread').currentThread().getStackTrace(); for (var i = 0; i < stack.length; i++) { console.log(stack[i].toString()); } // 调用原始方法并获取结果 var result = this.executeRequest(request); // 打印返回结果 console.log('NetworkResponse: ' + result.toString()); return result; }; }); Java.perform(function () { var AbstractHttpTransport = Java.use('com.alipay.imobile.network.quake.transport.http.AbstractHttpTransport'); AbstractHttpTransport.addRequestHeaders.overload('java.util.Map', 'com.alipay.imobile.network.quake.Request').implementation = function (headers, request) { console.log('[HOOwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwK] addRequestHeaders called'); try { // 確認 headers 是否為 Java 對象 if (headers && headers.getClass) { console.log('Headers Class: ' + headers.getClass().getName()); // 嘗試遍歷 headers 的鍵值對 if (headers.entrySet) { console.log('Headers Content:'); var iterator = headers.entrySet().iterator(); while (iterator.hasNext()) { var entry = iterator.next(); console.log(' Key: ' + entry.getKey() + ', Value: ' + entry.getValue()); } } else { console.log('[WARNING] headers does not have an entrySet method, cannot iterate over it.'); } } else { console.log('[WARNING] headers is not a valid Java object.'); } // 確認 request 是否為 Java 對象 if (request && request.getClass) { console.log('Request Class: ' + request.getClass().getName()); } else { console.log('[WARNING] request is not a valid Java object.'); } } catch (e) { console.log('[ERROR] Exception while processing addRequestHeaders: ' + e.message); } // 調用原始方法 this.addRequestHeaders(headers, request); }; }); Java.perform(function () { var RpcRequest = Java.use('com.alipay.imobile.network.quake.rpc.RpcRequest'); // Hook RpcRequest 構造方法 RpcRequest.$init.overload('java.lang.String', 'java.lang.reflect.Type', 'com.alipay.imobile.network.quake.Request$Listener', 'com.alipay.imobile.network.quake.Request$ErrorListener').implementation = function (arg1, arg2, arg3, arg4) { console.log('[HOOK] RpcRequest constructor called'); // 安全檢查並列印參數 console.log(' arg1 (String): ' + (arg1 !== null ? arg1 : 'null')); console.log(' arg2 (Type): ' + (arg2 !== null ? arg2.toString() : 'null')); console.log(' arg3 (Listener): ' + (arg3 !== null ? arg3.toString() : 'null')); console.log(' arg4 (ErrorListener): ' + (arg4 !== null ? arg4.toString() : 'null')); // 調用原始構造方法 var instance = this.$init(arg1, arg2, arg3, arg4); return instance; }; });