首页
社区
课程
招聘
[原创]shopee app算法分析第一篇
发表于: 2024-11-27 00:36 9645

[原创]shopee app算法分析第一篇

2024-11-27 00:36
9645

shopee app算法分析第一篇

分析完整算法大概要好几篇,耐心等待下

image-20241126220341011

抓的搜索接口,get请求,核心的有3个4字节键和x-sap-ri,如果是post,就是4个4字节键和值,多出来的一个和post的表单有关

image-20241126220612188

后续内容都是post的,post会了,get肯定也会了,4个4字节3个短的,一个长的.这5个参数来着同一个so,libshpssdk.so,后面说怎么定位到的.

4字节的key和value也是一直变化的,最好摸清楚生成机制,随机可能引起风控.(有9套算法)

太长了,放前面的结果

在com.shopee.shpssdk.SHPSSDK.uvwvvwvvw方法里,这个app有很多站点的,初步看了只是包名不一样,函数,so偏移都是一样的,包名是com.shopee.xx xx是域名后面的,我使用的样本是ph,3.37.31

image-20241126221616280

这个位置值已经生成了,往上找调用,就一个,结果来自wvvvuwwu.vuwuuwvw(str.getBytes(), bArr),hook发现,第一个参数url,第二个表单(get就是null)

image-20241126221714102

点过去来到native注册的地方

image-20241126221845356

hook下libart

so名字libshpssdk,偏移0x995dc,到lib目录下找发现一个so都没有,hook下dlopen

可以看到so是压缩了下,拖出来即可.

注意脚本写法(排除空,异常字段),很多时候排除掉手机,app,frida版本这些的问题, 为什么明明确定是这个位置hook脚本就是没输出,考虑下是不是脚本有问题,有时候有问题是不会输出东西的,也不报错,然后你以为没走这,就是因为你对参数进行了错误操作,比如类型没判断正确,空没有排除掉导致脚本什么都不打印.好几个人问我,这里统一回复下.

都是基本写法,不熟悉多google,自己琢磨才能记得住.

连续调用会有一个4字节key不变,1A9EC9B9,这个只和url有关,后续写还原,这个键对应的值解密出来是16字节随机+9套算法中的哪3套,第二篇写算法还原

native call的作用是方便确定哪些是so的初始化函数(不管有没有),可以节省后续很多时间.

在so刚加载后直接native call如果有正确结果就没有初始化,如果有需要一步步调用初始化直到生成正确结果,方便后续模拟执行

-f启动,很幸运没有初始化,国内大厂没有没有初始化的,这块占逆向比重也很大.

执行无异常

image-20241126225427782

然后调用函数. callByAPI放开

image-20241126225522242

上来就查找异常,上面验证了没有初始化,也就是说直接调用理论上是可以的.很明显上来就走到异常了. 要么放弃unidbg,用stalker,要么硬干,排除异常.

我选择试试排除异常,在刚调用函数的位置开启trace,运行

image-20241126230214931

刚开始异常的位置是0x980b8,ida中看看

image-20241126230610607

没有有用的信息

image-20241126230701341

往上找了找,看到了都是和异常相关的字段,判断应该是走入这个函数导致的异常,如果不让函数执行到这里是不是就可以绕过了?可以尝试一下,没有好的办法,不试你就只能扔到回收站.

异常函数是sub_9646C

image-20241126231121159

日志中看到由9a204跳到异常

image-20241126231217854

off_345F20里放的都是函数地址,有点罕见这种.

image-20241126231239173

复制出来搜索发现只有一处走向异常,之前尝试了不让他走到这个判断里面,有些困难

image-20241126231558702

最好的办法是把这个跳转直接nop掉

运行

image-20241126231916020

进入到正常逻辑了,后续的补环境交给你相信也是信手拈来.

补环境代码中可能有东西参与了计算,需要注意,另外大部分结果由随机数构成,需要处理好哪些随机是对应的.走的是/dev/urandom

x-sap-ri算法

image-20241126233036721

不要觉得看上去很简单,想一想没有资料你能不能搞的出来? 后续预计3-4篇算法

后续这种简单的定位,脚本什么可能一笔带过了,默认都会了,我觉得这篇还是很详细的,后续算法远比这些复杂

Java.perform(function (){
    //     HashMap.put
    var hashMap = Java.use("java.util.HashMap");
    hashMap.put.implementation = function (a, b) {
        if(a!=null && a.equals("x-sap-ri")){
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
            console.log("hashMap.put: ", a, b);
        }
        return this.put(a, b);
    }
})
Java.perform(function (){
    //     HashMap.put
    var hashMap = Java.use("java.util.HashMap");
    hashMap.put.implementation = function (a, b) {
        if(a!=null && a.equals("x-sap-ri")){
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
            console.log("hashMap.put: ", a, b);
        }
        return this.put(a, b);
    }
})
java.lang.Throwable
    at java.util.HashMap.put(Native Method)
    at org.json.JSONObject.put(JSONObject.java:276)
    at org.json.JSONTokener.readObject(JSONTokener.java:394)
    at org.json.JSONTokener.nextValue(JSONTokener.java:104)
    at org.json.JSONObject.<init>(JSONObject.java:168)
    at org.json.JSONObject.<init>(JSONObject.java:185)
    at com.shopee.shpssdk.SHPSSDK.uvwvvwvvw(Unknown Source:81)
    at com.shopee.shpssdk.SHPSSDK.requestDefense(Unknown Source:59)
 
hashMap.put:  x-sap-ri 443e41678c54f44f62b70d1901d115bc703ebab92a5b4251176d
java.lang.Throwable
    at java.util.HashMap.put(Native Method)
    at org.json.JSONObject.put(JSONObject.java:276)
    at org.json.JSONTokener.readObject(JSONTokener.java:394)
    at org.json.JSONTokener.nextValue(JSONTokener.java:104)
    at org.json.JSONObject.<init>(JSONObject.java:168)
    at org.json.JSONObject.<init>(JSONObject.java:185)
    at com.shopee.shpssdk.SHPSSDK.uvwvvwvvw(Unknown Source:81)
    at com.shopee.shpssdk.SHPSSDK.requestDefense(Unknown Source:59)
 
hashMap.put:  x-sap-ri 443e41678c54f44f62b70d1901d115bc703ebab92a5b4251176d
马来西亚:https://shopee.my
新加坡:https://shopee.sg
泰国:https://shopee.th
印度尼西亚:https://shopee.id
越南:https://shopee.vn
菲律宾:https://shopee.ph
台湾:https://shopee.tw
大陆:https://shopee.cn
马来西亚:https://shopee.my
新加坡:https://shopee.sg
泰国:https://shopee.th
印度尼西亚:https://shopee.id
越南:https://shopee.vn
菲律宾:https://shopee.ph
台湾:https://shopee.tw
大陆:https://shopee.cn
[RegisterNatives] method_count: 0x4
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvv sig: (I)V module_name: libshpssdk.so offset: 0x1bef84
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvu sig: (Lcom/shopee/shpssdk/wvvvuvvv;)I module_name: libshpssdk.so offset: 0x1bf478
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvw sig: ([B[B)Ljava/lang/String; module_name: libshpssdk.so offset: 0x995dc
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvvw sig: ([B)V module_name: libshpssdk.so offset: 0x9932c
[RegisterNatives] method_count: 0x4
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvv sig: (I)V module_name: libshpssdk.so offset: 0x1bef84
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvu sig: (Lcom/shopee/shpssdk/wvvvuvvv;)I module_name: libshpssdk.so offset: 0x1bf478
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvw sig: ([B[B)Ljava/lang/String; module_name: libshpssdk.so offset: 0x995dc
name: com.shopee.shpssdk.wvvvuwwu vuwuuwvvw sig: ([B)V module_name: libshpssdk.so offset: 0x9932c
var dlopen = Module.findExportByName(null, "dlopen");//6.0
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");//高版本8.1以上
 
Interceptor.attach(dlopen, {
    onEnter: function (args) {
        var path_ptr = args[0];
        var path = ptr(path_ptr).readCString();
        console.log("[dlopen:]", path);
    },
    onLeave: function (retval) {
        // Thread.sleep(3);
    }
});
 
Interceptor.attach(android_dlopen_ext, {
    onEnter: function (args) {
        var path_ptr = args[0];
        var path = ptr(path_ptr).readCString();
        console.log("[dlopen_ext:]", path);
    },
    onLeave: function (retval) {
            // Thread.sleep(3);
    }
});
var dlopen = Module.findExportByName(null, "dlopen");//6.0
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");//高版本8.1以上
 
Interceptor.attach(dlopen, {
    onEnter: function (args) {
        var path_ptr = args[0];
        var path = ptr(path_ptr).readCString();
        console.log("[dlopen:]", path);
    },
    onLeave: function (retval) {
        // Thread.sleep(3);
    }
});
 
Interceptor.attach(android_dlopen_ext, {
    onEnter: function (args) {
        var path_ptr = args[0];
        var path = ptr(path_ptr).readCString();
        console.log("[dlopen_ext:]", path);
    },
    onLeave: function (retval) {
            // Thread.sleep(3);
    }
});
/data/app/~~KVEKJlJur2r6197VML5LRw==/com.shopee.sg-ZyVbLWincySSEAiqQSuPLQ==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libshpssdk.so
/data/app/~~KVEKJlJur2r6197VML5LRw==/com.shopee.sg-ZyVbLWincySSEAiqQSuPLQ==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libshpssdk.so
Java.perform(function (){
    console.log('======================')
    let wvvvuwwu = Java.use("com.shopee.shpssdk.wvvvuwwu");
    wvvvuwwu["vuwuuwvw"].implementation = function (bArr, bArr2) {
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");
        if(bArr!==null){
            try{
                console.log('111111111')
                console.log(`wvvvuwwu.vuwuuwvw is called: bArr=${ByteString.of(bArr).utf8()}, bArr2=${bArr2}`);
            }catch (e) {
            }
        }
        // console.log(`wvvvuwwu.vuwuuwvw is called: bArr=${bArr}, bArr2=${bArr2}`);
        let result = this["vuwuuwvw"](bArr, bArr2);
        console.log(`wvvvuwwu.vuwuuwvw result=${result}`);
        return result;
    };
})
Java.perform(function (){
    console.log('======================')
    let wvvvuwwu = Java.use("com.shopee.shpssdk.wvvvuwwu");
    wvvvuwwu["vuwuuwvw"].implementation = function (bArr, bArr2) {
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");
        if(bArr!==null){
            try{
                console.log('111111111')
                console.log(`wvvvuwwu.vuwuuwvw is called: bArr=${ByteString.of(bArr).utf8()}, bArr2=${bArr2}`);
            }catch (e) {
            }
        }
        // console.log(`wvvvuwwu.vuwuuwvw is called: bArr=${bArr}, bArr2=${bArr2}`);
        let result = this["vuwuuwvw"](bArr, bArr2);
        console.log(`wvvvuwwu.vuwuuwvw result=${result}`);
        return result;
    };
})
function call(){
    Java.perform(function (){
        let wvvvuwwu = Java.use("com.shopee.shpssdk.wvvvuwwu");
        var str = 'https://mall.shopee.ph/api/v4/pages/bottom_tab_bar'
        var StringClass = Java.use('java.lang.String');
        var byteArray = StringClass.$new(str).getBytes();
        var str2 = '{"img_size":"3.0x","latitude":"","location":"[]","longitude":"","new_arrival_reddot_last_dismissed_ts":0,"feed_reddots":[{"timestamp":0,"noti_code":28}],"client_feature_meta":{"is_live_and_video_merged_tab_supported":false},"video_reddot_last_dismissed_ts":0,"view_count":[{"count":1,"source":0,"tab_name":"Live"}]}'
        var byteArray2 = StringClass.$new(str2).getBytes();
        var res = wvvvuwwu["vuwuuwvw"](byteArray,byteArray2)
        console.log('res==>',res)
    })
}
function call(){
    Java.perform(function (){
        let wvvvuwwu = Java.use("com.shopee.shpssdk.wvvvuwwu");
        var str = 'https://mall.shopee.ph/api/v4/pages/bottom_tab_bar'
        var StringClass = Java.use('java.lang.String');
        var byteArray = StringClass.$new(str).getBytes();
        var str2 = '{"img_size":"3.0x","latitude":"","location":"[]","longitude":"","new_arrival_reddot_last_dismissed_ts":0,"feed_reddots":[{"timestamp":0,"noti_code":28}],"client_feature_meta":{"is_live_and_video_merged_tab_supported":false},"video_reddot_last_dismissed_ts":0,"view_count":[{"count":1,"source":0,"tab_name":"Live"}]}'
        var byteArray2 = StringClass.$new(str2).getBytes();
        var res = wvvvuwwu["vuwuuwvw"](byteArray,byteArray2)
        console.log('res==>',res)
    })
}
url = '/api/v4/pages/bottom_tab_bar'
def getKey1(url):
    tmp = 0
    for i in bytearray(url.encode()):
        tmp = tmp*0x334b & 0xffffffff
        tmp=(tmp+i) & 0xffffffff
    key = tmp&0x7fffffff
    return f"{key:04X}"
print('getKey1',getKey1(url)) # 1A9EC9B9 还原这个只需要url
url = '/api/v4/pages/bottom_tab_bar'
def getKey1(url):
    tmp = 0
    for i in bytearray(url.encode()):
        tmp = tmp*0x334b & 0xffffffff
        tmp=(tmp+i) & 0xffffffff
    key = tmp&0x7fffffff
    return f"{key:04X}"
print('getKey1',getKey1(url)) # 1A9EC9B9 还原这个只需要url
function stringToHexArray(str) {
    var hexArray = [];
    for (var i = 0; i < str.length; i++) {
        var hex = str.charCodeAt(i);
        hexArray.push(0x00 + hex);
    }
    return hexArray;
}
 
function call2(){
    var soAddr = Module.findBaseAddress("libshpssdk.so");
    var funAddr = soAddr.add(0x995dc);
    var fun = new NativeFunction(funAddr, 'pointer', ["pointer", "pointer",'pointer','pointer']);
    var JNIEnv = Java.vm.getEnv();
 
    var byteArray = stringToHexArray('https://mall.shopee.ph/api/v4/pages/bottom_tab_bar');
    var byteArrayPtr = Memory.alloc(byteArray.length);
    Memory.writeByteArray(byteArrayPtr, byteArray);
 
    var byteArray2 = stringToHexArray('{"img_size":"3.0x","latitude":"","location":"[]","longitude":"","new_arrival_reddot_last_dismissed_ts":0,"feed_reddots":[{"timestamp":0,"noti_code":28}],"client_feature_meta":{"is_live_and_video_merged_tab_supported":false},"video_reddot_last_dismissed_ts":0,"view_count":[{"count":1,"source":0,"tab_name":"Live"}]}');
    var byteArrayPtr2 = Memory.alloc(byteArray2.length);
    Memory.writeByteArray(byteArrayPtr2, byteArray2);
 
 
    var arr1 = JNIEnv.newByteArray(byteArray.length);
    JNIEnv.setByteArrayRegion(arr1,0,byteArray.length,byteArrayPtr)
 
    var arr2 = JNIEnv.newByteArray(byteArray2.length);
    JNIEnv.setByteArrayRegion(arr2,0,byteArray2.length,byteArrayPtr2)
 
    var res = fun(JNIEnv, ptr(0x0),arr1,arr2)
    var s = Java.cast(res, Java.use("java.lang.Object"));
    console.log(s)
}
function stringToHexArray(str) {
    var hexArray = [];
    for (var i = 0; i < str.length; i++) {
        var hex = str.charCodeAt(i);
        hexArray.push(0x00 + hex);
    }
    return hexArray;
}
 
function call2(){
    var soAddr = Module.findBaseAddress("libshpssdk.so");
    var funAddr = soAddr.add(0x995dc);
    var fun = new NativeFunction(funAddr, 'pointer', ["pointer", "pointer",'pointer','pointer']);
    var JNIEnv = Java.vm.getEnv();
 
    var byteArray = stringToHexArray('https://mall.shopee.ph/api/v4/pages/bottom_tab_bar');
    var byteArrayPtr = Memory.alloc(byteArray.length);
    Memory.writeByteArray(byteArrayPtr, byteArray);
 
    var byteArray2 = stringToHexArray('{"img_size":"3.0x","latitude":"","location":"[]","longitude":"","new_arrival_reddot_last_dismissed_ts":0,"feed_reddots":[{"timestamp":0,"noti_code":28}],"client_feature_meta":{"is_live_and_video_merged_tab_supported":false},"video_reddot_last_dismissed_ts":0,"view_count":[{"count":1,"source":0,"tab_name":"Live"}]}');
    var byteArrayPtr2 = Memory.alloc(byteArray2.length);
    Memory.writeByteArray(byteArrayPtr2, byteArray2);
 
 
    var arr1 = JNIEnv.newByteArray(byteArray.length);
    JNIEnv.setByteArrayRegion(arr1,0,byteArray.length,byteArrayPtr)

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-11-28 17:41 被杨如画编辑 ,原因:
收藏
免费 50
支持
分享
最新回复 (16)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
大佬 牛逼
2024-11-27 07:40
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
学习学习
2024-11-27 11:06
0
雪    币: 27
活跃值: (1768)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
跟老大学习
2024-11-27 12:00
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
期待大佬更多的trace技巧
2024-11-27 12:38
0
雪    币: 466
活跃值: (2629)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
look looook
2024-11-27 15:37
0
雪    币: 415
活跃值: (519)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
????????
2024-11-27 17:03
0
雪    币: 6
活跃值: (254)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
look looook
2024-11-27 18:22
0
雪    币: 181
活跃值: (145)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
好脚本
2024-11-27 19:32
0
雪    币: 8642
活跃值: (6743)
能力值: ( LV12,RANK:449 )
在线值:
发帖
回帖
粉丝
10
牛的,看看
2024-11-27 21:53
0
雪    币: 104
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
来了
2024-11-27 22:15
0
雪    币: 2186
活跃值: (2912)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
感谢分享
2024-11-27 22:17
0
雪    币: 1413
活跃值: (3046)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感谢分享
2024-11-28 13:28
0
雪    币: 1
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
感谢分享
2024-11-28 16:14
0
雪    币: 51
活跃值: (288)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
细看
2024-11-28 16:53
0
雪    币: 12
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
感谢分享
2024-11-28 17:47
0
雪    币: 2564
活跃值: (1661)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
17
已关闭回复可看,勿回复无用内容
2024-11-28 18:13
0
游客
登录 | 注册 方可回帖
返回
//