今日内容

1 逆向目标

1
2
3
# 识货app
1 搜索商品功能
2 查看商品详情

image-20231228200648460

image-20240517170730669

2 版本选择

1
2
3
4
5
#  豌豆夹下载app
- 老版本:7.21.1 ---》强制更新--》绕过强制更新
- 讲课版本:7.53.0
- 最新版:7.73.0
----最新版跟讲课版一样---

3 绕过app强制更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#1  如果我们使用老版本  7.21.1   识货app要求我们更新---》我们不更新,接口也是可以用的---》更新弹出框,盖住了app---》无法操作
# 2 adb install 识货7.21.1 装到手机上,打开,会看到强制更新,并且无法点击其他操作

# 3 但是我们看到,其实app不更新,接口也是可以用的,但是弹出框,我们没法先取消,于是我们需要绕过app的强制更新----》有些app不是强制更新---》有个x,点击x,就可以不更新了

# 4 以后咱们在使用app过程中,遇到更新情况,会有以下两种情况
1 选择更新:弹出框,有取消按钮,可以不更新---》暂时不更新即可---》app版本中用到的所有接口,肯定是可以用的
2 强制更新:弹出框,没有取消,必须更新---》我们可以绕过更新---》有可能接口不能使用了---》如果能用,咱们就可以破解这个版本--》老版本的app,更好破解一些---》识货,绕过更新可以使用


# 5 如何绕过强制更新
1 车智赢:强制更新,断开wifi,进入app,然后链接wifi,就可以绕过了
-app一启动---》向后端发送请求---》获取app的最新版本号---》跟本地版本号做比较---》如果两个版本差距过大---》强制弹出窗---》让咱们更新---》弹窗代码在首页---》只要切换到别的页面,这个弹窗就没了

2 识货:断网,绕不过,只要联网,在任意一个页面,都会再弹出
-通过反编译,找到弹窗位置---》hook技术,让弹窗不弹出--》实现绕过


# 6 注意点(一会后面会看到):
hook方案---》必须先运行一次app,点同意使用app后,在运行hook脚本

image-20240517170744783

3.1 hook绕过更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1 反编译:apk---》搜索    最新版本
# 2 一个结果,双击进来
public void d() {
e.c(f20545b.get());
if (b()) {
if (c()) {
f20545b.get().startService(new Intent(f20545b.get(), DownloadService.class));
# 如果后端查到的版本高,就会弹出窗,要求更新
} else if (this.j > com.azhon.appupdate.c.a.c(f20545b.get())) {
#弹出窗
UpdateDialog updateDialog = new UpdateDialog(f20545b.get());
this.p = updateDialog;
# 只要执行 show ,就会弹窗,通过hook技术--》hook这个show方法,让它不运行
# 绕过了弹窗
# app中所有弹窗都会失效--》包括第一次运行app时,同意规范
# 通用方案:所有app都可以用这个方案
updateDialog.show();
} else {
if (this.f20550g) {
Toast.makeText(f20545b.get(), R.string.latest_version, 0).show();
}
f.f(f20544a, "当前已是最新版本");
}
}
}

image-20240517170756442

3.2 hook脚本()

启动frida-server

1
2
3
4
5
# 打开cmd,执行
adb shell
su
cd /data/local/tmp
./frida-server-16.1.7-an

端口转发

1
2
3
4
5
import subprocess
subprocess.getoutput("adb forward tcp:27042 tcp:27042")
subprocess.getoutput("adb forward tcp:27043 tcp:27043")

# 以后手机端每次启动了frida-server,都要执行端口转发,否则会报错

打印前台运行app的包名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 枚举手机上的所有进程 & 前台进程,找到 识货的包名
import frida

# 获取设备信息
rdev = frida.get_remote_device()

# 枚举所有的进程
processes = rdev.enumerate_processes()
for process in processes:
print(process)

# 获取在前台运行的APP
front_app = rdev.get_frontmost_application()
print(front_app)
# Application(identifier="com.hupu.shihuo", name="识货", pid=28602, parameters={})

spawn和attach方案–>使用spawn方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import frida
import sys

rdev = frida.get_remote_device()
pid = rdev.spawn(["com.hupu.shihuo"])
session = rdev.attach(pid)

scr = """
Java.perform(function () {
var UpdateDialog = Java.use('com.azhon.appupdate.dialog.UpdateDialog');
UpdateDialog.show.implementation = function(ctx){
console.log("执行了");
//this.show();
}
});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
rdev.resume(pid)
sys.stdin.read()

执行hook时,发现只要一运行hook脚本,app就闪退了–》做了friad的反调试

4 绕过frida反调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1 我们写好了hook脚本,运行的时候,发现,只要运行hook脚本,app就闪退
# 2 因为识货app,做了frida的反调试,只要检测到frida运行,app就自动结束
# 3 绕过frida反调试方案

# 4 绕过frida反调试方式一:
-有些公司,安全部门的人员,会通过编写 so文件,检测frida是否在运行,如果运行,就自动终止app
-安全人员写的so,是单独的,不会跟app的业务功能关联,我们通过删除这些so文件,实现绕过
-我们要尝试删除---》再测试app是否能正常使用,如果正常使用,说明这个so跟业务无关,如果app不能使用了,说明删除的这个so跟业务有关,我们就不能删除
-识货,得物app,就是 删除不影响的
-我们只需要找到是那个so检测了frida,直接删除即可
-写一个hook脚本,在执行app的时候,一个个打印出so文件,当打印到某个so文件时,如果app退出了,这个so文件,就是在检测frida是否运行
-通过hook安卓底层,依次打印 运行app时,加载的so文件---》这个hook脚本,以后直接拿着用
-会依次打印出app加载了那些so文件

# 5 绕过frida反调试方案二: 后续会讲
使用一个增强版的frida---》内部还是frida---》隐藏了frida的特征--》app检测不出来是在运行frida

# 6 绕过fida方案三:
断网执行app,能正常hook并打开,再联网---》只能绕过比较少的app

4.1 打印app加载了那些so文件的hook脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import frida
import sys

rdev = frida.get_remote_device()
pid = rdev.spawn(["com.hupu.shihuo"])
session = rdev.attach(pid)

scr = """
Java.perform(function () {

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) {

}
});


});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
rdev.resume(pid)
sys.stdin.read()

4.2 删除so

1
2
3
4
5
# 打开cmd
adb shell
su
# 你们的路径跟我的不一样
rm /data/app/~~ns1TfdYpeas9zx30Q7mtCQ==/com.hupu.shihuo-T19RXL87pIsM6A5Pfbvcxg==/lib/arm64/libmsaoaidsec.so

image-20240517170818164

5.1 绕过app代理检测

1
2
3
# 1 我们抓包,发现好多包,抓出来是乱码,而且没有咱们想抓的包
# 2 识货app,做了代理检测,如果使用代理,就是乱码
# 3 绕过代理的检测---》抓取更底层的包--》不抓https的包了,抓socket的包,需要使用app装在手机上

image-20240517170830650

image-20240517170837763

1
2
3
4
5
# 1 这种类型app很多,我们使用 SocksDroid.apk
# 2 删除系统代理--》手机上代理是无
# 3 安装 SocksDroid.apk
# 4 打开SocksDroid 配置 电脑的ip和抓取socket包的端口:8889,如下图
# 5 打开app抓包即可,如下,顺利抓包

**image-20240517170850072

image-20240517170859846

5.1.1 SocksDroid(推荐-我们讲)

  • 手机系统代理删除
  • 基本配置

切记:在使用前删除手机上设置的系统代理。

image-20240517170909962

image-20240517170948345

image-20240517170919579

image-20240517170929844

5.1.2 drony

安装在手机、模拟器上的一个软件,对你的手机中某些app中的请求进行转发。

  • Drony-102.apk 【英文版】 【安卓低版本】【模拟器】
  • Drony-1-3.154.apk 【繁体中文】【手机】

打开app,滑动进入settings配置页面。

注意:这个app不稳定,有时加载不出 WIFI,所以就没办法使用了。

image-20240517171007982

image-20240517171016684

5.1.3 ProxyDroid

切记:在使用前删除手机上设置的系统代理。

image-20240517171025087

image-20240517171033329

5.2 抓包搜索功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 老版本搜索功能   新版本搜索跟老版本有点区别
# 1 在app上搜索,抓包
# 2 请求包
-请求地址:
https://sh-api.shihuo.cn/daga/search/goods/v1
-请求参数
minVersion 15670
clientCode {holder}
v 7.20.1
channel myapp
device Pixel 2 XL
platform android
timestamp 1703770453838
token 578f8d6b56fcaa416b2e891de95e1021
-请求方式
post
-请求头:
很多,尝试删除某些,好多都可以删除

-请求体:
{

"keywords": "羽绒服", # 搜其他商品,只要改这个名字即可
"page": "1",
"pageSize": "20",

}


# 3 我们只要向 https://sh-api.shihuo.cn/daga/search/goods/v1 这个地址发请求,修改请求体的keywords,就可以查询出不同的商品

5.3 python代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests

res = requests.post(
url='https://sh-api.shihuo.cn/daga/search/goods/v1',
params={
'minVersion': '15670',
'clientCode': '{holder}',
'v': '7.20.1',
'channel': 'myapp',
'device': 'Pixel 2 XL',
'platform': 'android',
'timestamp': '1703770453838'
},
json={
"keywords": "篮球", # 搜其他商品,只要改这个名字即可
"page": "1",
"pageSize": "20",
},
verify=False
)

print(res.text)


# 后续咱们代码整合,会把所有参数都加上

5.4 抓包商品详情功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#1  老版本的详情地址:
请求地址:https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_zone/detail/v
请求方式:get
请求参数:
...
id 4564401 # 商品id
...

# 2 之前的时候,发送请求查询详情,把请求数据都加密了--》返回的数据也是加密的
现在演示不出来了
如果是这种方式,我们需要后续操作
现在不是了,我们直接破即可,只要要绕过验证码

# 3 现在它换成了,第一个加载,要求我们滑动验证码


### 注意:目前它不是加密方式,所有后续的 6,咱们只是为了学习
-因为6中会学到好多破解方案--》hook脚本,后期别的app可能会用

image-20240517171050337

6 Hook尝试

1
2
3
# 假设咱么后期再破解app,遇到了上面那种,请求数据加密和返回数据加密的情况,咱们应该如何破解


6.1 hook-Map操作–这个app没走–后续别的app会用

1
2
3
4
# 1 通过hook map操作,确认是不是走了这
data:加密数据--》很有可能在app内部--》map.put('data',xx.sign(数据))
我们可以尝试hook--map---》确认是不是这种思路
咱们这个app不是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import frida
import sys

rdev = frida.get_remote_device()
session = rdev.attach("识货")

scr = """
Java.perform(function () {
var TreeMap = Java.use('java.util.TreeMap');
var Map = Java.use("java.util.Map");

TreeMap.put.implementation = function (key,value) {
if(key=="data"){
console.log(key,value);
}
var res = this.put(key,value);
return res;
}
});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
sys.stdin.read()

6.2 hook-StringBuilder操作-也没走

1
2
3
4
5
6
7
# 2 没走map ,有可能走了 字符串拼接
StringBuilder sb =new StringBuilder();
sb.append('data')
sb.append('加密字符串')
sb.toString()
# 把它转成真正的字符串
# 通过hook StringBuilder 的toString 方法看看有没有走

6.2.1 python 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# com.che168.autotradercloud

import frida
import sys

rdev = frida.get_remote_device()
session = rdev.attach("识货")

scr = """
Java.perform(function () {
var StringBuilder = Java.use("java.lang.StringBuilder");

StringBuilder.toString.implementation = function () {
var res = this.toString();
console.log(res);
return res;
}

});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
sys.stdin.read()

6.2.2 js脚本-把打印输出到txt中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 7-js-hook-StringBuidler.js

Java.perform(function () {
var StringBuilder = Java.use("java.lang.StringBuilder");

StringBuilder.toString.implementation = function () {
var res = this.toString();
console.log(res);
return res;
}
});

// frida -UF 7-js-hook-StringBuidler.js -o string.txt
// 把hook脚本的打印输出到 string.txt 中
// 发现并没有输出到string.txt中

6.3 hook-base64脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import frida
import sys

rdev = frida.get_remote_device()
session = rdev.attach("识货")

scr = """
Java.perform(function () {
var Base64 = Java.use("android.util.Base64");

Base64.encodeToString.overload('[B', 'int').implementation = function (bArr,val) {
var res = this.encodeToString(bArr,val);
console.log("加密了-->",res);
return res;
}
});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
sys.stdin.read()

# 通过查看输出,那请求的数据搜索,发现hook到了

6.3 hook-拦截器

1
2
3
4
5
6
7
8
9
10
11
12
// hook_Interceptor.js
Java.perform(function () {
var Builder = Java.use('okhttp3.OkHttpClient$Builder');

Builder.addInterceptor.implementation = function (inter) {

console.log(JSON.stringify(inter) );
return this.addInterceptor(inter);
};
})

//frida -Uf com.hupu.shihuo -l hook_Interceptor.js -o all_interceptor3.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.h>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.imageview.loader.c.b$a>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.e>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.d>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.b>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.h>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.g>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.a>"
"<instance: okhttp3.Interceptor, $className: cn.shihuo.modulelib.utils.f1.a$a>"
"<instance: okhttp3.Interceptor, $className: cn.shihuo.modulelib.startup.core.c.b>"
"<instance: okhttp3.Interceptor, $className: cn.shihuo.modulelib.startup.core.c.a>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.d>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.h>"
"<instance: okhttp3.Interceptor, $className: com.shizhi.shihuoapp.library.net.h.g>"
"<instance: okhttp3.Interceptor, $className: cn.shihuo.modulelib.utils.f1.a$a>"
"<instance: okhttp3.Interceptor, $className: cn.shihuo.modulelib.startup.core.c.b>"
"<instance: okhttp3.Interceptor, $className: cn.shihuo.modulelib.startup.core.c.a>"

6.3.1 一个个hook拦截器–看看那个拦截器做了加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 这个不是
import frida
import sys

rdev = frida.get_remote_device()
session = rdev.attach("识货")

scr = """
Java.perform(function () {
var a = Java.use("cn.shihuo.modulelib.startup.core.c.a");

a.intercept.implementation = function (chain) {
var req = chain.request();
var httpUrl = req.url().toString();
if( httpUrl.indexOf("https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_shoe/preload/single") != -1 ){
console.log('执行前',httpUrl);
}

var res = this.intercept(chain); // 执行自己这个拦截器
return res;
}

});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
sys.stdin.read()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 走了这个拦截器做了加密
# 我们直接跳过拦截器的执行---》他就不加密了---》发出去的是明文请求---》回来的也是明文响应
# 发送加密请求--》返回加密数据 可以用
# 发送明文请求--》返回明文数据 可以用
import frida
import sys

rdev = frida.get_remote_device()
session = rdev.attach("识货")

scr = """
Java.perform(function () {
var a = Java.use("cn.shihuo.modulelib.utils.f1.a$a");

a.intercept.implementation = function (chain) {
var req = chain.request();
var httpUrl = req.url().toString();
if( httpUrl.indexOf("https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_shoe/preload/single") != -1 ){
console.log('执行前',httpUrl);
}
// 不走自己的拦截器了,跳过该拦截器执行,继续执行下面的拦截器
var response = chain.proceed(req);
return response;
}

});
"""
script = session.create_script(scr)


def on_message(message, data):
print(message, data)


script.on("message", on_message)
script.load()
sys.stdin.read()


// 这个拦截器找到了可以发送明文的地址

6.4 总结

1
2
3
4
5
# 我们通过hook拦截器--》找到了某个拦截器做了加密--》正常思路,去代码中查看拦截器如何加密的-->用so文件加密的---》
#但是这个加密过程很复杂--》直接硬破so--》难度很大
# 我们发现直接明文发送,可以返回明文--》那我们没有必要破解了--》现在的版本都是这样了

# so的破解加密数据---》后续学习unidbg会直接把加密数据跑成明文---》不需要硬核破解so

7 python发送请求获取商品详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 老版本--》不能用--》目前客户端也不能用了
'''
可能得原因---》有可能封了ip
老版本接口不稳定--》可能不能用
'''

# 切换app版本--》换成新版--》app来测试

import requests
import utils

header_str = '''
platform android
timestamp 1703773087449
app-v 7.20.1
sh-token 87hst02l44ZGM1MThiNDFjNjViZGJkMzdlG+uyjSoG4dhG+Z10Djqz49dGEenN4jjVqsd3TNRjYoyEzgcQbbKyVRhv25Wy8u88yBS4/yhKtisuPY2xS1E6+ajO6XMz5ngM7MDuhI/KpJTIpECDt1S56uywH9+2jPfAPDdGWkV0+K0ZutVz8GxaEA==
sh-id 25v48ze69aff513bc9558c019c697605
sh-sign C13420884460F6AE649B92294547E34D
abtest-control HN=2;Gs=0;zF=1;aQ=0;Xj=1;zT=0;Xs=35;IG=0;AA=1;af=12;jO=2;am=0;shrec_is_gdetail=11;rd=1;kA=3;kB=11;ay=3;search_wf=2;ZW=11;zz=12;Qv=11;Ah=1;bn=0;sa=0;JZ=0;sf=12;Av=24;Rg=2;sh=2;cY=1;Rh=15;tK=3;dD=1;dK=2;t_s=1703772219828;gdetail_brand_rec=11;KY=1;By=1;Bz=0;uO=0;data_community_relate=12;dc=1;ln=2;eI=3;tx=19;LR=2;DO=2;Ta=1;uc=2;Te=1;vL=1;Df=12;MQ=2;data_community_personal=89;fK=12;UZ=1;fL=0;Lu=1;nY=2;EQ=2;ev=2;vn=12;Un=0;mainSearchV3=25;fa=0;NI=1;mainSearchV4=23;nj=2;nn=0;vv=2;shrec_gdetail_bags=13;data_gdetail_shoes_personal=11;data_gdetail_clothes_personal=12;shoes_ratio_ctrl=1;oZ=12;gdetail_shoes_brand_rec=11;gX=0;fx=2;shrec_home_feed=17;Fd=2;ge=15;xV=0;gf=13;gh=0;pR=21;ou=3;Fn=3;GP=0;shrec_cf_mine_v2=11;XD=0;hW=3;Wg=12;pa=0;shrec_gdetail_clothes=13;PE=12;Od=13;yN=1
shreqid 2BC91662A05CC9F996F71A8F9A4B3BAB
osv 11
network 1
sh_session 7f9a1fca3b114ce0b308283f0062d5e0_foreground_525571
sk 9MRYHxYzeIwT5VTCyBnbXFdf39hbCo06r1oTpaW4rnNvheJuLIckKkSUH2cpirlmXot9rIFBAvDP37nmOXBb7L5Drd1x
appid app
cookie acw_tc=76b20ff517037722253338690e1322c1846ea470719927b4302648969599f6
user-agent Android 11 {Z29vZ2xl} CPU_ABI arm64-v8a CPU_ABI2 HARDWARE taimen MODEL {UGl4ZWwgMiBYTA} network/WIFI shihuo/7.20.1 sc({holder},myapp) minVersion(15670) sh-dv-sign[v1|10418e17bc015815ef161fc2a5029c0d0d2751f79b8da0aa]
daga-ban-personal 0
accept-encoding gzip
'''

'''
'devices': 'Pixel 2 XL',
'dspm' :'1d71bbc11c117c0d',
'gender': '2',
'goods_id': '823698',
'sourceLocation': 'oneRowOne:[N]',
'style_id': '7068632',
'top_style_id': '7068632',
'tpExtra': '{"sourceTp":"home:search:","sourceTpName":"马丁靴","wsf":"normal_search_words","ast":"马丁靴","is_inspire":0,"dgReqId":"SHSS_CG-P0HFLTBTUMO7_SPU_1:23","si":"8001","skc":"7068632","layer":"2"}',
'access_token': 'b7EM8Up9VSFJUhkyEJ',
'minVersion': '15670',
'clientCode': '{holder}',
'v': '7.20.1',
'channel': 'myapp',
'device': 'Pixel 2 XL',
'platform': 'android',
'timestamp': '1703773087449',
'access_token': 'b7EM8Up9VSFJUhkyEJ',
'token' :'7f66140a1de98e4b59b6c3417d0a4c4e',

'''
# 不同的情况,查询详情的接口不太一样
# 详情接口有:https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_shoe/preload/single
# 详情接口也有:https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_zone/detail/v
res = requests.get(
'https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_shoe/preload/single',
params={
'devices': 'Pixel 2 XL',
'dspm': '1d71bbc11c117c0d',
'gender': '2',
'goods_id': '823698',
'sourceLocation': 'oneRowOne:[N]',
'style_id': '7068632',
'top_style_id': '7068632',
'tpExtra': '{"sourceTp":"home:search:","sourceTpName":"马丁靴","wsf":"normal_search_words","ast":"马丁靴","is_inspire":0,"dgReqId":"SHSS_CG-P0HFLTBTUMO7_SPU_1:23","si":"8001","skc":"7068632","layer":"2"}',
'access_token': 'b7EM8Up9VSFJUhkyEJ',
'minVersion': '15670',
'clientCode': '{holder}',
'v': '7.20.1',
'channel': 'myapp',
'device': 'Pixel 2 XL',
'platform': 'android',
'timestamp': '1703773087449',
'access_token': 'b7EM8Up9VSFJUhkyEJ',
'token': '7f66140a1de98e4b59b6c3417d0a4c4e',
},
verify=False, headers=utils.header_str_to_dict(header_str))
print(res.json())

8 代码整合

8.1 老版本(不用试了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import requests
from utils import header_str_to_dict
import urllib3

urllib3.disable_warnings()
header_str = '''
sh-token 07YHP1RqF2ZjZiZDRlMjg0ZWJlNmY5OWRiVrVJil+FyNFpPfAYRwUnQZjD7Y0EMrH0URCKv764zx2HrJrYl7RugWdY2JZP2mlh2o63ZQhD9f2BlkbdZzS3eRaVNn+LfKaM+2xWa3yAnTwDsBJq658HFt7VNjuaBKnX+e9kjFcgtdCl2h0kIgZyFA=='''
headers = header_str_to_dict(header_str)
# 搜索商品的接口
res = requests.post(
url="https://sh-api.shihuo.cn/daga/search/goods/v1?minVersion=15670&clientCode=%7Bholder%7D&v=7.20.1&channel=myapp&device=Pixel%202%20XL&platform=android&timestamp=1697021144536&token=3dec4554119714351dedd1f457099573",
# headers=headers,
json={
"keywords": "帆布鞋",
"pageSize": "20",
"page": "1",

}, verify=False
)
print(res.text)
data_dict = res.json()

print('------')
l = []
for item in data_dict['data']['lists']:
try:
print(item['name'])
for ele in item['style_lists']:
print('-----', ele['goods_id'], ele['name'], ele['price'])
# 通过商品id,获取商品的详情
l.append(ele['goods_id'])
except:
pass

header_str = '''
platform android
timestamp 1697022069424
app-v 7.20.1
sh-token 19Zo0LudYxM2M3NDBiZThjNmNjNTM1ZGMwnqndf6tomH872jLQjhgYbdFdIyqJGmWsdG6mb1tPj5mcB/3l6G58H274IwjqbjH09QyGMZg/QEqYOjTFSXdZ6SqroQY0+7KrhcoExdS0hlCpdaSb4FF9/sPivU2Eh9ZoPRaufuOMqX08wzYTIF4eug==
sh-id 913962kpcbdb29f68fc2552232c86cb3
sh-sign DF380FBA1CF473B2FDD4BC570F6EB5B1
abtest-control ln=3;eI=3;HN=0;LR=0;Ks=0;eN=2;Gs=2;zF=1;Ta=2;uc=2;aQ=0;Xj=1;zT=0;IG=0;AA=2;Df=13;MQ=1;fK=11;data_community_personal=3;jO=2;UZ=0;fL=0;Lu=1;nY=2;am=0;EQ=2;shrec_is_gdetail=12;RA=2;ev=22;kA=3;kB=11;ay=3;gA=2;mainSearchV3=25;search_wf=3;NI=0;mainSearchV4=27;nj=2;Us=1;nn=0;zz=12;Yz=1;shrec_gdetail_bags=11;Qv=17;Ah=11;data_gdetail_shoes_personal=11;data_gdetail_clothes_personal=11;oZ=12;shoes_ratio_ctrl=0;bn=0;sa=0;Ap=2;gdetail_shoes_brand_rec=11;JZ=1;SD=0;fx=3;sf=12;Av=24;sh=0;Rg=2;cY=1;Rh=15;tK=3;shrec_home_feed=17;Fd=2;gf=12;dD=0;gh=0;CI=1;ou=3;dK=0;Fn=3;CL=2;GP=1;t_s=1697020869050;oy=2;gdetail_brand_rec=11;shrec_cf_mine_v2=11;KY=6;hW=3;Wg=12;pa=0;shrec_gdetail_clothes=11;Od=11;yN=8;By=0;Bz=0;uO=0;data_community_relate=11;dc=1
shreqid 57F9D010EF0EA0A05E845396BA6B3E1F
osv 11
network 1
sh_session 7804c48b010b40f699adcc4b4aaa89f0_foreground_1002591
sk 9MJTD4FFJBgRUPSgNfZIKOA8bCGnv4wt7McVWcxBYyOZBJiez6r4AjzcgGweapZa1GGcamedBEXYqzEOVegB7d2klJ1w
appid app
cookie acw_tc=76b20fe616970207931503924e60da603e28e89a17d213f16b5b87b95b3433
user-agent Android 11 {Z29vZ2xl} CPU_ABI arm64-v8a CPU_ABI2 HARDWARE taimen MODEL {UGl4ZWwgMiBYTA} network/WIFI shihuo/7.20.1 sc({holder},myapp) minVersion(15670) sh-dv-sign[v1|6bd3e4ffa3ce6c880e6681a9f90775c60d2751f79b8da0aa]
'''
for good_id in l:
print(good_id)

headers = header_str_to_dict(header_str)
res = requests.get(
url=f'https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_shoe/preload/single?devices=Pixel%202%20XL&dspm=95e6ec308860e77a&gender=2&goods_id={good_id}&sourceLocation=oneRowOne%3A%5BN%5D&style_id=40941356&top_style_id=40941356&tpExtra=%7B%22sourceTp%22%3A%22home%3Asearch%3A%22%2C%22sourceTpName%22%3A%22%E5%B8%86%E5%B8%83%E9%9E%8B%22%2C%22wsf%22%3A%22normal_search_words%22%2C%22ast%22%3A%22%E5%B8%86%E5%B8%83%E9%9E%8B%22%2C%22is_inspire%22%3A0%2C%22dgReqId%22%3A%22SHSS_CG-O7CKNHGTO8RT_SPU_1%3A27%22%2C%22si%22%3A%228001%22%2C%22skc%22%3A%2240941356%22%2C%22layer%22%3A%222%22%7D&access_token=b7EM8Up9VSFJUhkyEJ&minVersion=15670&clientCode=%7Bholder%7D&v=7.20.1&channel=myapp&device=Pixel%202%20XL&platform=android&timestamp=1697022069424&access_token=b7EM8Up9VSFJUhkyEJ&token=570a49e713cc2b3a2a3a1e627878b86b',
verify=False,
headers=headers
)
# print(res.text)
print('付款人数:', res.json()['data']['info']['goods_info']['monthSellPoint'])

8.2 新版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import requests
from utils import header_str_to_dict
import urllib3
import utils
urllib3.disable_warnings()

import requests

res = requests.post(
url='https://sh-api.shihuo.cn/daga/search/goods/v1',
params={
'minVersion': '15670',
'clientCode': '{holder}',
'v': '7.20.1',
'channel': 'myapp',
'device': 'Pixel 2 XL',
'platform': 'android',
'timestamp': '1703770453838'
},
json={
"keywords": "篮球", # 搜其他商品,只要改这个名字即可
"page": "1",
"pageSize": "20",
},
verify=False
)

print(res.text)
data_dict = res.json()

print('------')
l = []
for item in data_dict['data']['lists']:
print(item['name'])
for ele in item['style_lists']:
print('-----', ele['goods_id'], ele['name'], ele['price'])
# 通过商品id,获取商品的详情
l.append(ele['goods_id'])


header_str = '''
替换成你们抓包抓到的
'''


for good_id in l:
print(good_id)
params_str = '''

'''%good_id

headers = header_str_to_dict(header_str)
res = requests.get(
url=f'https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_zone/detail/v1',
params=utils.header_str_to_dict(params_str),
verify=False, headers=headers)
print(res.text)
# print('付款人数:', res.json()['data']['info']['goods_info']['monthSellPoint'])


9 问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 新版本的接口,加了滑动验证
-在手机上滑动滑块---》向后端发送请求--》只要通过---》手机就通过认证了---》只需要抓包--》拿到请求头和请求参数内容,放到代码中,就可以发请求了--》因为咱们得python代码的手机设备号,用的是我自己手机的设备号


# 详情接口
--有可能封了手机的设备号
--封ip了


# 总结:
1 强制更新绕过
2 frida反调试
3 绕过系统代理检测
4 一堆hook脚本--后续会有
-hook-map
-hook-StringBuilder
-hook-base64
-hook-拦截器
5 搜索和详情python代码实现了
-详情 新版本加入了滑块认证
-手机上先滑块通过---》python发送请求,copy出请求头和请求参数的数据,请求参数中只需要替换id

6 我现在除了问题---》详情接口访问不通
-封了设备id--》模拟器也不行
-封了ip---》使用代理解决

7 拿着我的代码
-1 手机上滑块认证通过
-2 把请求头和参数数据copy出来,使用python发送请求就可以了




8 charles抓包工具--》如果开启了
proxy---》window proxy--》抓电脑包--》电脑上发送的所有请求包都会抓到--》在pycharm中发送请求,也会走这个代码(电脑上)--》我们不希望这样,就把对钩去掉---》还可以抓手机包----》只是电脑上的请求包不会在走代理了

image-20240517171115855

__END__