找到加密的smile具体位置

抓包查看参数

/v2/member?password=abc123456&clientid=1&device_id=865166029891887&ip=172.16.2.15&system_name=android&sign=a6ed53f3ff9ad4fd0727d277711d9c57&siteid=10001&time=1650617846325&type=android&account=18235673456&modules=cloudlogin%3A1

只有sign是加密的,所以分析sign就好

搜出来肯定很多,所以我想到了结合链接,找位置

/v2/membersign

找了半天,好像都是差不多的地方,于是找到了这里,只有这里最像

以下是我找到的具体代码,有很多跟第一个函数很像的

我的疑问:确定不了的话,只能下断点,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
 private Params createParams(Params arg8) {
if(arg8 == null) {
arg8 = new Params();
}

arg8.put("device_id", DeviceUtils.getDeviceId(this.ctMediaCloudConfig.mContext));
arg8.put("clientid", "1");
arg8.put("ip", NetworkUtil.getLocalIP());
long v0 = System.currentTimeMillis();
arg8.put("siteid", this.ctMediaCloudConfig.siteId);
arg8.put("system_name", "android");
arg8.put("type", "android");
arg8.put("sign", SignUtil.getSignStr(arg8.getUrlParams(), this.ctMediaCloudConfig.secretSign, v0 + ""));
arg8.put("time", v0 + "");
return arg8;
}




private Params getRequestParams(Params arg10, String arg11) {
Params v1 = new Params();
v1.put("device_id", DeviceUtils.getDeviceId(this.ctMediaCloudConfig.mContext));
v1.put("siteid", this.ctMediaCloudConfig.siteId);
v1.put("clientid", "1");
v1.put("ip", NetworkUtil.getLocalIP());
v1.put("system_name", "android");
v1.put("modules", arg11);
long v2 = System.currentTimeMillis();
v1.put("type", "android");
Params v0 = new Params(v1.getUrlParams());
v0.putAll(arg10.getUrlParams());
v1.put("sign", SignUtil.getSignStr(v0.getUrlParams(), this.ctMediaCloudConfig.secretSign, v2 + ""));
v1.put("time", v2 + "");
return v1;
}

CTRL+B下断点在每个sign的地方,例如这样:

然后打开模拟器,点击jeb的debug

附加上了后会出来这么一个界面

然后点击模拟器中的登录

password:abc123456

然后就找到了这里sign的具体位置

1
2
3
4
5
6
7
8
9
10
11
12
13
public RequestParams a(RequestParams arg7, Context arg8) {
arg7.put("device_id", PhoneInfoUtils.getDeviceId(arg8));
arg7.put("clientid", "1");
arg7.put("ip", AppUtil.getLocalIP());
long v0 = System.currentTimeMillis();
arg7.put("siteid", "10001");
arg7.put("system_name", "android");
arg7.put("type", "android");
arg7.put("sign", b.a(arg7.getURLHashMap(), v0 + ""));
arg7.put("time", v0 + "");
return arg7;
}

总结:我们要找的就是arg7.put("sign", b.a(arg7.getURLHashMap(), v0 + ""));这一串

函数分析

v0看代码可以知道是时间戳

关键在于分析b.a(arg7.getURLHashMap(), v0 + "")

1.getURLHashMap()

1
2
3
public HashMap getURLHashMap() {
return this.l;
}

2.arg7应该是前面涉及的集合

3.a()

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
public static String a(HashMap arg14, String arg15) {
LinkedHashMap v8 = new LinkedHashMap();
Object[] v3 = arg14.keySet().toArray(); // keySet相当于把{x:1,y:2,z:3}中的xyz取出组成数组
Arrays.sort(v3);
int v11 = v3.length;
int v10;
for(v10 = 0; v10 < v11; ++v10) {
Object v2 = v3[v10];
try {
v8.put(v2.toString(), URLEncoder.encode(arg14.get(v2).toString(), "UTF-8"));
}
catch(UnsupportedEncodingException v0) {
v0.printStackTrace();
}
}

StringBuilder v5 = new StringBuilder();
Iterator v10_1 = v8.entrySet().iterator(); //一般后边一定有个while循环
while(v10_1.hasNext()) {
Object v1 = v10_1.next();
if(v5.length() > 0) {
v5.append("&");
}

v5.append(((Map$Entry)v1).getKey());
v5.append("=");
v5.append(((Map$Entry)v1).getValue());
}

String v9 = v5.toString().replace("*", "%2A").replace("%7E", "~").replace("+", "%20");
crack.log(v9);
String v6 = MD5.md5(v9); //下断点切入点
crack.log(v6);
v9 = v6 + "1fa50ba25ed527f3fd1eb9467686f2bb" + arg15;
crack.log(v9);
String v4 = MD5.md5(v9); //下断点切入点
crack.log(v4);
return v4;
}

如果分析起来很麻烦,逆向思维,从下往上找,从结果找开始

String v4 = MD5.md5(v9);

v9 = v6 + "1fa50ba25ed527f3fd1eb9467686f2bb" + arg15;

String v6 = MD5.md5(v9);String arg15

String v9 = v5.toString().replace("*", "%2A").replace("%7E", "~").replace("+", "%20");

1
2
3
4
5
6
7
8
9
10
11
12
StringBuilder v5 = new StringBuilder();
Iterator v10_1 = v8.entrySet().iterator(); // iterator迭代器
while(v10_1.hasNext()) {
Object v1 = v10_1.next();
if(v5.length() > 0) {
v5.append("&");
}

v5.append(((Map$Entry)v1).getKey());
v5.append("=");
v5.append(((Map$Entry)v1).getValue());
}

这串代码,大概就是把

{x:1,y:2,z:3}

变为

x=1&y=2&z=3

结果(例如):

v5 = “x=1&y=2&z=3”

v9 = (v5).toString()

v6 = md5(v9)

v9 = v6 + “1fa50ba25ed527f3fd1eb9467686f2bb” + arg15

v4 = md5(md5(v9) + “1fa50ba25ed527f3fd1eb9467686f2bb” + arg15)

然后结合断点,看加密前和加密后的样子,就可以了,不用真的去找参数

4.b

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
public class b {
private static b a;

static {
b.a = null;
}

public b() {
super();
}

public static b a() {
if(b.a == null) {
Class v1 = b.class;
__monitor_enter(v1);
try {
if(b.a == null) {
b.a = new b();
}

__monitor_exit(v1);
}
catch(Throwable v0) {
try {
label_13:
__monitor_exit(v1);
}
catch(Throwable v0) {
goto label_13;
}

throw v0;
}
}

return b.a;
}

总结:

arg7.getURLHashMap()就是对arg7内容进行哈希加密

arg7 目前由以下构成:

device_id + PhoneInfoUtils.getDeviceId(arg8) + clientid + 1 + ip + AppUtil.getLocalIP() + siteid + 10001 + system_name + android + type + android

以上字段加密后 + 时间戳v0 + “” 就是完整字段

然后由b.a()处理,得出sign

然后结合断点,看加密前和加密后的样子,就可以了,不用真的去找参数

下断点开始调试

a.()里存在两个md5,下断点查看md5前后的值

image-20220425144216835

点击进入下一个断点

image-20220425144409768

这两个断点都是关于v9的,所以看v9的值就好

又因为v9是string类型,当出现以下这个界面时,只要把type改为string就好,

image-20220425144534582

得到account=2771773446%40qq.com&clientid=1&device_id=865166029891887&ip=172.16.2.15&modules=cloudlogin%3A1&password=abc123456&siteid=10001&system_name=android&type=android

然后跳过两次,查看v6的值

v6:20655d14e9879f20d1c68abc51b8d34b

然后直接跳过下一个断点

因为v9刚刚已经改成string类型,可以直接查看内容

20655d14e9879f20d1c68abc51b8d34b1fa50ba25ed527f3fd1eb9467686f2bb1650868912338

这一串1fa50ba25ed527f3fd1eb9467686f2bb1650868912338是后边加的东西

1650868912338就是传入的值(arg15)

然后就是查看v4的值,可以用终端输入readvar v4 string

445bed8c9b9a4bab252c255510233869

这个就是返回的值,跟上边分析的一样。

验证一下,于是网上把字符串md5加密了一下:

image-20220425150235953

学一下log输出(smile插桩)(略)

1.将classes.dexclasses2.dex提出来,用apk助手反编译

然后就是要去找到函数所在的类,也就是路径,去用工具输出结果

image-20220425153059885

image-20220425153113537

做好准备工作后, 用apk助手重打包dex,将dex放回apk中,这里不会改变签名。