shopee app算法分析第一篇
分析完整算法大概要好几篇,耐心等待下
抓的搜索接口,get请求,核心的有3个4字节键和x-sap-ri,如果是post,就是4个4字节键和值,多出来的一个和post的表单有关
后续内容都是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
这个位置值已经生成了,往上找调用,就一个,结果来自wvvvuwwu.vuwuuwvw(str.getBytes(), bArr),hook发现,第一个参数url,第二个表单(get就是null)
点过去来到native注册的地方
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启动,很幸运没有初始化,国内大厂没有没有初始化的,这块占逆向比重也很大.
执行无异常
然后调用函数. callByAPI放开
上来就查找异常,上面验证了没有初始化,也就是说直接调用理论上是可以的.很明显上来就走到异常了. 要么放弃unidbg,用stalker,要么硬干,排除异常.
我选择试试排除异常,在刚调用函数的位置开启trace,运行
刚开始异常的位置是0x980b8,ida中看看
没有有用的信息
往上找了找,看到了都是和异常相关的字段,判断应该是走入这个函数导致的异常,如果不让函数执行到这里是不是就可以绕过了?可以尝试一下,没有好的办法,不试你就只能扔到回收站.
异常函数是sub_9646C
日志中看到由9a204跳到异常
off_345F20里放的都是函数地址,有点罕见这种.
复制出来搜索发现只有一处走向异常,之前尝试了不让他走到这个判断里面,有些困难
最好的办法是把这个跳转直接nop掉
运行
进入到正常逻辑了,后续的补环境交给你相信也是信手拈来.
补环境代码中可能有东西参与了计算,需要注意,另外大部分结果由随机数构成,需要处理好哪些随机是对应的.走的是/dev/urandom
x-sap-ri算法
不要觉得看上去很简单,想一想没有资料你能不能搞的出来? 后续预计3-4篇算法
后续这种简单的定位,脚本什么可能一笔带过了,默认都会了,我觉得这篇还是很详细的,后续算法远比这些复杂
Java.perform(
function
(){
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
(){
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"
);
var
android_dlopen_ext = Module.findExportByName(
null
,
"android_dlopen_ext"
);
Interceptor.attach(dlopen, {
onEnter:
function
(args) {
var
path_ptr = args[0];
var
path = ptr(path_ptr).readCString();
console.log(
"[dlopen:]"
, path);
},
onLeave:
function
(retval) {
}
});
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) {
}
});
var
dlopen = Module.findExportByName(
null
,
"dlopen"
);
var
android_dlopen_ext = Module.findExportByName(
null
,
"android_dlopen_ext"
);
Interceptor.attach(dlopen, {
onEnter:
function
(args) {
var
path_ptr = args[0];
var
path = ptr(path_ptr).readCString();
console.log(
"[dlopen:]"
, path);
},
onLeave:
function
(retval) {
}
});
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) {
}
});
/
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) {
}
}
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) {
}
}
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))
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))
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
被杨如画编辑
,原因: