微信小程序云函数主动调用

微信小程序云函数主动调用

还是以泡泡玛特为例,小程序使用了云函数,普通抓包根本获取不到有价值的内容,顶多能抓到与微信服务器之间的mmtls流量。前面的一篇文章中,成功的使用了hook的方式获取到了通信数据,一般可以通过修改请求数据实现调用小程序API的目的,有没有方法直接发送数据包调用小程序API?

调试的过程中踩了一些坑,因为在android环境中,小程序与微信是两个独立的进程…

微信版本: 8.0.37

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
package gr0;

import ad0.c;
import ad0.y;
import com.tencent.mm.network.n;
import com.tencent.mm.network.u;
import com.tencent.mm.sdk.platformtools.Log;
import gl3.b;
import kl3.no2;
import kl3.qc5;

public class g extends y implements n {
public interface a {
void a(int arg1, int arg2, String arg3, y arg4);
}

public final c d;
public ad0.n e;
public a f;

public g(String s, String s1, String s2, int v, int v1, int v2, int v3, boolean z, String s3, int v4, boolean z1) {
Log.i("MicroMsg.webview.NetSceneJSOperateWxData", "<init> hash[%d] appId [%s], data [%s], grantScope [%s], versionType [%d], opt [%d], extScene [%d] sessionId [%s] avatarOpt [%d]", new Object[]{((int)this.hashCode()), s, s1, s2, v, v2, v3, s3, v4});
c c0 = this.i1(((boolean)(((int)z)))).a();
this.d = c0;
no2 no20 = (no2)c0.a.a;
no20.d = s;
no20.e = new b((s1.getBytes() == null ? new byte[0] : s1.getBytes()));
no20.f = s2;
no20.h = v;
no20.g = v2;
no20.j = v1;
no20.o = v4;
no20.n = s3;
no20.p = z1;
if(v3 > 0) {
qc5 qc50 = new qc5();
no20.i = qc50;
qc50.e = v3;
}
}

@Override // ad0.y
public int doScene(com.tencent.mm.network.g g0, ad0.n n0) {
Log.i("MicroMsg.webview.NetSceneJSOperateWxData", "doScene hash=%d, funcid=%d", new Object[]{((int)this.hashCode()), ((int)this.d.d)});
this.e = n0;
return this.dispatch(g0, this.d, this);
}

@Override // ad0.y
public int getType() {
return 0x46D;
}

public ad0.c.b i1(boolean z) {
return h.a(((boolean)(((int)z))));
}

@Override // com.tencent.mm.network.n
public void onGYNetEnd(int v, int v1, int v2, String s, u u0, byte[] arr_b) {
Log.i("MicroMsg.webview.NetSceneJSOperateWxData", "onGYNetEnd, hash[%d] errType = %d, errCode = %d, errMsg = %s", new Object[]{((int)this.hashCode()), v1, v2, s});
ad0.n n0 = this.e;
if(n0 != null) {
n0.onSceneEnd(v1, v2, s, this);
}

a g$a0 = this.f;
if(g$a0 != null) {
g$a0.a(v1, v2, s, this);
}
}
}


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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package com.tencent.mm.plugin.appbrand.jsapi.auth;


public final class JsApiOperateWXData extends q {
static class OperateWXDataTask extends MainProcessTask implements a {
public interface f {
}


com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a jsApiOperateWXData$OperateWXDataTask$a0 = new f() {
public void a(String s, int v) {
Log.e("MicroMsg.AppBrand.JsApiOperateWXData", "onFailure !");
OperateWXDataTask.this.z = "fail:" + s;
OperateWXDataTask.this.A = v;
OperateWXDataTask.this.a();
}
};
if(this.j.equals("operateWXData")) {
this.m(this.y, // s:java.lang.String
this.n, // s1:java.lang.String
"", // s2:java.lang.String
this.q, // v:int
this.r, // v1:int
0, // v2:int
jsApiOperateWXData$OperateWXDataTask$a0, // jsApiOperateWXData$OperateWXDataTask$f0:com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData$OperateWXDataTask$f
this.T, // z:boolean
this.t // z1:boolean
);
return;
}

if(this.j.equals("operateWXDataConfirm")) {
this.m(this.y, // s:java.lang.String
this.n, // s1:java.lang.String
this.D, // s2:java.lang.String
this.q, // v:int
this.r, // v1:int
this.s, // v2:int
jsApiOperateWXData$OperateWXDataTask$a0, // jsApiOperateWXData$OperateWXDataTask$f0:com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData$OperateWXDataTask$f
this.T, // z:boolean
this.t // z1:boolean
);
}
}


public void m(String s, String s1, String s2, int v, int v1, int v2, f jsApiOperateWXData$OperateWXDataTask$f0, boolean z, boolean z1) {
gr0.f f0;
if(z) {
f0 = new gr0.f(s, // s:java.lang.String
s1, // s1:java.lang.String
s2, // s2:java.lang.String
v, // v:int
v2, // v1:int
v1, // v2:int
this.R, // v3:int
this.v, // s3:java.lang.String
this.u, // v4:int
z1, // z:boolean
(int v, int v1, String s, g g0) -> {
OperateWXDataTask jsApiOperateWXData$OperateWXDataTask1;
OperateWXDataTask jsApiOperateWXData$OperateWXDataTask0 = OperateWXDataTask.this;
g g1 = g0;
if(jsApiOperateWXData$OperateWXDataTask0.V) {
jsApiOperateWXData$OperateWXDataTask0.y0 = Util.nowMilliSecond();
}
else {
jsApiOperateWXData$OperateWXDataTask0.p0 = Util.nowMilliSecond();
}

if(v == 0 && v1 == 0) {
}

((com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a)this.b).a(String.format("cgi fail(%d,%d)", v, v1), 0);
} // g$a0:gr0.g$a
);
}
else {
int v3 = this.R;
boolean z2 = this.U;
String s3 = this.v;
int v4 = this.u;
com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.d jsApiOperateWXData$OperateWXDataTask$d0 = (int v, int v1, String s, g g0) -> {
OperateWXDataTask jsApiOperateWXData$OperateWXDataTask1;
OperateWXDataTask jsApiOperateWXData$OperateWXDataTask0 = OperateWXDataTask.this;
g g1 = g0;
if(jsApiOperateWXData$OperateWXDataTask0.V) {
jsApiOperateWXData$OperateWXDataTask0.y0 = Util.nowMilliSecond();
}
else {
jsApiOperateWXData$OperateWXDataTask0.p0 = Util.nowMilliSecond();
}

if(v == 0 && v1 == 0) {
if(g1 != null) {
if(jsApiOperateWXData$OperateWXDataTask0.r == 2) {
return;
}

oo2 oo20 = g1.d == null ? null : ((oo2)g1.d.b.a);
kn2 kn20 = oo20.d;
if(kn20 == null) {
((com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a)this.b).a("cgi fail response null", 0);
return;
}

int v2 = kn20.d;
String s2 = kn20.e;
l24 l240 = oo20.f;
LinkedList linkedList0 = new LinkedList();
if(l240 != null) {
linkedList0.add(l240);
}

String s3 = oo20.g;
String s4 = oo20.h;
String s5 = "";


if(v2 == 0) {
gl3.b b0 = oo20.e;
if(b0 == null) {
((com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a)this.b).a("internal error", v2);
return;
}

String s8 = b0.h();
com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a jsApiOperateWXData$OperateWXDataTask$a1 = (com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a)this.b;
jsApiOperateWXData$OperateWXDataTask$a1.getClass();
try {
OperateWXDataTask.this.p = z94.h.h(new String[]{OperateWXDataTask.this.y, OperateWXDataTask.this.S + "", OperateWXDataTask.this.i + "", Util.currentTicks() + ""}, "$");
OperateWXDataTask.R0.putString(OperateWXDataTask.this.p, s8).commit();
if(TextUtils.isEmpty(OperateWXDataTask.R0.getString(OperateWXDataTask.this.p, null))) {
throw new IOException("write data failed");
}

d.e.idkeyStat(1063L, 0L, 1L, false);
}
catch(Throwable throwable0) {
goto label_247;
}

if(TextUtils.isEmpty(OperateWXDataTask.this.p)) {
OperateWXDataTask.this.o = s8;
OperateWXDataTask.this.z = "ok";
OperateWXDataTask.this.a();
return;
try {
throw new IOException("write data failed");
}
catch(Throwable throwable0) {
}

try {
label_247:
Log.e("MicroMsg.AppBrand.JsApiOperateWXData", "runInMainProcess::onSuccess, write to XProcessStore failed, appId[%s], callbackId[%d] e=%s", new Object[]{OperateWXDataTask.this.y, ((int)OperateWXDataTask.this.i), throwable0});
OperateWXDataTask.this.p = null;
d.e.idkeyStat(1063L, 1L, 1L, false);
goto label_278;
}
catch(Throwable throwable1) {
}

if(TextUtils.isEmpty(OperateWXDataTask.this.p)) {
OperateWXDataTask.this.o = s8;
}

throw throwable1;
label_278:
if(TextUtils.isEmpty(OperateWXDataTask.this.p)) {
OperateWXDataTask.this.o = s8;
}
}

OperateWXDataTask.this.z = "ok";
OperateWXDataTask.this.a();
return;
}

Log.e("MicroMsg.AppBrand.JsApiOperateWXData", "onSceneEnd NetSceneJSOperateWxData Failed %s", new Object[]{s2});
((com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a)this.b).a(s2, v2);
}

return;
}

((com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.a)this.b).a(String.format("cgi fail(%d,%d)", v, v1), 0);
};
f0 = new g(s, // s:java.lang.String
s1, // s1:java.lang.String
s2, // s2:java.lang.String
v, // v:int
v2, // v1:int
v1, // v2:int
v3, // v3:int
((boolean)(((int)z2))), // z:boolean
s3, // s3:java.lang.String
v4, // v4:int
z1 // z1:boolean
);
f0.f = jsApiOperateWXData$OperateWXDataTask$d0; // 构建数据包
}

int v5 = this.S;
no2 no20 = (no2)f0.d.a.a;
if(no20.i == null) {
no20.i = new qc5();
}

no20.i.f = v5;
a0.d().f(f0); // 发送数据包

public class com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.d implements gr0.g.a {
public com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.d(String s, f jsApiOperateWXData$OperateWXDataTask$f0) {
}

@Override // gr0.g$a
public void a(int v, int v1, String s, ad0.y y0) {
OperateWXDataTask.this.l(v, v1, s, ((g)y0), this.a, this.b);
}
}


public class com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.e implements gr0.g.a {
public com.tencent.mm.plugin.appbrand.jsapi.auth.JsApiOperateWXData.OperateWXDataTask.e(String s, f jsApiOperateWXData$OperateWXDataTask$f0) {
}

@Override // gr0.g$a
public void a(int v, int v1, String s, ad0.y y0) {
OperateWXDataTask.this.l(v, v1, s, ((g)y0), this.a, this.b);
}
}

}

}


image-20240509215518053

以上的代码中,最关键的部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
f0 = new g(s,         // s:java.lang.String
s1, // s1:java.lang.String
s2, // s2:java.lang.String
v, // v:int
v2, // v1:int
v1, // v2:int
v3, // v3:int
((boolean)(((int)z2))), // z:boolean
s3, // s3:java.lang.String
v4, // v4:int
z1 // z1:boolean
);
f0.f = jsApiOperateWXData$OperateWXDataTask$d0; // 构建数据包
}

int v5 = this.S;
no2 no20 = (no2)f0.d.a.a;
if(no20.i == null) {
no20.i = new qc5();
}

no20.i.f = v5;
a0.d().f(f0); // 发送数据包

编写一个xposed模块,开启http服务,接收参数后创建对象(new gr0.g()), 然后调用a0.d().f(f0)发送。并hook gr0.g.onGYNetEnd获取返回结果。

1
2
3
4
5
6
7
Class class_g = XposedHelpers.findClass("gr0.g", classLoader);
Class class_a0 = XposedHelpers.findClass("m50.a0", classLoader);
Class class_b0 = XposedHelpers.findClass("ad0.b0", classLoader);

Object objcet_f0 = newInstance(class_g, appid, data, scope, 0, 0, 0, callid, true, sessionid, avatarOpt, false);
Object objcet_b0 = callStaticMethod(class_a0, "d");
callMethod(objcet_b0, "f", objcet_f0);
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
XposedHelpers.findAndHookMethod("gr0.g", classLoader, "onGYNetEnd", int.class,int.class,int.class,"java.lang.String","com.tencent.mm.network.u",byte[].class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object thiz = param.thisObject;

Class class_gr0_g = findClass("gr0.g", classLoader);
Field g_field = class_gr0_g.getDeclaredField("d");

Class class_ad0_c = findClass("ad0.c", classLoader);
Field c_field = class_ad0_c.getDeclaredField("b");

Class class_ad0_c_d = findClass("ad0.c$d", classLoader);
Field a_field = class_ad0_c_d.getDeclaredField("a");

Class class_oo2 = findClass("kl3.oo2", classLoader);
Field field = class_oo2.getField("e");

Class class_gl3_b = findClass("gl3.b", classLoader);
Method method = class_gl3_b.getDeclaredMethod("h");
Object object_c = g_field.get(thiz);
Object object_ad0_c_d = c_field.get(object_c);
Object object_a = a_field.get(object_ad0_c_d);
Object b0 = field.get(object_a);
String resp = (String) method.invoke(b0);
Log.d("CALL_SERVER", "onGYNetEnd: " + resp);



}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});