/** * v19 - 完整搜索响应捕获 + 扩展 warn 检测 + JSON 文件保存 * * v18 成果: * - Gson.toJson() 成功序列化 SearchResponse (122KB+) * - 搜索响应结构确认: resultGroups[].data[].entity.trackWrapper.track * - warnContent/warnSubType/warnType 字段存在于客户端 tracking 上下文 * * v19 改进: * 1. 扩展 warn 检测关键词:warn_info, warnInfo, warnContent, warnType, ai_info, aiInfo, is_ai, ai_generated * 2. 对 SearchResponse 解析每首歌的 track 对象,提取 warn 相关字段 * 3. 将完整 SearchResponse JSON 保存到文件(通过 send 发回 Python 端) * 4. 精简非搜索类噪音输出 这段代码里面的hook方式可以hook响应底层位置,ai生成的 */ var capturedResponses = []; var gsonInstance = null; var searchResponseCount = 0; // 扩展检测关键词 var WARN_KEYWORDS = [ "warn_info", "warnInfo", "warnContent", "warnType", "warnSubType", "ai_info", "aiInfo", "is_ai", "ai_generated", "ai_label", "aigc", "AIGC", "ai_tag", "aiTag" ]; setTimeout(function() { console.log("\n[*] v19 - 完整搜索响应捕获 + 扩展 warn 检测"); console.log("=".repeat(60)); Java.perform(function() { var foundLoader = null; var targetNames = [ "com.luna.biz.search.result.net.SearchResultApi", "com.bytedance.ttnet.retrofit.SsInterceptor" ]; Java.enumerateClassLoaders({ onMatch: function(loader) { if (foundLoader) return; for (var t = 0; t < targetNames.length; t++) { try { var clz = loader.loadClass(targetNames[t]); if (clz) { foundLoader = loader; console.log("[+] ClassLoader found via " + targetNames[t]); return; } } catch(e) {} } }, onComplete: function() {} }); if (!foundLoader) { console.log("[!] ClassLoader 未找到"); return; } var factory = Java.ClassFactory.get(foundLoader); // 获取 Gson 实例 initGson(factory); // Hook RxJava (搜索响应核心入口) hookRxJavaForSearch(factory); // Hook Gson.fromJson - 只关注 SearchResponse hookGsonForSearchResponse(factory); // 枚举 Track 模型字段,找 warn 相关 enumerateTrackFields(factory); }); console.log("\n[*] v19 Hook 设置完成,请在APP中搜索含AI生成标记的歌曲\n"); }, 5000); // ===== 初始化 Gson ===== function initGson(factory) { try { var GsonBuilder = factory.use("com.google.gson.GsonBuilder"); gsonInstance = GsonBuilder.$new().serializeNulls().create(); console.log("[+] Gson 实例创建成功"); } catch(e) { try { var Gson = factory.use("com.google.gson.Gson"); gsonInstance = Gson.$new(); console.log("[+] Gson 实例创建成功 (默认)"); } catch(e2) { console.log("[!] Gson 创建失败: " + e2); } } } // ===== 检查字符串中是否包含 warn 关键词 ===== function checkWarnKeywords(jsonStr) { var found = []; for (var i = 0; i < WARN_KEYWORDS.length; i++) { if (jsonStr.indexOf(WARN_KEYWORDS[i]) !== -1) { found.push(WARN_KEYWORDS[i]); } } return found; } // ===== 提取 warn 字段上下文 ===== function extractWarnContext(jsonStr, keyword) { var idx = jsonStr.indexOf(keyword); var contexts = []; while (idx !== -1 && contexts.length < 5) { var start = Math.max(0, idx - 50); var end = Math.min(jsonStr.length, idx + keyword.length + 200); contexts.push(jsonStr.substring(start, end)); idx = jsonStr.indexOf(keyword, idx + 1); } return contexts; } // ===== Hook RxJava - 专注搜索响应 ===== function hookRxJavaForSearch(factory) { // DisposableLambdaObserver - SearchResponse 通过这里传递 try { var obs = Java.use("io.reactivex.internal.observers.DisposableLambdaObserver"); if (obs.onNext) { obs.onNext.implementation = function(obj) { if (obj !== null) { var className = obj.getClass().getName(); // 只关注 SearchResponse if (className === "com.luna.biz.search.result.net.data.SearchResponse") { searchResponseCount++; send("\n[SearchResponse#" + searchResponseCount + "] 捕获"); if (gsonInstance !== null) { try { var json = gsonInstance.toJson(obj); var jsonStr = json.toString(); send("[SearchResponse#" + searchResponseCount + "] len=" + jsonStr.length); // 扩展关键词检测 var warnFound = checkWarnKeywords(jsonStr); if (warnFound.length > 0) { send("\n[!!!] WARN 关键词命中: " + warnFound.join(", ")); for (var w = 0; w < warnFound.length; w++) { var contexts = extractWarnContext(jsonStr, warnFound[w]); for (var c = 0; c < contexts.length; c++) { send("[WARN-CTX] " + warnFound[w] + " #" + c + ": ..." + contexts[c] + "..."); } } capturedResponses.push(jsonStr); } else { send("[SearchResponse#" + searchResponseCount + "] 无 warn 关键词"); } // 解析 track 列表提取关键字段 extractTrackInfo(jsonStr, searchResponseCount); // 发送完整 JSON 供 Python 端保存 send("[FULL_JSON_START#" + searchResponseCount + "]"); // 分块发送(每块 50KB) var chunkSize = 50000; var chunks = Math.ceil(jsonStr.length / chunkSize); for (var i = 0; i < chunks; i++) { send("[JSON_CHUNK#" + searchResponseCount + ":" + i + "/" + chunks + "]" + jsonStr.substring(i * chunkSize, (i + 1) * chunkSize)); } send("[FULL_JSON_END#" + searchResponseCount + "]"); } catch(e) { send("[SearchResponse] Gson.toJson 失败: " + e.toString().substring(0, 300)); } } } } this.onNext(obj); }; console.log("[+] Hooked DisposableLambdaObserver.onNext (SearchResponse 专注)"); } } catch(e) { console.log("[!] DisposableLambdaObserver: " + e); } // LambdaObserver - TrackResultViewData 通过这里 try { var LambdaObserver = Java.use("io.reactivex.internal.observers.LambdaObserver"); if (LambdaObserver.onNext) { LambdaObserver.onNext.implementation = function(obj) { if (obj !== null) { var className = obj.getClass().getName(); // SearchResponse 也可能走这里 if (className === "com.luna.biz.search.result.net.data.SearchResponse") { searchResponseCount++; send("\n[SearchResponse-LO#" + searchResponseCount + "] 捕获 len=?"); if (gsonInstance !== null) { try { var json = gsonInstance.toJson(obj); var jsonStr = json.toString(); send("[SearchResponse-LO#" + searchResponseCount + "] len=" + jsonStr.length); var warnFound = checkWarnKeywords(jsonStr); if (warnFound.length > 0) { send("\n[!!!] WARN 关键词命中: " + warnFound.join(", ")); for (var w = 0; w < warnFound.length; w++) { var contexts = extractWarnContext(jsonStr, warnFound[w]); for (var c = 0; c < contexts.length; c++) { send("[WARN-CTX] " + warnFound[w] + " #" + c + ": ..." + contexts[c] + "..."); } } capturedResponses.push(jsonStr); } else { send("[SearchResponse-LO#" + searchResponseCount + "] 无 warn 关键词"); } // 同样提取 track 信息 extractTrackInfo(jsonStr, searchResponseCount); // 完整 JSON send("[FULL_JSON_START#" + searchResponseCount + "]"); var chunkSize = 50000; var chunks = Math.ceil(jsonStr.length / chunkSize); for (var i = 0; i < chunks; i++) { send("[JSON_CHUNK#" + searchResponseCount + ":" + i + "/" + chunks + "]" + jsonStr.substring(i * chunkSize, (i + 1) * chunkSize)); } send("[FULL_JSON_END#" + searchResponseCount + "]"); } catch(e) { send("[SearchResponse-LO] Gson.toJson 失败: " + e.toString().substring(0, 300)); } } } // TrackResultViewData - 只报告状态 if (className.indexOf("TrackResultViewData") !== -1) { if (gsonInstance !== null) { try { var json = gsonInstance.toJson(obj); var jsonStr = json.toString(); var warnFound = checkWarnKeywords(jsonStr); if (warnFound.length > 0) { send("\n[!!!TrackViewData] WARN 关键词: " + warnFound.join(", ")); for (var w = 0; w < warnFound.length; w++) { var contexts = extractWarnContext(jsonStr, warnFound[w]); for (var c = 0; c < contexts.length; c++) { send("[WARN-CTX-TVD] " + warnFound[w] + " #" + c + ": ..." + contexts[c] + "..."); } } } } catch(e) {} } } } this.onNext(obj); }; console.log("[+] Hooked LambdaObserver.onNext (SearchResponse + TrackViewData)"); } } catch(e) { console.log("[!] LambdaObserver: " + e); } } // ===== 从 JSON 字符串提取 track 摘要信息 ===== function extractTrackInfo(jsonStr, responseId) { // 用简单字符串搜索找 track name 和相关 warn 字段 // 找 "trackWrapper" 出现次数 var trackCount = 0; var idx = 0; while ((idx = jsonStr.indexOf('"trackWrapper"', idx)) !== -1) { trackCount++; idx += 14; } send("[SearchResponse#" + responseId + "] 包含 " + trackCount + " 个 trackWrapper"); // 搜索所有可能的 warn 相关字段名(即使值为 null) var warnFields = ["warnContent", "warnType", "warnSubType", "warn_info", "ai_info", "aigc_type", "is_pgc_aigc", "song_maker_info"]; for (var i = 0; i < warnFields.length; i++) { var count = 0; var searchIdx = 0; var firstNonNull = null; while ((searchIdx = jsonStr.indexOf(warnFields[i], searchIdx)) !== -1) { count++; // 检查值是否非 null var valueStart = searchIdx + warnFields[i].length; var valueSnippet = jsonStr.substring(valueStart, valueStart + 30); if (valueSnippet.indexOf("null") === -1 && valueSnippet.indexOf('""') === -1 && valueSnippet.indexOf('"null"') === -1 && firstNonNull === null) { firstNonNull = jsonStr.substring(searchIdx, searchIdx + 100); } searchIdx += warnFields[i].length; } if (count > 0) { send("[FIELD-SCAN] " + warnFields[i] + " 出现 " + count + " 次" + (firstNonNull ? " | 非空值: " + firstNonNull : " | 全部为null")); } } } // ===== Hook Gson.fromJson - 只拦截 SearchResponse ===== function hookGsonForSearchResponse(factory) { try { var Gson = factory.use("com.google.gson.Gson"); if (Gson.fromJson) { Gson.fromJson.overloads.forEach(function(overload) { overload.implementation = function() { var result = overload.apply(this, arguments); if (result !== null) { var resultClass = result.getClass().getName(); // 只关注搜索响应相关(精准过滤) if (resultClass === "com.luna.biz.search.result.net.data.SearchResponse" || resultClass.indexOf("SearchTrackResponse") !== -1 || resultClass.indexOf("SearchAllResponse") !== -1) { send("\n[GSON-DESER] " + resultClass); // SearchResponse 会在 RxJava 层再次捕获,这里只做标记 } } return result; }; }); console.log("[+] Hooked Gson.fromJson (SearchResponse 标记模式)"); } } catch(e) { console.log("[!] Gson hook: " + e); } } // ===== 枚举 Track 模型的所有字段(找 warn 相关) ===== function enumerateTrackFields(factory) { var trackClasses = [ "com.luna.common.arch.db.entity.Track", "com.luna.biz.search.result.net.data.SearchResponse", "com.luna.biz.search.result.net.data.SearchResponse$ResultGroup", "com.luna.biz.search.result.net.data.SearchResponse$ResultData", "com.luna.biz.search.result.net.data.SearchResponse$Entity", "com.luna.biz.search.result.net.data.SearchResponse$TrackWrapper" ]; for (var i = 0; i < trackClasses.length; i++) { try { var cls = factory.use(trackClasses[i]); var fields = cls.class.getDeclaredFields(); var fieldNames = []; var warnRelated = []; for (var f = 0; f < fields.length; f++) { var name = fields[f].getName(); fieldNames.push(name); if (name.toLowerCase().indexOf("warn") !== -1 || name.toLowerCase().indexOf("ai") !== -1 || name.toLowerCase().indexOf("aigc") !== -1 || name.toLowerCase().indexOf("label") !== -1 || name.toLowerCase().indexOf("tag") !== -1 || name.toLowerCase().indexOf("maker") !== -1) { warnRelated.push(name + ":" + fields[f].getType().getName()); } } console.log("\n[+] " + trackClasses[i].split(".").pop() + " (" + fields.length + " fields)"); if (warnRelated.length > 0) { console.log(" [!!!] WARN相关字段: " + warnRelated.join(", ")); } console.log(" 所有字段: " + fieldNames.join(", ")); } catch(e) {} } } // ===== RPC 接口 ===== rpc.exports = { ping: function() { return "pong_v19"; }, getCaptured: function() { return capturedResponses; }, getStatus: function() { return { version: "v19", captured_count: capturedResponses.length, search_response_count: searchResponseCount }; } };chatgpt生成的
import frida, sys j2 = """ Java.perform(function() { console.log('进入') var URLClass = Java.use("java.net.URL"); var HttpURLConnectionClass = Java.use("java.net.HttpURLConnection"); URLClass.$init.overload('java.lang.String').implementation = function(url) { console.log("URL: " + url); return this.$init(url); }; HttpURLConnectionClass.connect.implementation = function() { console.log("Connecting to: " + this.getURL().toString()); // 获取堆栈信息 var stackTrace = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); console.log("Stack Trace: " + stackTrace); // 获取请求头信息 console.log("Request Headers: " + JSON.stringify(this.getRequestProperties())); // 获取请求参数 var requestMethod = this.getRequestMethod(); if (requestMethod === 'POST') { var inputStream = this.getOutputStream(); var byteArrayOutputStream = Java.use("java.io.ByteArrayOutputStream").$new(); byteArrayOutputStream.writeTo.implementation = function(outputStream) { console.log("Request Data: " + this.toString()); byteArrayOutputStream.writeTo(outputStream); }; var bufferedWriter = Java.use("java.io.BufferedWriter").$new(Java.use("java.io.OutputStreamWriter").$new(inputStream)); bufferedWriter.write.implementation = function(str) { console.log("Request Data: " + str); bufferedWriter.write(str); }; } return this.connect(); }; }); """ def on_message(message, data): if message['type'] == 'send': print("[*]{0}".format(message['payload'])) else: print(message) process = frida.get_usb_device(-1).attach(10600) # 可选择j1或者j2算法,使用起来功能一样,看哪个用的更顺手 script = process.create_script(j2) script.on('message', on_message) script.load() # 不让程序断掉 sys.stdin.read()