Android反调试实战:绕过libmsaoaidsec.so对Frida的检测机制

发布时间:2026/7/27 6:09:56

Android反调试实战:绕过libmsaoaidsec.so对Frida的检测机制 1. 项目概述当Frida遇上libmsaoaidsec.so在移动安全研究特别是Android应用逆向与动态分析领域Frida几乎成了人手必备的瑞士军刀。它能让我们在运行时注入JavaScript脚本去Hook函数、修改逻辑、分析数据流效率极高。但道高一尺魔高一丈越来越多的应用尤其是那些对安全性有极高要求的金融、支付类App开始集成强大的反调试与反注入机制。libmsaoaidsec.so这个库就是近年来在不少加固方案和风控SDK中频繁出现的“守门员”之一。它的核心任务之一就是检测并阻止像Frida这样的动态分析工具。所以当你的Frida脚本一附加上目标进程就崩溃或者干脆无法附加时libmsaoaidsec.so很可能就是幕后黑手。这个项目要解决的就是如何系统地检测并绕过这个库对Frida的防护。这不仅仅是一个简单的“开关”问题它涉及对Android Native层反调试原理的理解、对Frida自身工作机制的洞察以及一场在内存中进行的精细“外科手术”。对于安全研究员、应用逆向工程师或是想要深入理解移动端攻防的同学来说掌握这套绕过技术意味着你能打开更多此前无法动态分析的应用洞察其核心逻辑。2. libmsaoaidsec.so 反调试机制深度解析要绕过它首先得知道它是怎么工作的。libmsaoaidsec.so通常作为安全组件被主应用加载。它的检测手段是多维度、多层次的并非单一方法。2.1 基于进程特征与端口扫描的检测这是最经典也是最初级的检测方式。Frida Server在设备上运行后会默认监听27042端口默认情况下等待来自frida命令行工具或Python绑定的连接。检测原理端口检测libmsaoaidsec.so可能会定期或在关键逻辑执行前扫描本机进程打开的端口。通过读取/proc/net/tcp和/proc/net/tcp6文件可以列出所有TCP连接和监听端口。如果发现27042端口处于LISTEN状态并且关联的进程名可疑就会触发防护。进程名与文件检测扫描/proc目录下的进程列表查找名为frida-server、re.frida.server或其变种的进程。同时也可能检查/data/local/tmp等目录下是否存在Frida Server的可执行文件。映射文件检测检查进程的内存映射/proc/self/maps或/proc/pid/maps寻找包含frida、gadget、libfrida等关键词的共享库如libfrida-gadget.so。当Frida以Gadget模式注入时相关库会被映射到目标进程空间。注意单纯的端口改名或路径隐藏对于现代的安全组件来说已经不够了。它们会结合多种特征进行综合判断。2.2 基于内存状态与线程遍历的深度检测当Frida成功注入后会在目标进程中创建用于通信和脚本执行的工作线程。这些线程具有一些可被识别的特征。检测原理线程名检测Frida创建的一些内部线程其名称可能包含特定字符串如frida、gum-js等。libmsaoaidsec.so可以通过遍历/proc/self/task/目录下的所有线程读取每个线程的comm文件或使用prctl(PR_GET_NAME, ...)来检查线程名。内存属性与路径检测除了映射文件名还可以检查内存段的属性。例如Frida注入的代码段可能具有可写、可执行的异常属性W^X安全策略的例外或者其映射文件的路径不在常规的系统库或应用库路径下。断点指令检测Frida实现Hook的核心机制之一是插入软中断指令如ARM的svc 0或brk指令。安全模块可能会对关键函数如ptrace、open、readlink等的代码段进行校验和检查或者直接扫描内存中是否存在这类指令模式。2.3 基于ptrace与调试器状态的检测这是Native层反调试的基石。ptrace是进程跟踪和调试的底层系统调用。检测原理防止附加应用在启动时可能会先发制人地调用ptrace(PTRACE_TRACEME, ...)将自己设为被跟踪状态。根据Linux内核规则一个进程在同一时间只能被一个调试器跟踪。这样当后续Frida尝试通过ptrace(PTRACE_ATTACH, ...)附加时就会失败。检测跟踪状态通过读取/proc/self/status文件中的TracerPid字段。如果该值不为0则表示当前进程正在被其他进程跟踪调试。libmsaoaidsec.so可以定期检查这个值一旦发现被跟踪立即触发反制措施如崩溃、退出或执行误导性代码。检测调试器连接通过ptrace或其他接口进行自检尝试与一个不存在的调试器交互观察行为是否异常。2.4 基于定时器与时间差检测这是一种相对隐蔽的检测方法。调试器单步执行、断点都会显著减慢程序的执行速度。检测原理计算代码段执行时间在两条关键指令之间插入高精度计时器如clock_gettime(CLOCK_MONOTONIC, ...)。在正常执行下这段代码的运行时间在纳秒或微秒级。如果处于调试状态尤其是单步调试时间差会急剧增大到毫秒甚至秒级。libmsaoaidsec.so可能在一些循环或关键函数入口/出口处设置这样的检查点。检测gettimeofday或clock_gettime调用频率调试时研究员可能会频繁调用这些函数来观察时间安全模块可以监控这些系统调用的异常频率。3. 绕过方案设计与核心思路拆解面对上述层层检测我们的绕过思路也需要立体化不能指望一招鲜吃遍天。核心原则是隐藏特征、混淆行为、主动对抗。3.1 思路一配置隐藏与特征修改治标这是最先尝试的步骤目的是消除最明显的特征可能对早期版本或检测力度不强的版本有效。修改Frida Server端口与名称原理避免被基于默认端口27042和进程名frida-server的扫描检测到。操作启动Frida Server时使用非标准端口例如frida-server -l 0.0.0.0:8080。同时将可执行文件重命名为一个看似无害的名字如mediaserver或surfaceflinger。局限性高级检测会扫描所有开放端口和进程列表单纯改名换端口可能被基于行为或内存特征的二次分析识破。使用Frida Gadget模式嵌入式原理不通过frida-server进行远程连接而是将libfrida-gadget.so直接打包或注入到目标APK中。应用启动时自动加载Gadget通过配置文件或环境变量与脚本交互。操作修改APK的AndroidManifest.xml在application标签中添加android:extractNativeLibstrue如果尚未设置并将libfrida-gadget.so重命名为目标应用已有的某个库名如libhelper.so替换掉原APK中的该文件。同时需要配置对应的config.json文件来指定脚本加载方式。优势完全避开了网络端口和独立frida-server进程隐蔽性大大提升。挑战需要反编译、重打包APK可能触发签名校验libfrida-gadget.so本身在内存中的映射特征仍需处理。3.2 思路二Hook与内存对抗治本这是技术核心通过主动干预libmsaoaidsec.so的执行逻辑使其检测函数失效或返回错误结果。关键函数Hook目标函数识别libmsaoaidsec.so中用于检测的关键函数。这些函数名可能经过混淆但可以通过分析其导入表如fopen、readlink、readdir、ptrace、gettimeofday、clock_gettime或字符串常量如/proc/self/mapsfrida来定位。Hook策略文件读取相关Hookfopen、read、getdents等。当路径参数包含/proc/self/、/proc/net/或frida等关键词时返回错误码如-1或伪造一个“干净”的文件内容。进程/线程遍历相关Hookreaddir或扫描/proc目录的相关函数。在返回的目录项列表中过滤掉名称包含frida或与Frida Server相关的条目。时间相关Hookgettimeofday和clock_gettime。当检测到调用来自可疑的检测代码段时返回一个被缓存过的、正常的时间值消除因调试停顿产生的时间差。ptrace与TracerPid相关Hookptrace函数使其调用失败或返回成功但实际不做任何事情。对于读取/proc/self/status的检测可以在文件读取层就返回一个TracerPid: 0的伪造内容。内存补丁Inline Hook原理直接修改libmsaoaidsec.so在内存中的代码段将关键的检测指令如条件跳转BNE,BEQ修改为相反的逻辑或者直接替换为NOP无操作指令让检测分支永远无法触发。操作首先需要定位到检测逻辑的汇编代码位置。这通常需要通过静态分析IDA Pro, Ghidra找到检测函数并确定其对应的机器码在内存中的偏移。然后使用Frida的Memory.protect()API临时将该内存页改为可写再用Memory.writeByteArray()写入修改后的指令。示例ARM64假设检测到Frida后执行BL abort跳转到崩溃函数。我们可以找到这条BL指令将其替换为NOP指令在ARM64下NOP的机器码通常是0xd503201f。风险直接修改代码段可能破坏指令对齐或缓存导致崩溃。且不同版本或不同设备上的库代码偏移可能不同通用性差。环境伪装与干扰原理不直接对抗检测函数而是创造一个“检测结果正常”的假环境。操作伪造/proc文件系统这是一个高阶技巧。通过Hook底层文件系统访问为libmsaoaidsec.so虚拟出一个不包含任何Frida痕迹的/proc视图。这需要深入Hook VFS相关函数。干扰时间基准在应用启动早期就Hook时间函数并引入一个微小的、随机的延迟变量使得时间差检测的基准本身就不稳定难以设定有效的阈值。3.3 思路三逆向分析与精准打击这是最根本的方法但需要投入更多时间进行逆向工程。静态分析定位检测点使用IDA Pro、Ghidra等工具反编译libmsaoaidsec.so。搜索字符串常量如fridamapsstatustcp、分析交叉引用找到所有疑似检测逻辑的函数。动态调试验证在模拟器或已Root的设备上使用gdb或lldb附加到加载了该库的进程在疑似检测函数上下断点观察其调用栈、参数和返回值确认其具体行为。绘制检测流程图理清所有检测逻辑的先后顺序和依赖关系。有时绕过一个前置检测后续的检测就不会被执行。找到整个链条中最薄弱、最易绕过的一环。制作针对性绕过脚本基于上述分析编写一个高度定制化的Frida脚本。这个脚本可能只在特定的时机如库初始化后、某个检测函数被首次调用前执行一次性的内存补丁或关键函数Hook而不是全局Hook以减少性能开销和潜在冲突。4. 实操构建一个通用的Frida绕过脚本框架下面我将构建一个相对通用的Frida脚本框架它整合了多种绕过思路。在实际使用时你需要根据目标libmsaoaidsec.so的具体情况调整Hook点和策略。Java.perform(function () { console.log([*] 开始对抗 libmsaoaidsec.so 检测); // 获取基础模块 var linker Process.findModuleByName(linker); var libc Process.findModuleByName(libc.so); // 如果没有找到libc尝试其他常见名称 if (!libc) libc Process.findModuleByName(libc.so.1); if (!libc) { console.log([-] 未找到libc模块); return; } // 1. 关键文件读取函数 Hook var fopen Module.findExportByName(libc.so, fopen); if (fopen) { Interceptor.attach(fopen, { onEnter: function (args) { this.path args[0].readCString(); if (this.path) { // 过滤掉包含frida关键词的路径以及关键的/proc文件 if (this.path.indexOf(frida) ! -1 || this.path.indexOf(gadget) ! -1 || this.path /proc/self/maps || this.path /proc/net/tcp || this.path /proc/net/tcp6 || this.path.indexOf(/proc/self/task) 0) { console.log([!] fopen 被拦截: ${this.path}); // 返回NULL模拟打开失败 this.fakeReturn true; } } }, onLeave: function (retval) { if (this.fakeReturn) { retval.replace(ptr(0)); // 返回NULL指针 } } }); console.log([] fopen Hook 已安装); } // 2. 目录读取函数 Hook (用于/proc扫描) var readdir Module.findExportByName(libc.so, readdir); if (readdir) { Interceptor.attach(readdir, { onEnter: function (args) { // 我们可以在这里记录DIR*但更常见的做法是在onLeave过滤返回值 }, onLeave: function (retval) { if (!retval.isNull()) { // readdir返回struct dirent*其中d_name是文件名 // 注意这是一个简化的示例实际需要解析dirent结构体 // 这里演示思路更彻底的过滤需要在getdents/readdir64层面进行 var dirEntry retval; // 假设我们能读取到文件名这里仅作演示 // 实际项目中可能需要根据libc版本和架构解析正确的偏移量 try { // 这是一个不稳定的示例仅说明思路 // var namePtr dirEntry.add(/* d_name 偏移 */); // var name namePtr.readCString(); // if (name name.indexOf(frida) ! -1) { // // 跳过此项递归调用自己返回下一项复杂此处不展开 // console.log(过滤进程/目录: ${name}); // } } catch(e) {} } } }); console.log([] readdir Hook 已安装); } // 3. 时间函数 Hook (对抗时间差检测) var gettimeofday Module.findExportByName(libc.so, gettimeofday); var clock_gettime Module.findExportByName(libc.so, clock_gettime); var lastTime { sec: 0, usec: 0 }; var timeJitterEnabled false; if (gettimeofday) { Interceptor.attach(gettimeofday, { onEnter: function (args) { var tv args[0]; var tz args[1]; // 检查调用栈判断是否来自可疑的检测模块 var backtrace Thread.backtrace(this.context, Backtracer.ACCURATE); var isFromSecurityLib false; for (var i 0; i backtrace.length; i) { var mod Process.findModuleByAddress(backtrace[i]); if (mod mod.name.indexOf(msaoaidsec) ! -1) { isFromSecurityLib true; break; } } if (isFromSecurityLib timeJitterEnabled) { // 如果是检测库在调用且我们启用了时间干扰则返回一个固定的或微小递增的时间 if (tv !tv.isNull()) { this.shouldFake true; this.tv tv; lastTime.usec 1000; // 增加1毫秒 if (lastTime.usec 1000000) { lastTime.sec 1; lastTime.usec - 1000000; } } } }, onLeave: function (retval) { if (this.shouldFake this.tv) { // 伪造时间结构体 this.tv.writeU32(lastTime.sec); this.tv.add(4).writeU32(lastTime.usec); } } }); console.log([] gettimeofday Hook 已安装); } // 4. ptrace Hook (防止附加和检测) var ptrace Module.findExportByName(libc.so, ptrace); if (ptrace) { Interceptor.attach(ptrace, { onEnter: function (args) { this.request args[0].toInt32(); // PTRACE_TRACEME 是防止被附加的常用调用 if (this.request 0 /* 假设PTRACE_TRACEME的值是0实际值需查系统头文件如ptrace.h */) { console.log([!] 检测到 ptrace(PTRACE_TRACEME, ...)尝试阻止); this.shouldBlock true; } // 也可以拦截 PTRACE_ATTACH 等 }, onLeave: function (retval) { if (this.shouldBlock) { // 返回-1并设置errno为EPERM retval.replace(ptr(-1)); // 在Android上设置errno可能需要更精细的操作这里是一个简化示例 console.log([] 已阻止 ptrace(PTRACE_TRACEME)); } } }); console.log([] ptrace Hook 已安装); } // 5. 直接内存扫描与补丁 (针对已知检测函数) // 首先我们需要找到 libmsaoaidsec.so 模块 var targetModule null; Process.enumerateModules().forEach(function (mod) { if (mod.name.indexOf(msaoaidsec) ! -1) { targetModule mod; console.log([] 找到目标模块: ${mod.name} ${mod.base}); } }); if (targetModule) { // 示例假设我们通过逆向知道在偏移0x1234处有一个关键比较指令 // 如果比较成功发现Frida就会跳转到崩溃函数。 // 我们的目标是将条件跳转改为无条件跳转或NOP掉。 var patchOffset 0x1234; // 这需要根据实际分析确定 var patchAddress targetModule.base.add(patchOffset); // 读取原始指令假设是ARM644字节一条指令 var originalInstruction patchAddress.readU32(); console.log([*] 地址 ${patchAddress} 原始指令: 0x${originalInstruction.toString(16)}); // 假设原始指令是条件跳转 B.NE (跳转如果不相等) // 我们想把它改成 B (无条件跳转)或者直接改成 NOP // 这需要知道具体的机器码。这里以改为NOP为例。 var nopInstruction 0xd503201f; // ARM64 NOP // 修改内存保护为可写 Memory.protect(patchAddress, 4, rwx); // 写入NOP指令 patchAddress.writeU32(nopInstruction); console.log([] 已在 ${patchAddress} 应用内存补丁 (NOP)); // 恢复内存保护可选根据情况 Memory.protect(patchAddress, 4, r-x); } else { console.log([-] 未找到 libmsaoaidsec.so 模块跳过内存补丁); } console.log([*] 绕过脚本框架加载完成。注意部分功能需要根据目标库具体调整。); });脚本使用说明将上述脚本保存为bypass_msaoaidsec.js。在已Root的设备上启动目标应用。使用Frida CLI附加并加载脚本frida -U -f com.target.app -l bypass_msaoaidsec.js --no-pause观察控制台输出看是否有拦截日志。如果应用不再崩溃或Frida可以稳定附加说明部分措施生效。重要提示这是一个框架性示例。实际生效需要你根据目标libmsaoaidsec.so的具体版本来调整函数名与偏移fopen、readdir等函数名是通用的但ptrace常数的值如PTRACE_TRACEME需要根据设备架构和libc版本确定。内存补丁的偏移量0x1234是占位符必须通过逆向分析获取真实偏移。检测逻辑顺序有些库会先进行ptrace自保再进行文件扫描。如果ptrace防护没解除后续Hook可能无法生效。可能需要调整Hook的时机或顺序。字符串过滤示例中过滤了frida但实际库可能使用大小写变换、字符串加密或哈希比较。你需要逆向分析找到它实际搜索的关键词。5. 高级对抗与动态检测规避当基础Hook和补丁失效时说明libmsaoaidsec.so可能采用了更高级的检测技术。5.1 对抗反Hook与完整性校验一些高级的安全库会检查自身关键函数是否被Hook。检测原理代码段CRC校验计算自身.text段代码段的CRC32或MD5哈希值与预存的合法值对比。指令头检查检查函数开头几条指令是否被修改为跳转指令如LDR PC, ...或B指令这是Inline Hook的典型特征。系统调用表检查直接读取内核的系统调用表sys_call_table检查ptrace、open等关键系统调用的地址是否被修改。绕过策略Hook校验函数本身找到执行CRC校验或指令检查的函数在其读取内存或计算哈希之前返回原始的、未修改的内存数据。这需要你能够区分“校验函数读取内存”和“正常执行读取内存”的上下文通常可以通过分析调用栈来实现。使用更底层的Hook技术如果库检查系统调用表那么用户态的Hook如Interceptor.attach可能被察觉。可以考虑使用内核模块如Kernel Module进行更底层的拦截但这需要设备具有可加载内核模块的能力且风险极高。Return Oriented Programming (ROP)在不修改函数头的情况下通过精心构造的ROP链改变程序执行流。这非常复杂通常用于漏洞利用在Frida对抗中较少见。5.2 对抗基于异常行为的检测安全库可能会故意触发一些异常观察处理过程是否被调试器干扰。检测原理断点指令陷阱在代码中插入brkARM或int3x86指令。在正常执行时这些指令会触发信号SIGTRAP由应用自身的信号处理器处理。如果调试器存在它可能会先捕获这个信号从而改变程序行为或被检测到。非法指令陷阱执行一条非法指令。同样观察信号处理流程是否异常。单步陷阱利用ptrace的单步执行标志结合时间检测判断是否每一步都在被跟踪。绕过策略信号处理HookHooksigaction或signal函数确保应用设置的信号处理器被正确安装。当陷阱信号发生时让信号处理器正常执行。让调试器“隐身”配置Frida或调试器使其对某些信号如SIGTRAP采取“不处理、不通知、直接传递”的策略。对于Frida这可能需要修改其源码或使用更底层的调试API。时间干扰强化如前所述更精细地控制时间函数Hook使得即使在单步模式下时间差也落在“合理”的随机波动范围内。5.3 动态环境感知与自适应绕过最稳健的绕过方案是能动态感知当前环境并自动调整策略。实现思路特征库匹配维护一个已知libmsaoaidsec.so版本的特征库如关键函数哈希、字符串常量、检测代码片段的字节模式。脚本加载后先扫描内存中的模块匹配特征库识别出具体的库版本。策略分发根据识别出的版本自动加载对应的、经过验证的绕过策略特定的Hook点、内存补丁偏移量、字符串过滤列表。行为监控与反馈脚本运行后持续监控目标进程的状态是否崩溃、关键线程是否存活。如果某个绕过策略导致崩溃可以尝试回滚或切换到备用策略。这相当于为你的Frida脚本编写了一个“杀毒引擎”但实现复杂度很高通常用于商业化的安全研究工具中。6. 常见问题排查与实战心得在实际操作中你肯定会遇到各种问题。下面是一些常见坑点和解决思路。6.1 问题排查清单问题现象可能原因排查思路与解决方案Frida无法附加提示Failed to attach: unable to connect to remote frida-server1. Frida Server未运行或端口被占用。2. 防火墙或SELinux策略阻止。3.libmsaoaidsec.so在应用启动早期就阻止了网络连接或杀死了Frida进程。1. 检查adb shell ps | grep frida确认server在运行。用netstat检查端口。2. 临时禁用SELinuxsetenforce 0需要root。3.尝试使用Gadget模式完全绕过网络连接。附加成功但注入脚本瞬间目标进程崩溃1. 脚本语法错误或访问了非法内存。2.Hook了不该Hook的函数或内存补丁位置错误导致程序逻辑破坏。3. 触发了安全库的崩溃反制机制。1. 先注入一个最简单的console.log脚本测试。2.逐步启用脚本中的Hook功能定位导致崩溃的Hook点。使用try-catch包裹可疑代码。3. 分析崩溃日志logcat看崩溃点是否在libmsaoaidsec.so内。脚本注入后部分功能正常但过几秒或触发某个操作后崩溃1.延迟检测安全库并非在启动时立即检测而是在特定逻辑分支或定时器中触发。2. 脚本的Hook改变了程序状态导致后续逻辑出错。1.逆向分析找到触发检测的具体函数或条件。可能是在某个按钮点击、网络请求后。2. 尝试更精确的Hook条件避免影响正常业务流程。内存补丁应用成功但检测依然生效1.补丁位置错误你修改的并非真正的检测点或者库有多个检测副本。2.完整性校验库检测到自身代码被修改启用了备用检测路径或直接崩溃。3.指令缓存修改代码段后CPU的指令缓存未更新仍然执行旧指令。1.重新进行静态和动态分析确保找到正确的指令。使用调试器在补丁地址下断点看是否真的执行到。2.先Hook并绕过CRC校验函数。3. 在修改内存后尝试调用__builtin___clear_cache如果可用或触发一个内存屏障。在Frida中直接修改内存后通常需要确保该线程执行流离开该代码区域再返回。在非Root设备上Gadget模式绕过措施无效1. 权限不足无法Hook系统库如libc.so。2. Gadget加载顺序晚于安全库的初始化检测。1. Gadget模式下只能Hook目标应用自身的库和已加载的库。确保你的脚本在Gadget初始化早期如onLoad就执行。2.将Gadget库名改为比libmsaoaidsec.so按字母顺序更靠前的名字使其先被加载从而有机会Hook后续库的函数。6.2 实战心得与技巧逆向先行切勿盲打在编写绕过脚本前花时间用IDA Pro/Ghidra静态分析libmsaoaidsec.so。理解它的初始化流程、检测函数调用图、字符串常量这能让你事半功倍。动态调试gdb/lldb则是验证猜想的关键。最小化Hook原则不要一上来就Hook所有可疑函数。这会导致性能下降且不稳定。先通过分析确定最核心的1-2个检测入口进行精准打击。往往绕过一个关键检查整个防护链条就断了。分阶段测试编写脚本时采用“增量化”测试。先写一个什么都不做的脚本确保能稳定附加。然后每次只添加一个Hook或一个补丁测试是否崩溃。这样能快速定位问题点。关注/proc/self/maps和/proc/self/task这是安全库获取信息的主要来源。你的绕过脚本是否成功可以首先观察这些虚拟文件的内容是否被“净化”。你可以写一个小脚本在Hook后主动读取这些文件并打印看看Frida的痕迹是否还在。利用Frida的Stalker对于特别顽固的、逻辑复杂的检测函数可以使用Frida的Stalker功能进行指令级跟踪看清每一条指令的执行和分支从而找到最合适的修改点。社区与开源情报libmsaoaidsec.so可能被多个应用使用。在GitHub、安全论坛搜索其哈希值或特征字符串很可能找到别人已经分析过的资料或现成的绕过脚本片段可以作为参考起点。接受失败准备多套方案移动安全对抗是持续的军备竞赛。你这次成功的绕过方法在下个版本更新后可能就失效了。因此保持对新技术如eBPF用于观测的关注并准备多种绕过思路修改特征、Hook、补丁、虚拟机/模拟器检测绕过等的组合拳才能应对自如。绕过libmsaoaidsec.so这类反调试库是一个典型的“猫鼠游戏”。它没有一劳永逸的银弹考验的是你对系统底层机制的理解、逆向工程的耐心和创造性思维。每一次成功的绕过都是对移动应用安全边界的一次深刻探索。

相关新闻