App逆向百例|12|某电商App Sign分析 原文标题:App逆向百例|12|某电商App Sign分析-阿里云开发者社区
内容概要总结
“App逆向百例”系列第 12 篇,分析某电商 App 的 Sign 生成全过程(实为京东 com.jingdong.app.mall)。先用 Frida 定位:直接运行卡死闪退,判定有 frida 检测(默认端口 27042),改用 hluwa 魔改 strongR-frida-android 换端口成功。Hook BitmapkitUtils.getSignFromJni 拿到入参与结果(st=...&sign=...&sv=122)。再用 Unidbg 黑盒调用补环境(Context、unZip、PKCS7 等)。算法定位到 sub_126AC 做 Base64、sub_18B8 与 sub_227C(Base64 再 MD5),用 HookZz 固定 lrand48 控制 sv。
原文内容(原文即中文)
2023-09-17
1731
发布于天津
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《
阿里云开发者社区用户服务协议》和
《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写
侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
简介:
App逆向百例|12|某电商App Sign分析
本文章仅供学习交流,切勿用于非法通途,如有侵犯贵司请及时联系删除

样本:aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMUNtbzZHU1lOUmM4a2l4YkVsT3Rkc1E/cHdkPWxpbm4=
0x1 抓包&定位



打开frida 启动样本App发现 App卡死闪退
可能有frida检测 那我们就使用葫芦娃大佬的魔改frida
github: https://github.com/hluwa/strongR-frida-android
经过多次试错后最后可知 样本App对frida的默认端口27042进行检测
/data/local/tmp/hluda-server-15.1.17-android-arm64 -l 127.0.0.1:8080
adb forward tcp:8080 tcp:8080
frida -H 127.0.0.1:8080
成功运行frida且不闪退后就可以对样本进行hook操作了
function hook_getSignFromJni() {
[Java](https://developer.aliyun.com/label/article_de-3-100001).perform(function () {
var Class = Java.use('com.xxxx.common.utils.BitmapkitUtils');
var Method = "getSignFromJni"
Class[Method].overload('android.content.Context', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function () {
var result = this[Method]['apply'](this, arguments);
console.log('----------------------');
console.log('arg1:' + arguments[0]);
console.log('arg2:' + arguments[1]);
console.log('arg2:' + arguments[2]);
console.log('arg2:' + arguments[3]);
console.log('arg2:' + arguments[4]);
console.log('arg2:' + arguments[5]);
console.log('result:' + result);
console.log('----------------------');
return result;
}
})
}
setImmediate(hook_getSignFromJni)

通过hook 拿到了多个结果 选取其中一个进行固定分析
arg1:com.jingdong.app.mall.JDApp@f0dac2f
arg2:hotWords
arg2:{"originHotWord":"0","pageFrom":"1"}
arg2:3036c83c3c4b25a2
arg2:android
arg2:10.2.0
result:st=1664463515894&sign=7ce2045026643e68ea1639c5e291127f&sv=122
0x2 Unidbg黑盒调用

vm.resolveClass("android/app/Activity");
取getpackagemanager所以需要在前面的基础上再完善一点环境

vm.resolveClass("android/app/Activity",vm.resolveClass("android/content/ContextWrapper", vm.resolveClass("android/content/Context"))).newObject(null);

取ApplicationInfo也就是apk的存放位置 可以在RE文件管理器/data/app中找到对应的位置
new StringObject(vm,"/data/app/com.xxxx.app.mall-cd4VeJ0b5yxrR0Zb-io_MA=/base.apk");
取unZip 看传入参数是什么


arg1->"/data/app/com.xxxx.app.mall-cd4VeJ0b5yxrR0Zb-io_MA=/base.apk"
arg2->"META-INF/"
arg3->".RSA"
根据参数打开APK中中的META-INF搜索RSA结尾的文件
根据这个文件名补即可

new ByteArray(vm,vm.unzip("META-INF/xxxx.RSA"));

vm.resolveClass("sun/security/pkcs/PKCS7").newObject(new PKCS7((byte[]) varArg.getObjectArg(0).getValue()));

PKCS7 pkcs7 = (PKCS7) dvmObject.getValue();
X509Certificate[] certificates = pkcs7.getCertificates();
return ProxyDvmObject.createObject(vm,certificates);
这里的objectToBytes是java层的一个方法 直接去复制粘贴就行

new ByteArray(vm,objectToBytes(varArg.getObjectArg(0).getValue()));
补到这里 恭喜你完成初始化了

public void getSignFromJni(){
ArrayList<Object> args = new ArrayList<>(10);
args.add(vm.getJNIEnv());
args.add(0);
args.add(vm.addLocalObject(vm.resolveClass("android/content/Context").newObject(null)));
args.add(vm.addLocalObject(new StringObject(vm,"hotWords")));
args.add(vm.addLocalObject(new StringObject(vm,"{\"originHotWord\":\"0\",\"pageFrom\":\"1\"}")));
args.add(vm.addLocalObject(new StringObject(vm,"3036c83c3c4b25a2")));
args.add(vm.addLocalObject(new StringObject(vm,"android")));
args.add(vm.addLocalObject(new StringObject(vm,"10.2.0")));
Number number = module.callFunction(emulator, 0x28b5, args.toArray());
System.out.println(vm.getObject(number.intValue()).getValue().toString());
}
然后接着报错接着补环境

vm.resolveClass("java/lang/StringBuffer").newObject(new StringBuffer());

StringBuffer stringBuffer = (StringBuffer) dvmObject.getValue();
return vm.resolveClass("java/lang/StringBuffer").newObject(stringBuffer.append(vaList.getObjectArg(0).getValue()));

Integer integer = new Integer(vaList.getIntArg(0));
return vm.resolveClass("java/lang/Integer").newObject(integer);

Integer integer = (Integer) dvmObject.getValue();
return vm.resolveClass("java/lang/Integer").newObject(integer.toString());

StringBuffer stringBuffer = (StringBuffer) dvmObject.getValue();
return new StringObject(vm,stringBuffer.toString());


0x3 算法分析





固定了时间 不同的sv算出来的sign结果也不一致



HookZz instance = HookZz.getInstance(emulator);
instance.wrap(module.findSymbolByName("lrand48"), new WrapCallback<HookZzArm32RegisterContext>() {
int count=0;
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
count+=1;
if(count==2){
ctx.setR0(0x1);
}
if(count==1){
ctx.setR0(0x1);
}
}
});


sub_126AC传回的结果放入了sub_18B8

看到这里似乎是一个Base64的码表

那sub_18B8可能就是一个Base64方法


sub_18B8的结果由v66传出并且传入sub_227C

看到似曾相识的东西 这样看可能不是很明显 手动分割一下
拿到sub_126AC的结果进行Base64再MD5



unk_17440 = [0, 1, 2]
sv1 = 1
sv2 = 1
sv3 = 1
print(unk_17440[(sv2 + sv3) % 3])
sv1
sv2
sv3
sv
case
1
0
0
100
0
1
0
1
101
1
1
0
2
102
2
1
1
0
110
1
1
1
1
111
2
1
1
2
112
0
1
2
0
120
2
1
2
1
121
0
1
2
2
122
1
往下看这里先是内存拷贝了一个值然后根据v12 * 40的值进行偏移 其实实现的就是一个数组取值的操作
这里根据伪代码可以翻译为

v11 = ['44e715a6e322ccb7d028f7a42fa55040', '7d0069660c9b5d32074facf37c3738a1', '80306f4370b39fd5630ad0529f77adb6']
v13 = v11[v12]

a2->80306f4370b39fd5630ad0529f77adb6
a3->0x1
a4->functionId=hotWords&body={"originHotWord":"0","pageFrom":"1"}&uuid=3036c83c3c4b25a2&client=android&clientVersion=10.2.0&st=1664689004670&sv=111
a5->0x8f
所以这个if是必定成立的 else后面的那一块可以忽略不看

这一段主要在计算v21

这里的a3对应的是sv1 而sv1固定为1 所以同理 不用理else部分


v16 = &v21[7] + (v15 & 0xF);
v18 =*(v16 - 20);
从汇编中可知R0=(SP+0x20-0x14)+(R3&0xf)



v17 = v15++ & 7;
result = ((v18 ^ *a4 ^ *(a2 + v17)) + v18);
LOBYTE(v18) = v18 ^ result;
*a4++ = v18;
*(a4 - 1) = v18 ^ *(a2 + v17);
将异或后的结果取低位然后再与a2[v17]进行运算最后算出结果
v15 = 0
v21 = [0x37, 0x92, 0x44, 0x68, 0xA5, 0x3D, 0xCC, 0x7F, 0xBB, 0x0F, 0xD9, 0x88, 0xEE, 0x9A, 0xE9, 0x5A]
while v15 != a5:
v18 = v21[v15 % 16]
v17 = v15 & 7
result = (v18 ^ a4[v15] ^ a2[v17]) + v18
v18 = v18 ^ result % 256
a4[v15] = v18 ^ a2[v17]
v15 += 1

接下来将前面固定lrand48的返回值改为0x2 使得sv为122
进入sub_10E18 和前面一样进来就是三个方法

但是不同的是出现了一个nullsub_1 那就分析不了吗?
并不然 从前面的分析结合这里可知 sub_125F0可能为初始化 sub_12510可能为计算核心方法 那nullsub_1就可能是释放 所以并不需要理睬nullsub_1
入参和前面基本一致 a2变为7d0069660c9b5d32074facf37c3738a1
这里循环每次取8个字节进入sub_10EA4计算 一共循环a5 >> 3次

进入sub_10EA4 955行代码 有点多 不过大部分都能直接复制

这里一堆与操作的目的就是将传入的8位分别和0x80 0x40 0x20 0x10 8 4 2 1与操作扩展至64位




Python本身是没有的 但是可以依靠一个库goto-statement来实现
pip install goto-statement
https://www.w3cschool.cn/article/3069641.html
这里就是将前面计算好并且重新赋值后的64位循环4次计算 每次取16位


实现了goto 其他操作只需要复制粘贴复制粘贴并稍微改改就能实现 反正全靠肝

回到上层 这里一共循环0x8f >> 3 = 17 但是似乎还有部分明文并没有参与计算 而最后得出的结果显示 全部都参与了计算


确实 只循环了17次 后面还会有&sv=122没有参与计算 但是从最终结果来看 确实是计算到了 那是哪里计算了呢?
emulator.traceWrite(0x4021c080L,0x4021c080L+10L);


这里就是赋值位置 但是 这里居然有3509行 这谁顶得住


这。。这段不就是根据未参与计算的明文的长度走不同的方法 而且每个方法都有上千行 留给有肝的人还原吧

接下来将前面固定lrand48的返回值改为0x0 使得sv为100

进入sub_12580 看到核心方法是一样的sub_10EA4 不过16变成了32

到此整一个流程就基本走完了 最后再拼接成st=xxx&sign=xxx&sv=xxx即可
感谢各位大佬观看感谢大佬们的文章分享 如有错误 还请海涵共同进步 带带弟弟

1688 item_search_app 关键字搜索商品接口深度分析及 Python 实现
1688开放平台item_search_app接口专为移动端优化,支持关键词搜索、多维度筛选与排序,可获取商品详情及供应商信息,适用于货源采集、价格监控与竞品分析,助力采购决策。
京东 item_get_app 接口深度分析及 Python 实现
京东item_get_app接口可获取商品原始详情数据,包含更丰富的字段和细节,适用于电商分析、价格追踪等场景。需通过认证获取权限,支持字段筛选和区域化数据查询。
淘宝 item_get_app 接口深度分析及 Python 实现
淘宝item_get_app接口是淘宝开放平台提供的移动端商品详情数据获取接口,相较PC端更贴近APP展示效果,支持获取APP专属价格、促销活动及详情页结构,适用于电商导购、比价工具、数据分析等场景。接口采用appkey+appsecret+session认证机制,需申请相应权限。本文提供Python调用示例及使用注意事项,帮助开发者高效对接移动端商品数据。
apptrace 三大策略,助力电商 App 在 618 突围
随着“618”电商大促预售开启,各大平台投入百亿流量与现金争夺用户。然而,网络购物市场增量空间趋于饱和,电商App亟需突破曝光、拉新与转化瓶颈。apptrace提供三大增长策略:精准曝光通过智能广告监测优化投放;裂变拉新简化流程,助力社交传播;高效转化实现一键直达活动页面,提升用户体验与留存率。这些技术优势助力开发者和运营者在618大战中抢占先机,实现用户增长与商业价值最大化。
TypeOrmModule 从 app.module.ts 抽离到 database.module.ts 后出现错误的原因分析
本文分析了TypeORM实体元数据错误的成因,主要涉及实体注册方式、路径解析差异及模块结构变化导致的关系解析问题,并提供了具体解决方案和最佳实践建议。
1688 item_get_app 接口深度分析及 Python 实现
1688平台item_get_app接口专为移动端设计,提供商品原始详情数据,包含批发价格、起订量、供应商信息等B2B特有字段,适用于采购决策、供应链分析等场景。接口需通过appkey+access_token认证,并支持字段筛选,返回结构化数据,助力企业实现智能采购与供应商评估。
驱动业务决策:基于Python的App用户行为分析与可视化方案
驱动业务决策:基于Python的App用户行为分析与可视化方案
基于Python的App流量大数据分析与可视化方案
通过友盟+ 数据分析工具,团队深入分析了用户行为路径、转化漏斗、停留时间及错误事件等关键数据,定位到用户体验与产品性能的问题。经过精准优化,包括简化购物流程、修复技术故障及提升稳定性,最终显著提高了用户转化率。这一案例展示了数据驱动在产品优化中的重要作用。

通过友盟+数据分析工具的综合数据分析和个性化推送功能,解决APP用户活跃度迅速下降的问题。
热门文章
最新文章
通过阿里云APP,可以进行ECS,RDS 等实例的管理
JAVA智慧工厂制造生产管理MES系统,全套源码,多端展示(app、小程序、H5、台后管理端)
【安卓app开发】kotlin Jetpack Compose框架 | 先用OKhttp下载远程音频文件再使用ExoPlayer播放
【Android App】物联网实战项目之自动驾驶的智能小车(附源码和演示 超详细)
【Android App】物联网中查看手机支持的传感器及实现摇一摇功能-加速度传感器(附源码和演示 超详细)
尝试HTML + JavaScript 编写Windows App
基于安卓Android微信小程序的校园报修管理APP
Android 音乐APP(四)显示专辑图片、本地数据库、自定义通知栏样式、通知栏显示
【App Service】部署War包到Azure云上遇404错误
如何在1v1视频直播交友APP中实现防录屏防截屏功能?
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
Qoder + ADB Supabase :5分钟GET超火AI手办生图APP
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
UniApp开发的App在启动速度方面有哪些优势和劣势?
相关解决方案
相关课程
相关电子书
大模型
一站式为企业和开发者提供大模型能力体系,大模型原生应用以及最佳解决方案,助力云上开发者轻松完成 AI 落地。
千问AI平台
千问官方 MaaS 平台,为开发者和 Agent 而生,新用户赠送 1 亿 + tokens 额度
AI 体验馆
大模型
文本生成
Qwen3.8-MaxHOT
0902 快照版本重磅更新,智能体时代全能旗舰模型
Qwen3.8-FlashNEW
Qwen3-VL-Plus
视觉 Coding、空间感知、多模态思考等全面升级
Kimi-K3
Deepseek-v4-pro
GLM-5.2
图片和视频生成
Wan3.0-Video
Qwen-Image-3.0-ProNEW
细节真实,知识厚实,让图像生成真正成为可落地的生产力工具
HappyHorse-1.1-T2V
语音识别与合成
Qwen3-TTS-Flash
离线语音合成大模型,多语言方言自适应,低延迟高稳定
Cosyvoice-V3-Flash
Fun-ASR
大模型服务
千问AI平台-Token PlanNEW
个人版上线、团队版降价;千问3.8-Max首发发尝鲜
千问AI平台-模型体验
Happy 系列大模型
新一代 AI 视频生成模型,深度适配广告营销等场景
AI 应用构建
大模型服务平台百炼-应用模版
大模型服务平台百炼-智能体
人工智能平台 PAI
AI Native 的算法工程平台,一站式完成建模、训练、推理服务部署
大模型原生应用
QoderHOT
万镜一刻
伶鹊
千问办公NEW
万有无界
企业级人与Agent协作平台,接入和调度多个数字员工
秒悟
大模型解决方案
快速部署 Dify,高效搭建 AI 应用
10 分钟在聊天系统中增加一个 AI 助手
10分钟微调:让0.6B模型媲美235B模型
即刻拥有 DeepSeek-R1 满血版
多模态数据信息提取
超强辅助,Bolt.diy 一步搞定创意建站
与 AI 智能体进行实时音视频通话
构建大模型应用的安全防护体系
产品
人工智能与机器学习计算容器存储网络与CDN安全中间件数据库大数据计算企业服务与云通信开发工具迁移与运维管理专有云
精选产品
大模型服务平台百炼大模型
轻量应用服务器
云数据库 RDS
全托管,含MySQL、PostgreSQL、SQL Server、MariaDB多引擎
人工智能平台 PAI大模型
云原生大数据计算服务 MaxCompute
GPU 云服务器
云防火墙
域名与网站
千问大模型大模型
数字证书管理服务(原SSL证书)
短信服务
国内短信简单易用,安全可靠,秒级触达,全球覆盖200+国家和地区。
云解析DNS
覆盖公网/内网、递归/权威、移动APP等全场景解析服务
容器服务 Kubernetes 版 ACK
云服务器 ECS
对象存储 OSS
无影云电脑
Qoder
云原生数据库 PolarDB
100%兼容MySQL、PostgreSQL,兼容Oracle,支持集中和分布式
大数据开发治理平台 DataWorks
Data Agent 驱动的一站式 Data+AI 开发治理平台
产品动态
解决方案
精选解决方案
睿译宝,AI图片文字翻译与高保真排版NEW
一句话生成原生可编辑精美 PPT 文稿
一键部署幻兽帕鲁游戏服务器
漫剧工坊:一站式动画创作平台
千问办公,解锁你的工作新方式
DeepSeek Harness:构建插件化智能体NEW
快速部署 DeepSeek Harness 开源智能体
HappyHorse 打造一站式影视创作平台
快速拥有专属 OpenClaw
MiniMax-H3:一键部署,即刻创作HOT
通过计算巢快速部署 MiniMax H3 全模态视频创作环境。
即刻拥有 DeepSeek-V4-Pro
Hermes Agent,打造自进化智能体
低代码高效构建企业门户网站
Qwen Audio:打造专属 AI 语音助手
Qwen-Audio-3.0-Realtime 端到端实时语音角色扮演
睿译宝,AI翻译排版一步到位
5 分钟轻松部署专属 QwenPawHOT
10 分钟搭建微信、支付宝小程序
权益
上云优选,普惠好价,为开发者和企业提供多款超值优选上云必备产品;超 140 款免费试用产品;初创企业最高可得 100 万抵扣金。
普惠上云
普惠上云 官方力荐
官方推荐返现计划
云工开物
免费试用
解决方案免费试用 新老同享
AI 产品 免费试用
140+云产品 免费试用
大模型ACA认证体验
AI 特惠
智启 AI 普惠权益
Token Plan 39元起,节省计划低至 4.5 折
阿里云 OPC 创新助力计划
Token Plan 模型订阅计划NEW
“模型 + Agent 工具”一次配齐 AI 生产力,加量不加价
万小智 AI 建站低至 15元/月
Night Plan:3.8-Max/Flash 限时4折NEW
22:00 后开跑,Qoder / Meoo 客户直接生效
万镜一刻,视频创作低至39元/月
AI 场景体验
AI 电商营销
AI Coding
AI 广告创作
AI 建站
AI 办公
AI 短剧/漫剧
智能客服
自动承接线索、识别商机,让客服更高效、服务更出色。
企业知识库
AI 活动
AI 生产力先锋
飞天发布时刻
AI 实训营
创新加速
上云场景组合购
云聚AI 严选权益
AI 用量加速计划
定价
提供灵活的计费方式和清晰的计费规则,满足不同的业务场景需求;支持自助估算价格、高效采购;专业的成本管理工具,持续优化云上成本。
产品定价
云上成本管理
价格计算器
价格优势
配置报价器
阿里云 OPC 创新助力计划
至高可申请百万元 Token 补贴,五大权益加速 OPC 成功
AI 应用市场
汇聚大模型、AI应用与行业解决方案等优质伙伴产品和服务,助力企业加速智能化转型与业务创新。
精选AI频道
企业经营管理
数据产品
物联网与智能硬件
研发与运维工具
基础软件
安全与合规
专业服务
专区
伙伴
坚持伙伴优先,为伙伴提供产品、销售和服务的商业合作模式;与伙伴紧密合作,共同为客户提供更完备的产品、更完善的服务。
成为销售伙伴
销售伙伴合作计划
成为产品伙伴
产品伙伴合作计划
成为服务伙伴
服务伙伴合作计划
更多支持
服务
提供多样化的支持计划和专家服务,满足上云咨询、迁移上云、云上运维等场景的全链路服务需求。
售前咨询
售后服务
企业增值服务
企业成长
阿里云认证
信息公告
开发者社区
我要反馈
了解阿里云
作为全球领先的全栈人工智能服务商,阿里云坚持让计算成为公共服务,助力全球客户加速价值创新。