移动端接口参数逆向分析:从BSK参数抓包到Python算法还原

📅 2026/6/29 17:22:15
移动端接口参数逆向分析:从BSK参数抓包到Python算法还原
1. 项目概述一次典型的移动端接口参数逆向之旅最近在分析一个移动端应用时遇到了一个典型的场景某个社区应用的发帖接口在请求中携带了一个名为BSK的参数。这个参数看起来像是一串无规律的字符每次请求都会变化显然是服务端用于校验请求合法性、防止重放攻击或伪造请求的关键令牌。对于开发者、安全研究员或者自动化脚本编写者而言理解并能在本地还原这个参数的生成逻辑意味着能够模拟客户端行为进行更深度的功能测试、数据分析或自动化操作。这不仅仅是一个技术挑战更是一次完整理解客户端与服务端交互逻辑的绝佳实践。整个分析过程可以清晰地划分为几个阶段首先是数据捕获我们需要在移动设备上抓到包含BSK参数的原始网络请求其次是逆向分析聚焦于找到生成这个参数的代码位置并理解其算法最后是本地还原将算法用我们熟悉的编程语言如 Python重新实现并验证其有效性。这个过程会涉及到多种工具的组合使用包括抓包工具如 Fiddler/Charles、逆向工程工具如 Jadx-GUI、IDA Pro以及调试分析技巧。无论你是移动应用安全的新手还是希望深化逆向分析技能的开发者这次对BSK参数的“解剖”都将为你提供一个非常实用的技术范本。接下来我将以第一人称视角带你完整走一遍我从抓包到最终在 Python 中成功还原BSK生成逻辑的全过程并分享其中踩过的坑和总结的经验。2. 核心思路与工具选型为什么是这套组合拳面对“逆向分析某个参数”这类任务一个清晰、高效的策略至关重要。盲目地一头扎进反编译的代码海洋很容易迷失方向。我的核心思路是“由外而内动态追踪”。2.1 思路拆解从黑盒到白盒首先我们将整个应用及其网络交互视为一个黑盒。我们的突破口是网络流量。只要参数出现在HTTP/HTTPS请求中它就必然会被发送到网络上。因此第一步永远是抓包获取最原始、最真实的请求样本。这为我们提供了分析的“输入”和“输出”观察点我们能看到触发BSK生成的用户操作如点击发帖以及最终生成的BSK值。拿到足够多的样本后就可以进行初步的黑盒分析。比如观察BSK是否与时间戳有关是否与设备信息有关是否每次登录后固定通过对比不同时间、不同设备、不同账号下的请求可以缩小算法可能涉及的因素范围。然而对于现代应用仅靠黑盒猜测很难触及核心尤其是当算法涉及非对称加密、自定义哈希或与本地密钥结合时。这时就必须转向白盒分析即直接阅读代码。白盒分析的关键在于快速定位。我们不可能从头到尾阅读数百万行代码。如何在海量代码中找到生成BSK的那几行这里就需要动态分析或静态搜索技巧来引导。我常用的方法是结合关键词搜索和调用栈分析。在反编译得到的代码中全局搜索“BSK”这个字符串常量很可能直接找到拼接请求参数的代码位置从而逆向追踪到其生成函数。2.2 工具链选型与理由工欲善其事必先利其器。下面是我为这次任务选择的工具链及其原因抓包工具Fiddler Classic / Charles Proxy选择理由两者都是成熟的HTTP调试代理工具。我优先选择 Fiddler因为它对 Windows 平台的支持更原生且免费功能强大。它们的主要任务是在 PC 上设置一个代理服务器让手机流量通过这个代理从而拦截、查看和修改所有 HTTP/HTTPS 请求响应。这是获取原始BSK样本的必经之路。关键点需要处理 HTTPS 证书安装问题以解密 HTTPS 流量。Fiddler 可以一键生成并安装根证书到手机这一步至关重要。逆向分析工具Jadx-GUI 为主IDA Pro 为辅Jadx-GUI这是分析 Android APK 的“瑞士军刀”。它能将 APK 中的 DEX 文件反编译成可读性非常高的 Java 代码。对于大多数逻辑复杂但未做深度混淆的 App使用 Jadx 直接阅读源码是最快的方式。我们的主要战场就在这里。IDA Pro如果遇到核心算法被用 C/C 编写在 Native 层即 .so 动态库文件Jadx 就无能为力了。这时就需要 IDA Pro 这类强大的反汇编工具来逆向分析 ARM 汇编代码。本次分析幸运地没有走到这一步但我们必须为此做好准备。开发与验证工具Python 3 Requests 库选择理由算法还原后需要快速实现并验证。Python 语法简洁拥有丰富的加密库如hashlib,hmac,CryptoRequests库模拟 HTTP 请求也非常方便是进行 PoC概念验证开发的理想选择。辅助工具一部已 Root 的 Android 测试机或模拟器选择理由虽然抓包不一定需要 Root但在后续的动态调试、绕过 SSL Pinning证书绑定或访问应用私有目录时Root 权限会带来极大便利。例如有些应用会将密钥存储在/data/data/[包名]目录下。注意所有分析请仅在您拥有合法权限的应用上进行例如自己开发的 App、明确授权测试的 App 或用于学习研究的开源 App。未经授权对他人应用进行逆向分析可能涉及法律风险。3. 实操步骤一捕获网络流量与初步观察理论说得再多不如动手操作。让我们从最基础的抓包开始。3.1 配置 Fiddler 作为系统代理首先在电脑上启动 Fiddler。默认它会监听127.0.0.1:8888。我们需要确保它能捕获远程连接打开Tools - Options - Connections勾选Allow remote computers to connect。记下你的电脑在局域网内的 IP 地址例如192.168.1.100。3.2 在手机上配置代理并安装证书将手机和电脑连接到同一个 WiFi 网络。在手机的 WiFi 设置中修改当前网络选择“高级选项”或“代理”设置为手动主机名填写电脑的 IP192.168.1.100端口填写8888。此时用手机浏览器访问http://192.168.1.100:8888你会看到 Fiddler 的页面。点击FiddlerRoot certificate下载并安装证书。对于 Android 高版本可能需要在“设置-安全-加密与凭据”中从存储设备安装证书。安装成功后在 Fiddler 中应该能看到手机产生的 HTTP 流量。为了解密 HTTPS还需要在 Fiddler 的Tools - Options - HTTPS中勾选Decrypt HTTPS traffic。3.3 捕获目标请求打开目标应用进行发帖操作。在 Fiddler 的会话列表中你会看到大量的请求。我们需要找到发帖的接口。通常可以通过 URL 路径可能包含post、create、submit等关键词或请求方法POST来筛选。找到疑似发帖的请求后查看其Inspectors标签页下的WebForms或TextView这里会以表格或原始文本形式展示请求体。我们的目标BSK参数很可能就在这里。我捕获到的请求示例如下数据已脱敏POST /api/v1/post/create HTTP/1.1 Host: api.example.com Content-Type: application/x-www-form-urlencoded User-Agent: xxxApp/5.0.1 ... title测试标题content测试内容bsk7a89f3d2e8c1b54a6f9021ed37c5d8a9b0e4f7c2看bsk参数赫然在列是一串 32 位的十六进制字符串很像 MD5 的结果。3.4 初步黑盒分析我重复了几次发帖操作并记录了不同时间、相同内容下的bsk值时间 T1:bsk7a89f3d2e8c1b54a6f9021ed37c5d8a9b0e4f7c2时间 T2:bsk8b9a04e3f9d2c65b7a0132fe48d6e9b0c1f5g8d3时间 T3:bsk6c78e2c1d7b0a43b5e8910dc26b4c7f9a0d3e6b1观察发现每次的bsk都完全不同排除了它是固定值或基于静态内容生成的可能。接着我尝试在短时间内发送完全相同的标题和内容bsk依然变化这说明它很可能与时间戳或随机数强相关。此外32位十六进制128位的长度暗示其可能是一种哈希值如 MD5或 AES 加密后的结果。有了这些线索我们就可以带着假设进入代码层去寻找证据了。4. 实操步骤二静态逆向分析与关键代码定位拿到 APK 文件后我们用 Jadx-GUI 打开它。加载完成后左侧是项目文件树右侧是代码查看器。4.1 全局搜索寻找突破口最直接的方法是在 Jadx 中按CtrlShiftF进行全局文本搜索。我首先搜索了“bsk”。果然在几十个结果中我发现了关键线索。有一些字符串常量类似于bsk还有一些代码片段如params.put(bsk, generateBSK())或request.addParam(bsk, SecurityUtil.getBSKToken())。点击进入这些代码我们就能找到生成bsk的函数。在我的案例中我追踪到了这样一个类com.example.app.security.TokenGenerator。里面有一个核心方法public class TokenGenerator { private static final String SALT aStaticSaltValue; public static String generateBSK(String deviceId, long timestamp) { String rawString deviceId _ timestamp _ SALT; return md5(rawString); } private static String md5(String input) { try { MessageDigest md MessageDigest.getInstance(MD5); byte[] digest md.digest(input.getBytes(UTF-8)); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b 0xff)); } return sb.toString(); } catch (Exception e) { return ; } } }4.2 分析算法逻辑上面的代码非常清晰generateBSK方法接受两个参数deviceId设备ID和timestamp时间戳。它将这三个部分用下划线连接起来deviceId “_” timestamp “_” SALT。这里的SALT是一个硬编码在代码中的静态字符串。将这个连接后的字符串进行 MD5 哈希计算。将 MD5 输出的字节数组转换为 32 位小写十六进制字符串作为最终的bsk值。这完美解释了之前黑盒观察到的现象因为timestamp是毫秒级甚至微秒级变化的所以每次生成的bsk都不同。deviceId保证了不同设备之间的bsk也不同增加了伪造难度。静态SALT则是一个简单的“加盐”操作防止彩虹表攻击虽然对于 MD5 意义不大。4.3 寻找参数来源接下来需要确定deviceId和timestamp的具体值从哪里来。timestamp通常就是系统当前时间。在代码中搜索generateBSK的调用处发现传入的timestamp是System.currentTimeMillis()。deviceId这需要进一步追踪。在 Android 中设备标识符可能包括IMEI、Android ID、Serial Number或应用自己生成的UUID。通过交叉引用在 Jadx 中右键点击deviceId变量选择 Find Usage我找到了它是在应用初始化时通过Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID)获取的Android ID并进行了缓存。至此生成bsk的全部要素和算法都已经清晰bsk MD5(AndroidID “_” CurrentTimestamp “_” HardCodedSalt)。实操心得在 Jadx 中善用“查找用例”Find Usage和“导航到声明”Navigate - Declaration功能可以像在 IDE 中一样快速追溯变量和方法的来源与去向极大提升逆向效率。对于混淆过的代码类名和方法名可能变成a,b,c这时就需要结合调用上下文和字符串常量来推断其功能。5. 实操步骤三算法本地还原与验证算法已经清晰现在用 Python 在本地还原它。我们需要模拟出三个部分Android ID、timestamp和SALT。5.1 环境准备与代码实现首先确保 Python 环境已安装。我们主要使用hashlib库进行 MD5 计算。import hashlib import time def generate_bsk(device_id, timestamp_ms, salt): 根据逆向分析的算法生成 BSK 参数 :param device_id: 字符串模拟的 Android ID :param timestamp_ms: 整数毫秒级时间戳 :param salt: 字符串硬编码的盐值 :return: 32位小写十六进制字符串的 BSK # 拼接原始字符串 raw_string f{device_id}_{timestamp_ms}_{salt} # 计算 MD5 md5_hash hashlib.md5() md5_hash.update(raw_string.encode(utf-8)) bsk md5_hash.hexdigest() return bsk # 逆向得到的硬编码盐值 HARDCODED_SALT aStaticSaltValue # 模拟的 Android ID可以从之前抓包的请求头或其他接口响应中获取或者是一个固定值如果服务端不严格校验 SIMULATED_DEVICE_ID d5a4c8b7e1f2a309 # 获取当前毫秒时间戳 current_timestamp_ms int(time.time() * 1000) # 生成 BSK bsk_token generate_bsk(SIMULATED_DEVICE_ID, current_timestamp_ms, HARDCODED_SALT) print(fGenerated BSK: {bsk_token}) print(fTimestamp used: {current_timestamp_ms})5.2 关键细节与验证方法运行这段代码你会得到一个bsk值。但是如何验证它是否正确呢获取真实的 DeviceId最准确的方法是从抓包数据中获取。查看应用启动后第一个或早期几个请求特别是登录或设备注册接口的响应里面很可能包含服务端下发的设备标识或直接就是Android ID。也可以尝试在 Fiddler 中搜索包含android_id,deviceId等关键词的请求或响应。时间戳同步客户端和服务端的时间可能存在微小偏差。我们的 Python 脚本使用的是本地系统时间。为了验证你可以在抓包的同时记录下抓包工具显示的那个请求发出的精确时间Fiddler 的Timeline或Session列表有时间戳将其转换为毫秒时间戳代入你的 Python 脚本进行计算。然后将计算结果与抓包到的bsk值进行对比。发起真实请求验证这是终极验证。使用 Python 的requests库完全模拟发帖请求包括所有必要的 Header如User-Agent,Content-Type, 认证 Token 等并将我们自己生成的bsk放入请求体。如果服务端接受了请求并成功发帖或者返回了与bsk无关的其他错误如内容违规那就证明我们的bsk生成算法是正确的。如果返回“参数错误”或“签名无效”则需要检查deviceId和timestamp的准确性以及是否有其他未被发现的参数参与了计算。5.3 一个完整的验证脚本示例假设我们从抓包中提取到了以下信息接口 URL:https://api.example.com/api/v1/post/create认证 Header:Authorization: Bearer xxxx_your_login_token_xxxx其他固定参数import requests import time import hashlib def generate_bsk(device_id, timestamp_ms, salt): raw_string f{device_id}_{timestamp_ms}_{salt} return hashlib.md5(raw_string.encode(utf-8)).hexdigest() # 配置参数需要从抓包中获取并替换 HARDCODED_SALT aStaticSaltValue SIMULATED_DEVICE_ID d5a4c8b7e1f2a309 # 替换为真实值 API_URL https://api.example.com/api/v1/post/create AUTH_TOKEN xxxx_your_login_token_xxxx # 替换为真实Token USER_AGENT xxxApp/5.0.1 (Android 12; ...) # 替换为抓包中的UA # 准备请求 current_timestamp_ms int(time.time() * 1000) bsk_value generate_bsk(SIMULATED_DEVICE_ID, current_timestamp_ms, HARDCODED_SALT) payload { title: 测试帖子标题, content: 这是通过逆向BSK参数后自动发布的测试内容。, bsk: bsk_value, # 可能还有其他必要参数... } headers { Authorization: fBearer {AUTH_TOKEN}, User-Agent: USER_AGENT, Content-Type: application/x-www-form-urlencoded, } try: response requests.post(API_URL, datapayload, headersheaders, timeout10) print(f请求状态码: {response.status_code}) print(f响应内容: {response.text}) # 根据响应判断是否成功 if response.status_code 200: print(BSK 参数验证成功请求被服务端接受。) else: print(请求失败请检查其他参数或Token是否有效。) except Exception as e: print(f请求发生异常: {e})6. 深度排查与进阶问题应对在实际操作中很少有一次就成功的情况。下面分享几个我遇到过的典型问题及排查思路。6.1 问题一搜索不到“bsk”关键词可能原因字符串混淆开发者在打包时对字符串常量进行了加密或混淆。在 Jadx 中看到的可能是a.a(“abc”)这样的函数调用其返回值才是真正的”bsk”。参数名动态拼接参数名可能是通过”b” “s” “k”这种方式拼接出来的。Native层生成bsk的生成逻辑在 so 库里Java 层只是调用。排查技巧尝试搜索可能的相关词如token,sign,key,param。在抓包工具中仔细查看请求除了bsk是否还有其他看似随机的参数如_sign,nonce它们可能才是真正的签名而bsk只是其中一部分。查看网络请求相关的代码例如 OkHttp 的 Interceptor 或 Retrofit 的 Converter这里经常是统一添加签名参数的地方。可以搜索Interceptor,addQueryParam,addHeader等。如果怀疑在 Native 层使用IDA Pro打开 APK 解压后的.so文件搜索十六进制形式的字符串或导出函数名。6.2 问题二算法还原后生成的 token 仍然无效可能原因时间戳格式或精度不对服务端可能要求秒级时间戳或者需要是 UTC 时间或者时间戳是字符串格式。DeviceId 不匹配你模拟的Android ID与服务端记录的不符。有些应用会使用IMEI、OAID或自己生成的UUID作为设备标识。存在未发现的“盐”或密钥除了代码里的静态盐可能还结合了从服务端动态下发的密钥或者本地存储的密钥文件。算法不止 MD5可能是MD5之后又进行了Base64编码或者其实是HMAC-SHA256。参与计算的源数据不止这些可能还包含了请求的 URL 路径、请求体全部内容的哈希、或其他固定 Header。排查技巧对比法在同一秒内用抓包工具抓取两次请求可以重放请求。对比两个请求的bsk。如果它们不同说明有随机因子如 nonce参与。如果相同则说明算法是确定性的只与时间、设备等固定或半固定因子有关。Hook 验证使用Frida或Xposed框架Hook 住你怀疑的生成函数直接打印出它的输入参数和输出结果。这是最强大的动态验证手段。例如Hook 上文中的generateBSK函数打印出deviceId,timestamp和最终结果与你本地计算的结果对比。逆向调用链在 Jadx 中从generateBSK函数被调用的地方向上回溯查看在调用前程序是否还准备了其他数据并传入了该函数。6.3 问题三遇到 HTTPS 证书绑定SSL Pinning现象配置好代理后App 无法联网或抓包工具里看不到任何该 App 的 HTTPS 请求。原因App 在代码中内置了服务端证书或公钥只信任特定的证书而拒绝你安装的 Fiddler/Charles 的根证书从而阻止了中间人攻击也就是我们的抓包行为。解决方案使用已 Root 手机 特殊工具在已 Root 的手机上可以安装JustTrustMeXposed 模块或使用Frida脚本如frida-scripts中的ssl-pinning-bypass来绕过证书检查。使用虚拟环境在VirtualXposed、太极或平行空间这类免 Root 的虚拟环境中安装目标 App 和抓包工具的证书有时可以绕过。逆向修改 APK找到进行证书校验的代码通常使用OkHttp的CertificatePinner或TrustManager将其 Patch 掉然后重新打包签名安装。这需要一定的逆向修改能力。6.4 问题四参数是加密的看不到明文 bsk现象抓包看到的请求体是一串乱码或者是一个巨大的加密字符串无法直接看到bsk参数。原因可能使用了全局的请求体加密如 AESbsk被包裹在加密数据内部。解决方案首先需要找到加密/解密的入口。搜索encrypt,decrypt,AES,RSA,Cipher等关键词。找到加密函数后同样可以采用 Hook 的方法在数据加密之前打印出明文的请求体这样就能看到原始的bsk参数名和值。或者逆向整个加密流程在本地先构造明文数据包含bsk再按照同样的算法加密最后发送。这比只逆向bsk本身要复杂得多。7. 总结与安全思考通过这次从抓包到逆向再到本地还原BSK参数的完整流程我们实际上演练了一次小型的移动应用安全评估中“接口签名分析”的常见任务。整个过程的核心方法论可以概括为以网络流量为锚点以静态分析为地图以动态验证为罗盘最终在本地实现复现。对于开发者而言理解这种分析过程具有双重意义。从防御角度看它揭示了当前这种简单的“设备ID时间戳静态盐MD5”的签名方案是相对脆弱的。一旦静态盐被逆向签名算法就完全暴露。更安全的做法应该包括使用非对称加密或 HMAC并将密钥妥善保管如放在 so 库中或从服务端动态下发。增加随机数nonce防止重放。将更多请求元数据如 URL、部分请求头纳入签名计算增加伪造难度。定期更新签名算法或盐值。从学习角度看这是一个绝佳的入门项目。它串联了网络协议分析、移动端逆向、密码学应用和编程实现等多个技能点。每一个环节遇到问题、解决问题的过程都是经验的积累。我个人的体会是逆向工程就像侦探破案需要耐心、细致的观察和合理的逻辑推理。不要害怕复杂的代码学会利用工具如 Jadx 的搜索、引用分析来缩小侦查范围并大胆假设、小心验证。最后请务必记住技术是一把双刃剑。我们所学习和掌握的分析方法应该用于提升自身产品的安全性、进行授权的安全测试或是纯粹的技术研究与学习。尊重知识产权和法律法规在合法的边界内运用你的技能是每一位技术从业者应有的底线。