使用frida hook所有请求链接和响应
/** * 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()