拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Android安全攻防完全指南:从静态分析到动态调试实战

提起Android安全攻防很多刚入门的朋友第一反应是“水太深”觉得又要会Java又要懂汇编还得啃Linux内核还没开始就劝退了。实际上这个方向确实杂但并没有玄到摸不着门。我这些年做移动端安全测试和加固方案落地最深的感受是只要把“攻击面”理清楚知道对方或者自己的数据到底存在哪、从哪进来、往哪出去攻防的思路其实就八九不离十了。这篇内容是我把之前零散整理的笔记汇总成的一份《Android安全攻防完全指南》定位是给有一定Android开发基础、想系统了解安全测试与防护思路的同学看的。整个系列走的是“先拆解攻击面再上工具实操最后谈修复方案”的路线尽量把每一步的原理和为什么这样做讲明白而不是丢给你一串命令让你照抄。文章会覆盖环境搭建、静态分析、动态调试、常见漏洞场景以及相关排查思路内容比较长建议收藏后顺着往下读读到哪算哪实操的时候再翻回来对应章节。1. 内容整体设计与思路拆解1.1 为什么把安全攻防拆成“静态分析”和“动态调试”两条主线我见过很多人学Android安全一上来就拿着一堆工具瞎点今天试试jadx明天装个Frida结果折腾半个月还是只会看别人的教程遇到一个新App依然不知道从哪下手。问题出在缺少一个完整的认知框架。我自己习惯把整个攻防过程拆成两条主线静态分析和动态调试。静态分析是你拿到一个APK之后在不运行它的前提下直接对安装包本身做解剖。比如里面有哪些组件、申请了哪些敏感权限、代码里有没有硬编码的密钥、核心逻辑放在了哪个包名下面。动态调试则是把应用跑起来在运行过程中观察它的行为调用了哪些系统API、网络请求发给谁、本地数据库写了什么、某个函数的参数和返回值是什么。这两条线是互补关系。静态分析帮你快速建立全局认知动态调试帮你验证猜测并观察运行时行为。真正高效的测试流程永远是先静态后动态先用静态分析锁定嫌疑区域再用动态调试深入验证。反过来也可以动态调试发现异常行为再回到静态代码里定位实现逻辑两边交叉印证。1.2 从攻击面出发建立防御认知安全攻防有一句老话你不可能防御你看不见的东西。放在Android上一个应用的攻击面其实非常有限把它们列出来基本就这几类文件与数据存储、IPC组件暴露、网络通信、动态代码加载、WebView与JS桥、外围接口蓝牙、NFC等。你要做的就是在这些攻击面上逐一检查看哪里的保护做得不够。这个思路对应到代码层面就是去审视每一个关键节点的“信任边界”。比如这个App把登录凭证存在哪里SharedPreferences还是加密数据库组件有没有设置exportedfalseWebView的addJavascriptInterface暴露了哪些方法这些问题的答案就是攻防博弈的主战场。需要注意的是本文涉及的所有技术点都以合法合规为前提只适用于你自己拥有或已获得明确授权的应用测试。安全攻防的价值在于通过“知己知彼”来加固自己的应用而不是用来做任何未经授权的操作。1.3 工具链选型的原则Android安全测试工具非常多我用过一圈之后保留下来的是这么一套jadx负责静态反编译apktool负责资源解包重打包Frida全家桶负责动态插桩objection配合做运行时探索Burp Suite抓HTTP/HTTPS流量再加上frida-dexdump用于脱壳场景。选这套组合的原因很直接都是社区活跃、文档齐全、踩坑记录多的工具遇到问题能搜到解决方案这一点在实操里比啥都重要。这套工具链既覆盖了从静态到动态的全流程又兼顾了不同的测试场景。比如app加固了没法直接jadx看代码就需要动态手段先脱壳明文的HTTP请求直接用Burp就能看但遇到SSL Pinning就得靠Frida绕过。后面我会结合具体场景讲怎么配合使用。2. 环境搭建与前置知识准备2.1 模拟器与真机的取舍做动态调试之前先解决运行环境的问题。模拟器和真机各有优劣我建议条件允许的话准备一台专门的测试真机理由有三点。第一部分App会做模拟器检测你在模拟器里跑都跑不起来更别说调试了。第二模拟器在底层硬件模拟上跟真机有差异涉及传感器、蓝牙、GPS这类外围接口的功能没法完整测试。第三Frida在真机上的稳定性比模拟器好很多不容易出现莫名其妙的服务掉线。如果你确实只有模拟器也不是不能用跑一些不涉及敏感硬件的基础测试还是可以的。建议选择Android 9及以上系统镜像x86架构在性能上比ARM翻译模式好但在so文件的兼容性上不如ARM镜像。这块没有绝对的答案按你的测试目标来选就行。我的主力测试环境是一台Pixel系列手机刷了原生系统并解锁了BL一台日常开发用的电脑装好整套工具链。Frida要注意的是必须有root权限才能注入系统进程普通应用进程倒是可以借助ptrace方式调试但会麻烦不少。2.2 Windows / macOS / Linux环境下的工具安装要点我以Windows环境为主其他系统原理类似只说一下差异点。Frida需要安装两部分电脑端的frida-tools和目标设备运行的frida-server。电脑端直接pip install frida-tools即可设备端需要从官方仓库下载对应架构的frida-server再推送到设备的/data/local/tmp目录。需要注意frida版本需要匹配电脑端frida和手机端frida-server版本要一致否则会报错。这里给出一个快速自检方法在电脑终端执行frida-ps -U如果能列出设备进程就说明服务端和客户端连接正常这一步值得先跑通再往下走。还有其他工具的安装细节apktool是一个jar包直接下载后配置环境变量就能用jadx有图形界面版在GitHub下载对应平台的压缩包解压即用Burp Suite装好之后要配置代理让手机和电脑在同一个局域网内。这些细节都卡在“看起来很简单但第一次就是连不上”的地方后面实操篇我会把完整的配置截图思路写出来。2.3 避不开的基础概念APK结构与权限模型很多教程默认你已经懂了APK是个zip包也知道四大组件是什么结果新手上来直接懵。我这里花几十行把最关键的概念过一遍有基础的可以直接跳到下一节。APK本质上是一个压缩包里面主要的目录和文件有这些classes.dexApp的Java/Kotlin代码编译后的字节码文件是静态分析的核心对象。AndroidManifest.xmlApp的全局配置文件声明所有组件、权限、Application等信息。resources.arsc资源索引表记录资源ID与具体资源的映射关系。lib/存放so库按CPU架构分为armeabi-v7a、arm64-v8a、x86等子目录。assets/和res/存放原始资源和编译后的资源主要涉及资源混淆和加固。四大组件则包括Activity界面、Service后台服务、BroadcastReceiver广播接收器、ContentProvider内容提供者。每个组件都可以在Manifest里设置exported属性决定是否允许其他应用调用这个属性是组件攻击面的核心开关检查App安全时我几乎总是第一个看它。还有一个绕不开的概念是Android权限模型。App需要在Manifest里声明权限系统在安装时或运行时让用户授权。安全测试要关注的是权限的最小化原则比如一个手电筒应用申请读取联系人这种权限滥用就是很典型的风险点。3. 静态分析实操从APK里挖掘敏感信息3.1 初诊看一眼Manifest就能发现的问题静态分析第一步永远是把APK拖进jadx先看AndroidManifest.xml。这一步能发现大量表面问题不用分析一行代码。具体检查哪些点呢我列一个自己常用的检查清单所有组件是否都设置了exportedfalse尤其是有intent-filter的组件一旦声明了intent-filter系统会默认允许外部隐式调用。是否申请了与业务无关的敏感权限比如读取短信、定位、录音等。backup和debug属性是否为trueAndroidManifest里android:debuggabletrue表示可调试被反编译后风险极大。是否有自定义权限却在签名上没做protectionLevel约束。比如你看到一个App的某个Activity声明了exportedtrue同时又带着一个native的字符串参数那就可以去对应代码里看看它怎么处理这个参数。如果直接把参数传给WebView去loadUrl那就是一个典型的Intent注入风险点。这类问题通过静态扫描就能定位效率很高。3.2 五步定位核心业务代码拿到Manifest之后接下来要在方法数动辄几万的dex里找到核心代码。新手最容易在这里迷失不知道从哪看起。我总结了一套五步定位法实际测试中一直在用效率还不错。第一步看Application类。Application是App启动时最先执行的入口很多全局初始化、SDK注册、加密密钥的初始化都放在这里。jadx左侧直接找到Application子类读一遍它的onCreate方法基本能对App的整体框架有个了解。第二步搜关键字。不管代码混淆得多厉害字符串是藏不住的。直接在jadx里搜索一些关键词password、secret、aes、des、token、api_key、private_key等。这些硬编码的敏感信息是静态分析最容易逮到的收获。第三步追踪URL与网络请求。搜索https://或者http://先看App发了哪些请求然后顺着请求栈找到封装网络层的地方再找到签名生成的方法。有时候你会发现开发人员把签名逻辑写在客户端这意味着你在本地完全可以复刻签名伪造任意请求。第四步查数据库和文件操作。搜索SQLiteDatabase、openOrCreateDatabase、getSharedPreferences、getExternalStorageDirectory等关键字看看敏感数据存在哪里、有没有加密。大部分普通App的本地存储都是裸奔的root之后数据随便看。第五步看native层。如果核心算法在so库里Java层的表现通常是一个native方法的声明。定位到它之后再用IDA或Ghidra分析对应的so库。这个门槛略高但如果是做协议逆向或者加密分析绕不开这一步。3.3 识别加固方案壳种类与应对思路当你发现jadx打不开代码说明App做了加固。加固的原理是把真实的dex文件加密运行时在native层解密加载所以静态分析直接看是看不到真实字节码的。识别壳的工具有几款比如lib-detect壳检测、Xposed模块“AppOps”都可以看。简单方法是在NativeLibs里找so文件的名字各家加固厂商的so命名有规律比如某某盾的libprotectClass.so、某某加固的libDexHelper.so一看就知道是哪家的方案。对加固App的应对策略最基础的方式是内存脱壳。用Frida脚本在dex被解密并加载进内存之后把内存中的dex dump出来再用jadx分析。frida-dexdump就是这么干的开源方案。实测大部分企业级加固在默认配置下都能直接脱壳如果遇到高强度的VMP加固就需要结合主动调用与Unidbg等方案模拟执行那就是更高阶的方向了需要单独展开。4. 动态调试与Hook实操4.1 Frida环境自检与连接说再多静态分析真正上手之后你会发现动态调试才是效率核心。Frida这个工具允许你在App运行过程中动态注入JavaScript代码用来拦截函数、修改返回值、调用任意方法是Android安全测试的标配。先跑通最简单的连接链路确保电脑和设备上的frida-server版本一致之后执行frida-ps -U如果能列出设备进程列表环境就通了。接下来尝试对某个进程做基础hook比如我们想看看某个App进程里HashMap的put方法被调用的调用栈Java.perform(function () { var HashMap Java.use(java.util.HashMap); HashMap.put.implementation function (key, value) { console.log(HashMap.put called: key value); return this.put(key, value); }; });这段脚本的意思是劫持HashMap的put方法打印key和value再调用原方法保证逻辑不回滚。跑通了这一步说明你已经具备了最基本的动态插桩能力。4.2 典型场景实战拦截关键函数参数与返回值动态注入最常见的实战场景是分析一个关键函数的入参与返回值。假设某App有一个aesEncrypt方法你想知道它加密了什么内容以及加密后的结果直接在jadx里找到方法名然后写Frida脚本hook它。以拦截某个打包好的自定义加密方法为例我一般会先在jadx里定位出方法声明public static String a(String plainText, String key) { // ... return encryptedData; }对应的Frida脚本可以这么写Java.perform(function () { var Cls Java.use(com.example.crypto.EncryptHelper); Cls.a.overload(java.lang.String, java.lang.String).implementation function (plainText, key) { var result this.a(plainText, key); console.log(plainText: plainText); console.log(key: key); console.log(encrypted: result); return result; }; });这里的核心思想是先按原签名调用原方法拿到返回值再把参数和返回值一起打出来。这样一边观察业务数据流一边可以对加密逻辑进行黑盒分析不用去看so库的汇编也能得到关键信息。4.3 从“抓不到包”到“一清二楚”绕过证书锁定实战移动端安全测试里抓不到HTTPS流量是最高频的卡点之一。App在客户端做了SSL Pinning只信任固定的服务器证书导致代理工具无法解密流量。绕过它的思路不止一种这里说一种我实测有效的通用方案。利用Frida绕过SSL Pinning主要通过Hook证书校验相关的系统API。常见的目标包括TrustManagerImpl的verifyChain方法、OkHttp的CertificatePinner.check方法等。示例代码Java.perform(function () { var TrustManagerImpl Java.use(com.android.org.conscrypt.TrustManagerImpl); TrustManagerImpl.verifyChain.implementation function (unverifiedChain, authMethod, host, clientAuth, ocspData, tlsSctData) { return this.verifyChain(unverifiedChain, RSA, host, clientAuth, ocspData, tlsSctData); }; });或者使用现成的objection工具执行memory bypass ssl-pinning即可一键绕过大部分场景。objection -g com.example.app explore进入交互模式后运行android sslpinning disable绕过了证书锁定之后再用BurpSuite配合查看明文请求整个流量分析就从“盲人摸象”变成了“开卷考试”。需要注意证书锁定只是SSL Pinning的其中一种形式现在很多App也会对传输数据本身加密遇到这种情况得先定位加解密函数配合上一节的Hook手段来做。4.4 主动调用与批量自动化从单点验证到系统化测试Hook只能被动等函数被调用某些场景下需要主动调用方法才能触发逻辑。Frida的Java.use()得到的对象不只能修改implementation还能直接调用类里的静态方法和实例方法这在分析算法或触发隐蔽功能时很有用。比如想验证某个App的签名校验算法可以直接调用它的校验方法传入伪造的签名看返回值是什么Java.perform(function () { var SignChecker Java.use(com.example.util.SignChecker); var result SignChecker.checkSign(fake_signature); console.log(checkSign result: result); });再进一步如果你需要批量测试不同输入可以用Frida的Python绑定写个小脚本循环调用再配合每次调用的返回结果做分析。这个方法在做接口签名分析和自动化遍历时效率很高也是很多自动化工具链的底层原理。5. 典型漏洞场景与修复建议5.1 组件暴露四大组件为何成为攻击入口讲到这里“攻”的部分已经覆盖了静态与动态两条线接下来谈“防”。安全攻防最终要落到修复方案上否则只有破坏没有建设对实际工作没有任何帮助。Android组件暴露是最常见也是最容易被忽视的一类问题。前面提到exported属性时已经涉及这里展开说具体危害。如果一个BroadcastReceiver设置了exportedtrue攻击者就可以构造恶意广播触发它的逻辑如果是动态注册的Receiver在Android 13及以上系统还需要考虑flag的声明否则会收到系统限制。ContentProvider的暴露更危险。很多应用会在Manifest里把Provider设置为exported用于跨进程共享数据但如果提供的数据包含用户隐私、数据源路径可控攻击者就能直接通过content:// URI读取敏感信息甚至利用FileProvider的路径穿越漏洞读取App私有目录文件。这个思路对应对近期热门词汇里反复出现的content://com.tencent.wework.fileprovider和content://com.baidu.searchbox.fileprovider这类路径恰恰说明FileProvider暴露问题在真实世界中的普遍性。修复方案分两部分第一把所有不需要跨进程调用的组件显式设置android:exportedfalse第二必须暴露的组件做权限校验在代码里检查调用方的包名和签名避免被任意应用调用。5.2 数据存储SharedPreferences与数据库的裸奔问题很多开发者直接把登录token、用户手机号、身份证号等敏感信息明文存储在SharedPreferences或未加密的SQLite数据库里。在root过或者开启了USB调试的设备上攻击者可以直接读取这些文件。这里给几个实用加固建议。第一敏感信息优先用Android Keystore系统保存Keystore里的密钥材料不会离开安全硬件TEE/SE即使手机root了也拿不到明文密钥。第二数据库用SQLCipher做全库加密配合随机生成的密钥密钥再存到Keystore里。第三外部存储的文件不要存敏感数据如果必须存至少用AES-GCM加密后再写入并且文件权限设置为MODEPRIVATE。这块还有一个容易被忽视的点就是应用备份。如果Manifest里没有设置android:allowBackupfalse攻击者可以用adb backup命令把App数据完整备份走拿到的备份文件在本地直接解析就能得到数据库和shared_prefs。这一点建议所有涉及用户数据的App一律关掉或者至少做备份数据加密。5.3 WebView攻击面从JS桥到file域读取WebView是Android应用安全的另一个重灾区。addJavascriptInterface可能被远程网页恶意利用通过反射调用到App内部Java代码造成任意命令执行或数据窃取。以最常见的漏洞模式举例如果WebView开启了JavaScript并允许加载任意http(s)网页同时App在addJavascriptInterface里注入了带敏感方法的对象攻击者可以在自己控制的网页里构造恶意JS代码通过注入对象的方法读取本机文件或调用系统能力。修复方法如下第一addJavascriptInterface只在加载本地可信资产file:///android_asset/或httpshost白名单时启用不要对任意URL开启第二把注入对象的方法权限做到最小能不给的绝对不给第三targetSdkVersion提到17及以上这样只有带JavascriptInterface注解的方法能被网页调用避免反射攻击。5.4 网络传输层HTTP明文与弱加密协议网络层面的问题同样常见。很多App在开发调试阶段为了方便直接用HTTP明文接口上线时忘记切换然后流量被局域网内任意一个抓包工具看光。弱加密算法如DES、RC4和过时的TLS版本TLSv1.0也属于同类问题。做好网络层防护需要三个配合。第一全链路HTTPS并配置好证书校验建议做证书Pinning增加中间人攻击的成本。第二禁用明文流量targetSdkVersion 28及以上默认不允许明文流量开发者需要明确配置。第三传输内容也建议做一层应用层加密即使HTTPS被绕过攻击者拿到的也是密文。6. 常见问题与排查技巧实录6.1 高频问题速查表安全测试过程中会遇到各种奇奇怪怪的问题这里把最频繁的几个整理成速查表方便你遇到时直接对号入座。现象可能原因排查与解决思路frida-ps -U 无法连接设备服务端版本与客户端不一致或设备未root检查frida版本确认frida-server有执行权限尝试用USB而不是无线连接App检测到Frida后闪退应用内置Frida检测用frida-server改名、设置隐藏端口启动或改用Magisk模块方案检测点一般在so层需结合反调试思路绕过jadx打开加固APK看不到代码加固后真实dex未落地先用脱壳工具如frida-dexdumpdump内存中的dex再拖回jadx分析BurpSuite抓不到HTTPS包证书未信任或SSL Pinning先安装系统级CA证书再用objection或Frida绕过证书锁定模拟器里直接闪退App识别到模拟器环境换真机测试或者使用模拟器特征修改工具但这种绕过不一定能全过adb backup备份出来是加密文件Android 7.0以上默认备份加密低版本设备操作或使用其他数据获取方式so库函数分析卡住未识别导出函数或用了混淆指令用Ghidra/IDA的自动分析功能先看导出表再结合Frida对native函数做Trace这张表里的问题几乎每个项目都会碰到尤其是Frida连接和SSL Pinning绕过建议提前搭好环境验证一遍避免到具体测试时才现查。6.2 我在实操中踩过的坑最后分享几个在真实项目里踩过的坑当作给新人的经验提示。第一个坑是frida-server版本不匹配。有一次我电脑上frida-tools升级到了新版本忘了同步更新手机里的frida-server结果连接时一直报错“unable to start process”排查了很久才发现是版本号不一致。从那以后我的习惯是电脑端安装完frida之后第一时间执行frida --version再下载相同版本的frida-server。第二个坑是Magisk的隐藏功能。使用Magisk作为root方案时默认Magisk应用很多App都能检测出来后来发现Magisk自带了一个DenyList功能可以把金融类、游戏类App加进去让它们看不到root环境。这个设置给日常测试省了不少事。如果是在模拟器里测试很多模拟器自带root但兼容性问题多不如真机好使。第三个坑是脱壳后jadx还是打不开。我遇到过某数字加固壳dump出来的dex在jadx里能打开但某梆梆加固脱壳后dump出的dex是加密分段加载的重新拼装后还是不行后来用Frida脚本主动调用了系统的ClassLoader直接从内存里枚举了所有已经加载的类再逐个dump对应类的字节码侧路拿到了真实代码。这个思路可以用来应对部分高强度加固但过程确实麻烦需要有点耐心。第四个坑是Android 7.0以上的CA证书问题。很多新手按照老教程把Burp的CA证书装到用户证书目录结果发现App不信任用户证书流量还是抓不到。正确做法是把证书放到系统证书目录/system/etc/security/cacerts/这需要先remount系统分区。不同系统的挂载命令有差异可以直接搜对应版本的教程。6.3 动态调试中的反调试对抗到这一步基础的攻防流程就闭环了再补一个很多人问的进阶话题反调试对抗。现在的安全App几乎都有反调试能力常见的检测点包括Frida端口检测默认27042、/proc/self/maps里的frida-so痕迹、TracerPid是否被ptrace、运行时间与系统时间偏差等。对付这些检测无非是“改名字、换端口、清痕迹”三板斧。但是道高一尺魔高一丈最近一些企业级App已经开始检测系统调用层面的异常单纯在Java层做文章就不够用了。如果只是想了解原理建议先从“检测与绕过”的对抗中理解双方思考方式。我自己写过一个练习项目用Frida注入到Unidbg里跑so库的native逻辑绕开了设备环境相关检测这种做法在算法还原和协议分析场景里非常实用值得深入研究。不过这个话题展开又是一整篇等后面单独开一章讲。末尾分享一个我的使用习惯做安全攻防这行工具和脚本永远只是辅助真正值钱的是“怀疑一切”的思维方式和持续积累的问题库。我自己每次测试完一个App无论结果怎么样都会把流程记录成模板把踩过的坑和对应的排查思路整理进自己的速查表下次遇到类似问题直接查表比对节省大量时间。建议你也建立一个自己的笔记库哪怕一开始只有一个文档记录多了价值就会显现出来。每次遇到一个概率小的异常问题先停一下把它当作学习机会记下来比急着抢进度重要得多。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门