环境
小程序名称:正弘+
微信版本:3.9.10.19
逆向工具:WeChatOpenDevTools
逆向分析
先通过小程序解包并查找关键字sha找到了sha256加密函数,再通过逆向工具wxdevtools,找到了加密位置。
其中主要代码为
l = c.default.SHA256(l),
o.sign = l,
参数l为多个小参数拼接而成,如
accessToken=***********&appKey=*****&appUid=****************&appVersion=3.2.40&clientAppName=memberClient&clientType=mini_weixin¤tPageType=user&customVersion=9&deviceId=*************************&extendCode=none&mallId=201&model=microsoft&osVersion=Windows 10 x64&programVersion=3.9.10&rnd=C4Ndc4QAeGsoHqiGJxRHp9mWZWC29a&sceneValue=1256&sdkVersion=3.3.5&sid=****************&source=mini_weixin×tamp=17220515630RU2DV7E67T7ZMPQXWAVD99MY
其中需要注意的字段有accessToken,appKey,appUid,deviceId,rnd,sid,timestamp
先假设accessToken,appKey,appUid,deviceId为固定值。
rnd:
rnd的生成函数为
function rndGenerate(e) {
for (var t = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], r = "", i = 0; i < e; i++) {
r += t[Math.ceil(Math.random() * (t.length - 1))]
}
return r
}
其中e传入的值为固定值30
sid:和appUid的值相同
timestamp:时间戳+一串字符串
时间戳生成代码:
Math.trunc((new Date).getTime() / 1e3)
注意到u.default.config.apiSign.wap_KEYS为一个数组,内容为
['N94QKAZD289GQARELPOJQGZM8', 'GFNCV79W9U1CYFEXQ904OI6BB', 'C1BOEMXCP1A5KUBVQIXKGBH51', '0RU2DV7E67T7ZMPQXWAVD99MY', 'EPOJKLVKIQQMGG9XWT9C28F5C', '8GTBBWEADC6RG237EUEC7KZFU', '1XP3TLH0BZMZS7TT3TF7JD500', 'TNFVOH7WHTC4NCD6SI9QZ3W5N', 'ZZNEL2ULF9TPAC9NU3493GL7I', '8SABWT2MB1JOHOM02QVN36TGI']
发现timestamp为
var a = Math.trunc((new Date).getTime() / 1e3);
timestamp = a + u.default.config.apiSign.wap_KEYS[a % 10];
至此,除假设为固定值字段外,其他参数都已经分析完毕,下面将实现如何生成加密参数l,代码如下
var l = `accessToken=${accessToken}&appKey=${appKey}&appUid=${appUid}&appVersion=3.2.40&clientAppName=memberClient&clientType=mini_weixin¤tPageType=user&customVersion=9&deviceId=${deviceId}&mallId=201&model=microsoft&osVersion=Windows 10 x64&programVersion=3.9.10&rnd=${rnd}&sceneValue=1256&sdkVersion=3.3.5&sid=${appUid}×tamp=${timestamp[0]}`;
var m = `accessToken=${accessToken}&appKey=${appKey}&appUid=${appUid}&appVersion=3.2.40&clientAppName=memberClient&clientType=mini_weixin¤tPageType=user&customVersion=9&deviceId=${deviceId}&mallId=201&model=microsoft&osVersion=Windows%2010%20x64&programVersion=3.9.10&rnd=${rnd}&sceneValue=1256&sdkVersion=3.3.5&sid=${appUid}×tamp=${timestamp[1]}`;
console.log(m+'&sign='+SHA256(l)+'&signType=sha');
需要注意的是,这里l和m的区别在于osVersion一个是Windows 10 x64,另一个是Windows%2010%20x64,l负责用于SHA256加密生成参数使用,m用于传入python中作为url使用,二者不能相同,否则会出现请求失败的情况。
难点分析
在进行requests的POST请求时,明明已经计算出了正确的sign值并拼接除了最终的url,返回的结果仍然是访问检查失败。
经过很久的分析仍然没有结果,于是下载了ApiFox,使用Fiddler对刚请求的POST进行抓取,并将结果放入ApiFox中进行接口请求,发现可以请求成功。

再看ApiFox中的实际请求中的Python请求代码,发现他的POST请求是这样写的
payload = "{\"isPayMemberLevelCalc\":1,\"mallId\":\"201\",\"memberId\":\"****************\",\"skuInfos\":[{\"shopId\":\"AOjIn8s8gjrCG5Hm\",\"skuId\":\"3605975038132\",\"count\":\"1\",\"unitPrice\":35500}],\"source\":\"onlineMarket\",\"tradeChannel\":\"1\",\"tradeTime\":1722162830}"
response = requests.request("POST", url, headers=headers, data=payload)
也可以写成
response = requests.post(url, headers=headers, data=payload)
我之前的代码中的POST请求为
response = requests.post(url, headers=headers, json=payload)
于是,把我的代码中的POST请求换成ApiFox的请求格式,发现可以请求成功。
至此,本次逆向结束。
请求返回代码记录
PUB-00000 (此为请求成功)
{"errorCode":"PUB-00000","errorMessage":"成功","errorCodeMsg":null,"extra":null,"display":true,"exception":null,"reqTime":1722060807,"costTime":2,"skipType":null,"serviceTime":1722060807,"skipParam":null,"traceId":"195-1722060807557","showTraceId":0,"version":6,"branch":"mobcb","body":{//此处省略},"encrypted":false,"cache":true}
PUB-00001
{"errorCode":"PUB-00001","errorMessage":"[118-1722060689574]系统繁忙","errorCodeMsg":null,"extra":null,"display":true,"exception":null,"reqTime":0,"costTime":0,"skipType":null,"serviceTime":1722060689,"skipParam":null,"traceId":"118-1722060689574","showTraceId":0,"version":6,"branch":"mobcb","body":null,"encrypted":false,"cache":false}
PUB-00006
{"errorCode":"PUB-00006","errorMessage":"[118-1722060712877]访问检查失败","errorCodeMsg":"PUB-00006","extra":null,"display":true,"exception":null,"reqTime":0,"costTime":0,"skipType":null,"serviceTime":1722060712,"skipParam":null,"traceId":"118-1722060712877","showTraceId":0,"version":6,"branch":"mobcb","body":null,"encrypted":false,"cache":false}
PUB-00012
{"errorCode":"PUB-00012","errorMessage":"APPKEY为空","errorCodeMsg":null,"extra":null,"display":true,"exception":null,"reqTime":0,"costTime":0,"skipType":null,"serviceTime":1722060522,"skipParam":null,"traceId":"118-1722060522758","showTraceId":0,"version":6,"branch":"mobcb","body":null,"encrypted":false,"cache":false}