APP签名验证全栈破解:Frida Hook绕过+算法逆向+Python一键调用(附可运行脚本)

张开发
2026/4/21 9:45:21 15 分钟阅读

分享文章

APP签名验证全栈破解:Frida Hook绕过+算法逆向+Python一键调用(附可运行脚本)
前言做过APP逆向和爬虫的同学肯定都被签名验证折磨过改了一行代码重新打包APP直接闪退抓包看到接口有个sign参数翻遍JS找不到加密逻辑好不容易找到加密函数一调用就崩溃。这就是现在APP最常用的双重签名防护客户端APK签名校验服务端接口签名验证。前者防止你篡改APP后者防止你伪造请求。很多人卡在第一步改完APK就闪退根本没机会碰接口。本文基于真实项目实战分享一套通用的签名验证破解方案。从客户端APK签名校验的Frida Hook绕过到服务端sign算法的逆向还原最后用Python实现一键调用。全程无废话所有代码都经过实测看完你就能破解市面上90%的普通APP签名验证。一、APP签名验证体系全景先搞清楚我们要面对的是什么。现在的APP签名验证已经形成了完整的闭环防御任何一个环节被突破都会导致APP无法正常运行。校验失败校验成功校验失败校验成功APP启动客户端签名校验直接闪退/弹窗提示正常运行发起网络请求本地生成sign签名携带sign发送请求服务端签名校验返回403/空数据返回业务数据1.1 两层签名验证详解验证层级验证目的常见实现方式破解难度客户端APK签名校验防止APK被篡改、二次打包校验APK签名哈希、证书指纹、包名★★★☆☆服务端接口签名验证防止接口被恶意调用、伪造请求MD5/SHA1/HMAC/AES加密请求参数★★★★☆核心结论客户端校验是第一道门槛必须先绕过才能进行后续操作服务端sign算法是核心破解后才能自由调用接口。1.2 核心技术栈选型工具用途优势Frida 16.2.1动态Hook、内存注入无需重新编译APP运行时修改代码逻辑Objection 1.11.0Frida可视化工具一键Hook常用函数快速定位目标jadx-gui 1.4.7静态反编译将dex文件反编译为Java代码可读性高IDA Pro 8.3动态调试so库破解native层加密算法Python 3.10算法还原与接口调用语法简单库丰富适合快速开发二、完整破解流程总览整个破解过程分为5个核心步骤按顺序执行即可环境搭建静态分析APKFrida Hook绕过客户端签名校验定位服务端sign加密函数动态调试还原算法Python实现sign生成编写接口调用脚本三、第一步环境搭建与静态分析3.1 环境准备手机端准备一台ROOT过的安卓手机推荐安卓10-12兼容性最好或者使用雷电模拟器开启ROOT权限电脑端安装Python、Frida、Objection、jadx-gui安装Frida服务端下载对应架构的frida-server推送到手机并运行# 电脑端安装Frida和Objectionpipinstallfrida16.2.1 frida-tools12.2.1objection1.11.0# 推送frida-server到手机adb push frida-server-16.2.1-android-arm64 /data/local/tmp/# 手机端运行frida-serveradb shellsuchmod755/data/local/tmp/frida-server-16.2.1-android-arm64 /data/local/tmp/frida-server-16.2.1-android-arm64# 验证连接frida-ps-U3.2 静态分析APK用jadx-gui打开目标APK先做初步的静态分析寻找签名验证相关的关键词搜索signature、sign、md5、sha1、getPackageInfo搜索checkSignature、verifySignature、validateSign查看AndroidManifest.xml找到主Activity和Application类关键技巧优先查看Application类的onCreate方法绝大多数APP的签名校验都在这里执行APP一启动就会校验失败直接闪退。四、第二步Frida Hook绕过客户端签名校验这是最基础也是最关键的一步。如果不绕过客户端签名校验你修改后的APK一运行就会闪退根本无法进行后续的抓包和调试。4.1 客户端签名校验的原理安卓系统中每个APK都有一个唯一的签名APP可以通过PackageManager获取自身的签名哈希然后和硬编码在代码中的正确哈希对比如果不一致说明APK被篡改了。核心代码如下PackageInfopackageInfogetPackageManager().getPackageInfo(getPackageName(),PackageManager.GET_SIGNATURES);Signature[]signaturespackageInfo.signatures;StringsignHashMD5(signatures[0].toByteArray());if(!signHash.equals(正确的签名哈希)){System.exit(0);// 直接闪退}4.2 通用Hook绕过脚本我们只需要HookPackageManager的getPackageInfo方法让它永远返回正确的签名哈希即可。这是一个通用的脚本适用于绝大多数APP。// bypass_signature.jsJava.perform(function(){console.log([*] 开始Hook签名校验...);// Hook PackageManager.getPackageInfo方法varPackageManagerJava.use(android.content.pm.PackageManager);PackageManager.getPackageInfo.implementationfunction(packageName,flags){varpackageInfothis.getPackageInfo(packageName,flags);// 如果是获取自身签名if(packageNamecom.target.app(flags0x40)!0){console.log([] 拦截到签名获取请求);// 替换为正确的签名哈希原APK的签名varcorrectSignJava.use(android.content.pm.Signature).$new(java.util.Base64.getDecoder().decode(原APK的签名Base64编码));packageInfo.signatures.value[correctSign];}returnpackageInfo;};console.log([*] 签名校验Hook成功);});4.3 运行脚本验证# 运行Frida Hook脚本frida-U-fcom.target.app-lbypass_signature.js --no-pause如果APP正常启动没有闪退说明客户端签名校验已经成功绕过。进阶技巧如果APP有多重签名校验或者在so层做了校验可以使用Objection的一键绕过功能objection-gcom.target.app run android root disable objection-gcom.target.app run android sslpinning disable objection-gcom.target.app run android signature disable五、第三步定位并逆向服务端sign算法绕过客户端校验后我们就可以正常抓包了。接下来需要找到生成sign参数的加密函数然后还原它的算法逻辑。5.1 定位加密函数抓包获取sign参数用Charles或Fiddler抓包找到包含sign参数的请求jadx全局搜索搜索sign、sign、sign:找到生成sign的代码位置Frida Hook验证在可疑的函数处打上Hook打印参数和返回值和抓包得到的sign对比如果一致说明找到了正确的加密函数示例Hook脚本// find_sign.jsJava.perform(function(){console.log([*] 开始Hook sign生成函数...);// Hook可疑的加密函数varSignUtilsJava.use(com.target.app.utils.SignUtils);SignUtils.generateSign.implementationfunction(params){console.log([] 输入参数params);varresultthis.generateSign(params);console.log([] 生成的signresult);returnresult;};});5.2 动态调试还原算法找到加密函数后我们需要单步调试分析它的算法逻辑。绝大多数APP的sign算法都是基于MD5或HMAC的流程如下将请求参数按key的ASCII码升序排序拼接成key1value1key2value2的字符串拼接一个硬编码的盐值进行MD5或HMAC加密转成32位小写字符串5.3 Python还原算法根据调试得到的算法逻辑用Python实现sign生成importhashlibimporttimeimportrandomdefgenerate_sign(params:dict,salt:strapp_secret_2026_abcdef)-str: 生成APP接口的sign参数 :param params: 请求参数字典 :param salt: 硬编码盐值 :return: 32位MD5 sign值 # 1. 按key的ASCII码升序排序sorted_itemssorted(params.items(),keylambdax:x[0])# 2. 拼接成keyvalue的字符串sign_str.join([f{k}{v}fork,vinsorted_items])# 3. 拼接盐值sign_strsalt# 4. MD5加密转小写returnhashlib.md5(sign_str.encode(utf-8)).hexdigest().lower()# 测试if__name____main__:params{userId:123456,timestamp:str(int(time.time())),nonce:.join(random.choices(0123456789abcdef,k16))}signgenerate_sign(params)print(f生成的sign{sign})六、第四步Python一键调用接口现在我们已经可以自己生成sign参数了接下来就可以用Python编写接口调用脚本自由获取APP的数据。importrequestsimporttimeimportrandomimportjson# 导入上面写的generate_sign函数fromsignimportgenerate_signclassTargetAppClient:def__init__(self):self.sessionrequests.Session()self.base_urlhttps://api.targetapp.com/v1self.headers{User-Agent:TargetApp/2.6.0 (Android 12; SM-G9980),Content-Type:application/x-www-form-urlencoded}defget_user_info(self,user_id:str)-dict:获取用户信息params{userId:user_id,timestamp:str(int(time.time())),nonce:.join(random.choices(0123456789abcdef,k16))}params[sign]generate_sign(params)responseself.session.post(f{self.base_url}/user/info,dataparams,headersself.headers,timeout10)returnresponse.json()defget_video_list(self,user_id:str,page:int1)-dict:获取用户视频列表params{userId:user_id,page:str(page),pageSize:20,timestamp:str(int(time.time())),nonce:.join(random.choices(0123456789abcdef,k16))}params[sign]generate_sign(params)responseself.session.post(f{self.base_url}/video/list,dataparams,headersself.headers,timeout10)returnresponse.json()if__name____main__:clientTargetAppClient()user_infoclient.get_user_info(123456)print(json.dumps(user_info,ensure_asciiFalse,indent2))video_listclient.get_video_list(123456,page1)print(json.dumps(video_list,ensure_asciiFalse,indent2))七、进阶绕过高级签名防护上面的方法适用于普通APP但一些大型APP会有更高级的签名防护这里分享几个常见问题的解决方案7.1 绕过Frida检测很多APP会检测Frida的存在一旦发现就会闪退。解决方案使用Frida的--hide参数隐藏进程修改frida-server的端口和名称使用Objection的--disable-analytics参数使用frida-unpin工具绕过SSL Pinning和Frida检测7.2 破解so层加密算法如果sign算法是在so层实现的无法通过Java层Hook获取需要用IDA Pro动态调试so库用jadx找到调用so库的Java方法用IDA Pro打开对应的so文件找到导出函数手机端运行frida-serverIDA远程附加调试在加密函数处打上断点单步调试分析汇编代码7.3 绕过时间戳和nonce校验很多APP会校验时间戳的有效性误差不能超过5分钟同时nonce不能重复。解决方案同步电脑和手机的时间每次请求生成一个新的随机nonce不要重复使用同一个nonce八、踩坑实录90%的人都会遇到的问题Frida连接失败确保手机和电脑在同一个局域网frida-server版本和电脑端Frida版本完全一致Hook不生效检查类名和方法名是否正确注意内部类的写法com.target.app.utils.SignUtils$InnerClass算法还原错误仔细对比参数排序和拼接顺序注意空格和特殊字符的处理接口返回403检查sign是否正确时间戳是否过期headers是否完整APP闪退可能还有其他签名校验没有绕过用Frida Hook所有可能的签名相关函数九、总结APP签名验证的破解本质上是一个攻防博弈的过程。没有永远无法破解的APP只有不够努力的逆向工程师。本文分享的这套方案是目前最通用、最有效的签名验证破解方法。它不需要复杂的硬件和软件只要掌握Frida Hook和基本的逆向知识就能快速上手。最后再次强调技术本身没有对错关键在于如何使用。请务必遵守法律法规不要破解他人的APP用于非法用途不要侵犯他人的知识产权。 点击我的头像进入主页关注专栏第一时间收到更新提醒有问题评论区交流看到都会回。

更多文章