开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 4644|回复: 20
收起左侧

[Android逆向] 小破站so层sing算法

[复制链接]
回帖奖励 15 枚 精币 回复本帖可获得 1 枚 精币奖励! 每人限 1 次
发表于 2024-5-30 13:17:08 | 显示全部楼层 |阅读模式   湖北省武汉市
申明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

抓包

1.抓包没什么说的,往上滑或往下滑都能刷新抓到包


2.翻页后文本对比下发现只有两个时间戳是不同的然后加密得到不同的sign,其他参数可以暂时固定

定位sing的位置
3.首先把apk拖到jadx反编译一下,这个时候大部分都会去搜字符串,但是由于很多地方都使用了sign关键字,直接搜的话太麻烦了,所以也可以搜查询参数中比较特殊的字符串,比如ad_extra,banner_hash,statistics,他们最终肯定会参与params的组装,然后可以顺着找到sign  我这里采用的是hook hashmap的put方法,这样比搜索快一些,代码如下


[JavaScript] 纯文本查看 复制代码
 Java.perform(function (){
        function showStacks() {
        console.log(
            Java.use("android.util.Log")
                .getStackTraceString(
                    Java.use("java.lang.Throwable").$new()
                )
        );
    }
 
var hashMap = Java.use("java.util.HashMap");
    hashMap.put.implementation = function (a, b) {
        if(a.equals("ad_extra")){
            showStacks();
            console.log("hashMap.put: ", a, b);
        }
        return this.put(a, b);
    }
    }
    )


4.只有一处,顺着堆栈找可以找到com.bilibili.okretro.f.a.d

5.如下图

6.点击h这个方法里

7.再点进g这个方法 ,g加载s这个native方法

8.s来源于libbili.so这个文件

9.找到对应的so文件,只有32位的arm架构,下面那个是模拟器的,所以选择第一个里面的libbili.so

用32位的ida把它转为汇编

10.在导出表里面没有发现java的字眼,所以是动态注册,同时可以看到标志JNI_OnLoad,代表动态注册


11.点进去JNI_OnLoad 发现里面嵌套了很多函数,找到RegisterNatives动态注册很麻烦,这里可以用hook脚本,输出当前类下的所有native方法对应c中方法的偏移量,然后再找到c中的函数代码


[Python] 纯文本查看 复制代码
// 获取 RegisterNatives 函数的内存地址,并赋值给addrRegisterNatives。
var addrRegisterNatives = null;
 
// 列举 libart.so 中的所有导出函数(成员列表)
var symbols = Module.enumerateSymbolsSync("libart.so");
 
 
for (var i = 0; i < symbols.length; i++) {
    var symbol = symbols;
    console.log(symbol.name)
    //_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
    if (symbol.name.indexOf("art") >= 0 &&
        symbol.name.indexOf("JNI") >= 0 &&
        symbol.name.indexOf("RegisterNatives") >= 0 &&
        symbol.name.indexOf("CheckJNI") < 0) {
 
        addrRegisterNatives = symbol.address;
        console.log("RegisterNatives is at ", symbol.address, symbol.name);
        //break
    }
}
 
 
if (addrRegisterNatives) {
    // RegisterNatives(env, 类型, Java和C的对应关系,个数)
    Interceptor.attach(addrRegisterNatives, {
        onEnter: function (args) {
            var env = args[0];        // jni对象
            var java_class = args[1]; // 类
            var class_name = Java.vm.tryGetEnv().getClassName(java_class);
            var taget_class = "com.bilibili.nativelibrary.LibBili";
            if (class_name === taget_class) {
                //只找我们自己想要类中的动态注册关系
                console.log("\n[RegisterNatives] method_count:", args[3]);
                var methods_ptr = ptr(args[2]);
                var method_count = parseInt(args[3]);
                for (var i = 0; i < method_count; i++) {
                    // Java中函数名字的
                    var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                    // 参数和返回值类型
                    var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                    // C中的函数内存地址
                    var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
                    var name = Memory.readCString(name_ptr);
                    var sig = Memory.readCString(sig_ptr);
                    var find_module = Process.findModuleByAddress(fnPtr_ptr);
                    // 地址、偏移量、基地址
                    var offset = ptr(fnPtr_ptr).sub(find_module.base);
                    //console.log("name:", name, "name:", sig, "module_name:", find_module.name, "offset:", offset);
                    console.log("name:", name, "name:", sig, "offset:", offset);
 
                }
 
            }
        }
    });
}


12.这里因为app一开始加载的时候已经加载了所有的so文件,所以需要以重新启动app的方式来hook,而不能通过附加形式 hook,如下图
frida -U -f tv.danmaku.bili -l hook_code.js
13.这里在ida里按G就能弹出运行框,输入偏移量就可以调到指定函数位置14.转化JNIEnv对象后如下图

15.往下滑看返回值 这里其实是进行了一堆md5加密,参数1是url路径后面的参数(除了sign),参数2就是加密的sign

16.通过java层hook s方法即可看出

[JavaScript] 纯文本查看 复制代码
 Java.perform(function (){
     let LibBili = Java.use("com.bilibili.nativelibrary.LibBili");
LibBili["s"].implementation = function (sortedMap) {
    console.log(`LibBili.s is called: sortedMap=${sortedMap}`);
    var map = Java.use("java.util.TreeMap")
    var dict = Java.cast(sortedMap,map)
    console.log('传入的对象====>',dict)
    let result = this["s"](sortedMap);
    console.log(`LibBili.s result=${result}`);
    return result;
};
    }
    )

算法

17.最终sign python算法,z最终生成的与params中的一样,验证算法是正确的

[Python] 纯文本查看 复制代码
import hashlib
from urllib.parse import quote, unquote
params = {
    "ad_extra": "E86F4CFF1F8FA890A75155EEAA51E6AE4FA9DBE62FCE708186D0CE5EF37B86948620D8BA1D991685B1288E2EDE09C6D52F8C2D33D59872EAE1EB776D11F71523CE1AF2112D8A950B98F6A1A48F848BC6871A849C3ED14308F46431A85625726A929A8906FA0C16FEE2CEB33209AE6F1E0C6856961045F53A0FE3470E4E223F48DAE7923040EAC4541BE6F728DEA350329AC40887CB773083BB4D6D91DCCCDF8D16C5672A5E344293F5EFD2F3654B88602781A8869076E96FF8359FC76D3CD5851A733D0CF38E11DC869D660D1624928815C2A13497B215CCEA52053B302039B9B93DFABDD6A71A16AC8898285A37C7DEB5AB5ADD788C2456B5D9B2F8FDB1ACD334E8127D56B144B523155DE8AB49A1D1173CB590E379CCF33EFAE8C388100D5CEA7AD220E2AAA2256FF16D4BE28C8AA3D7BAE19B1FE6AA860276BB86B27ACCA34B8E081D67E8C699CF4ED4D7A45E8556B05584B35B1E11E80B9B41DC51C47B260C602E07B1936C73DDB8D7FFBBD148894822C5F7C9A688C5A25DB2CA92D77CA7C35E3AFD807D0AE95967943A42B30D0F0EF8EAD9D2E74A20BB4EA72014B5A3BFD53B2ECFB15B47455D97A4FBFDDFB4A3E30853E0B9CBF16AC70F25CB6B939540328256BF42AB6DF9D3DD4649E3F0B340376B162F859D5EE92D99A778FB313E28BCAD195FB59A30EC374436735A9732BF013A78FE3F606425B48A74137C267DAB91A00962C5FFECB7E798AC130FCF7F9428A05082C6D717D13F129F809818E05DB11EA3DE2EA80728D30DB7EECAE1231085C4E3B47B98506F261D89D15997AC09FB46DBA3444A438F43A59D232385F3C5548DFF3F51733A80A80880E7945035A18DCDDCDEB85A2DCCF755CD1AEBCA759CB2BE4AF6D5AB3A9FA8F7429DD37B740E33D80E1F11B8BD4DD312DEAECEEBAB7DC6FF57EFC5A81D3D7D02E798AA5CDCD387EAD885EE8D89368FA301463658FA52",
    "appkey": "1d8b6e7d45233436",
    "autoplay_card": "11",
    "autoplay_timestamp": "0",
    "build": "7500300",
    "c_locale": "zh-Hans_CN",
    "channel": "alifenfa",
    "column": "2",
    "column_timestamp": "0",
    "device_name": "Pixel 4",
    "device_type": "0",
    "disable_rcmd": "0",
    "flush": "8",
    "fnval": "464",
    "fnver": "0",
    "force_host": "0",
    "fourk": "1",
    "guidance": "0",
    "https_url_req": "0",
    "idx": "1698066410",
    "inline_danmu": "2",
    "inline_sound": "1",
    "interest_id": "0",
    "login_event": "0",
    "mobi_app": "android",
    "network": "wifi",
    "open_event": "",
    "platform": "android",
    "player_net": "1",
    "pull": "false",
    "qn": "32",
    "recsys_mode": "0",
    "s_locale": "zh-Hans_CN",
    "splash_id": "",
    "statistics": "{\"appId\":1,\"platform\":3,\"version\":\"7.50.0\",\"abtest\":\"\"}",
    "ts": "1698066416",
    "video_mode": "1",
    "voice_balance": "0",
    # "sign": "002c2395f37e8800095c41e08b652517"
}
sorted_params = sorted(params.items(), key=lambda x: x[0])
sorted_str = '&'.join([f'{k}={v}' for k, v in sorted_params])
 
original_string = sorted_str
# 分割字符串,然后仅对值进行编码
parts = original_string.split("&")
encoded_parts = []
for part in parts:
    key, value = part.split("=")
    encoded_value = quote(value)
    encoded_parts.append(f"{key}={encoded_value}")
# 重新组合编码后的部分
encoded_string = "&".join(encoded_parts)
 
# 盐值 560c52ccd288fed045859ed18bffd973
str = encoded_string+'560c52ccd288fed045859ed18bffd973'
sign = hashlib.md5(str.encode('utf-8')).hexdigest()
print(sign)



                                       出于安全考虑,本章未提供完整流程,调试环节省略较多,只提供大致思路,具体细节要你自己还原:







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

点评

这不是搬文章么?   湖南省株洲市  发表于 2024-5-30 14:47

签到天数: 12 天

 楼主| 发表于 2024-5-30 15:36:08 | 显示全部楼层   湖北省武汉市
不是原创,原作者:https://blog.csdn.net/xmx_000/article/details/134123902?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171705441616800186514755%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171705441616800186514755&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-3-134123902-null-null.142^v100^control&utm_term=so%E5%B1%82&spm=1018.2226.3001.4187
回复 支持 反对

使用道具 举报

结帖率:100% (1/1)

签到天数: 10 天

发表于 5 天前 | 显示全部楼层   陕西省西安市

回帖奖励 +1 枚 精币


还来的急么
回复 支持 反对

使用道具 举报

结帖率:100% (7/7)

签到天数: 21 天

发表于 2024-11-13 19:54:22 | 显示全部楼层   广东省佛山市

回帖奖励 +1 枚 精币

还来的急么
回复 支持 反对

使用道具 举报

结帖率:47% (9/19)

签到天数: 20 天

发表于 2024-11-10 20:17:41 | 显示全部楼层   广东省佛山市
666666666666666666666
回复 支持 反对

使用道具 举报

结帖率:47% (9/19)

签到天数: 20 天

发表于 2024-11-10 20:17:13 | 显示全部楼层   广东省佛山市
666666666666666666666666666
回复 支持 反对

使用道具 举报

结帖率:90% (9/10)

签到天数: 24 天

发表于 2024-11-9 00:15:31 | 显示全部楼层   重庆市重庆市

回帖奖励 +1 枚 精币

…………
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 9 天

发表于 2024-11-9 00:08:10 | 显示全部楼层   贵州省贵阳市

回帖奖励 +1 枚 精币

这不是搬文章么
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 1 天

发表于 2024-10-14 14:42:28 | 显示全部楼层   云南省昆明市

回帖奖励 +1 枚 精币

有简单的么
回复 支持 反对

使用道具 举报

签到天数: 6 天

发表于 2024-8-30 15:16:29 | 显示全部楼层   湖北省武汉市

回帖奖励 +1 枚 精币

感谢分享 无量功德
回复 支持 反对

使用道具 举报

签到天数: 3 天

发表于 2024-8-30 08:23:05 | 显示全部楼层   广东省湛江市

回帖奖励 +1 枚 精币

支持支持支持支持支持支持支持
回复 支持 反对

使用道具 举报

签到天数: 8 天

发表于 2024-8-13 08:42:41 | 显示全部楼层   河南省鹤壁市

回帖奖励 +1 枚 精币


66666666666666
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表