[JavaScript] 纯文本查看 复制代码 {
"a1" : "1.2" , # 加密版本
"a2" : new Date().valueOf() - serverTimeDiff, # 加密过程中用到的时间戳. 这次服主变坏了, 时间戳需要减去一个 serverTimeDiff(见a3) !
"a3" : "这是把xxx信息加密后提交给服务器, 服主校验成功后返回的一个dfpId" , # dfpId. 服务器返回的dfpId数据包里, 有一个serverTimestamp字段. serverTimeDiff = serverTimestamp - Date.now()
"a4" : "一个长48位的加密结果" , # a5, a2以及一小段jsvmp运行后, 输出a4
"a5" : "一个长320位的加密结果" , # a2, a6, 以及下面的Ln, 计算后输出a5
"a6" : "w1.2xxxxx这一段长512xxxxxxx" , # w1.2 + 客户端环境的加密结果
"a7" : wx[ "getAccountInfoSync" ]().miniProgram.appId, # 小程序id
"x0" : 3, # 源代码写死
"d1" : md5ToHex(j) # a1, a2, a3, a4, a7以及上面加密过程中出现的一些数组, 经过运算后, 输出d1
}
Ln = {
"b1" : {appId: "小程序id" , envVersion: "release" , version: "微信版本号" },
"b2" : "一个url" ,
"b6" : "微信的openId" , # 这个玩意儿可以考虑置空
"b7" : Math.floor(Date.now() / 1e3),
"b8" : "17" # 不重要, 1-20给个随机值就行
}
|
PS: 基于某评微信小程序的guard.js文件, 且文件经过简单的ast脱混淆.
1. 收集的环境[JavaScript] 纯文本查看 复制代码 Ne = {
DFP: [ "app" , "dfpid" , "filetime" , "fpv" , "localid" , "system" , "timestamp" , "ext" , "sessionId" ],
system: [ "accelerometer" , "albumAuthorized" , "BatteryInfo" , "batteryLevel" , "Beacons" , "benchmarkLevel" , "bluetoothEnabled" , "brand" , "brightness" , "cameraAuthorized" , "compass" , "deviceOrientation" , "devicePixelRatio" , "enableDebug" , "errMsg" , "fontSizeSetting" , "language" , "LaunchOptionsSync" , "locationAuthorized" , "locationEnabled" , "locationReducedAccuracy" , "microphoneAuthorized" , "model" , "networkType" , "notificationAlertAuthorized" , "notificationAuthorized" , "notificationBadgeAuthorized" , "notificationSoundAuthorized" , "pixelRatio" , "platform" , "safeArea" , "screenHeight" , "screenTop" , "screenWidth" , "SDKVersion" , "statusBarHeight" , "system" , "version" , "wifiEnabled" , "WifiInfo" , "windowHeight" , "windowWidth" ],
BatteryInfo: [ "errMsg" , "isCharging" , "level" ],
safeArea: [ "left" , "right" , "top" , "bottom" , "width" , "height" ],
WifiInfo: [ "SSID" , "BSSID" , "autoJoined" , "signalStrength" , "justJoined" , "secure" , "frequency" ]
}
|
1.1 环境加密逻辑(a6). 主要是找到收集了哪些环境, 以及环境对应的值.
a6
加密函数中只有常见的加密运算符, 没有检测环境的异常分支或其他坑. 所以逆向中遇到的加密函数直接 复制粘贴到自己的代码里就好. 譬如:
[JavaScript] 纯文本查看 复制代码 vn = {
gzipSync: R,
compressSync: R,
strToU8: function (e, n) {
var a = e.length;
if (!n && "undefined" != typeof TextEncoder) return new TextEncoder().encode(e);
for ( var t = new Je(e.length + (e.length >>> 1)), c = 0, r = function (e) {
t[c++] = e;
}, f = 0; f < a; ++f) {
if (c + 5 > t.length) {
var o = new Je(c + 8 + (a - f << 1));
o.set(t), t = o;
}
128 > (o = e.charCodeAt(f)) || n ? r(o) : 2048 > o ? (r(192 | o >>> 6), r(128 | 63 & o)) : 55295 < o && 57344 > o ? (r(240 | (o = 65536 + (1047552 & o) | 1023 & e.charCodeAt(++f)) >>> 18), r(128 | o >>> 12 & 63), r(128 | o >>> 6 & 63), r(128 | 63 & o)) : (r(224 | o >>> 12), r(128 | o >>> 6 & 63), r(128 | 63 & o));
}
return nn(t, 0, c);
}
};
function R(e, n) {
void 0 === n && (n = {});
var a = pn(),
t = e.length;
a.p(e);
var c = (e = ln(e, n, 10 + (n.filename && n.filename.length + 1 || 0), 8)).length,
r = n;
if (n = r.filename, e[0] = 31, e[1] = 139, e[2] = 8, e[8] = 2 > r.level ? 4 : 9 == r.level ? 2 : 0, e[9] = 3, 0 != r.mtime && gn(e, 4, Math.floor( new Date(r.mtime || Date.now()) / 1e3)), n) for (e[3] = 8, r = 0; r <= n.length; ++r) e[r + 10] = n.charCodeAt(r);
return gn(e, c - 8, a.d()), gn(e, c - 4, t), e;
}
gn = function (e, n, a) {
for (; a; ++n) e[n] = a, a >>>= 8;
},
function J(e) {
function n() {
for ( var e, n = [ "xxxxxxxxxxxxxxxxxxxxxxxxxx" , "xxxxxxxxxxxxxxxxxxxxxxxxxx" ], a = [], c = 0; c < n[ "length" ]; c++) {
e = "" ;
for ( var r = n[c], f = r[ "length" ], o = parseInt( "0x" + r[ "substr" ](0, 2)), d = 2; d < f; d += 2) {
var i = parseInt( "0x" + r[ "charAt" ](d) + r[ "charAt" ](d + 1));
e += String[ "fromCharCode" ](i ^ o);
}
a[ "push" ](e);
}
return a;
}
var a = ke[ "codec" ][ "utf8String" ][ "toBits" ](n()[0]),
c = ke[ "codec" ][ "utf8String" ][ "toBits" ](n()[1]);
return a = new ke[ "cipher" ][ "aes" ](a), e = ke[ "mode" ][ "cbc" ][ "encrypt" ](a, e, c), ke[ "codec" ][ "base64" ][ "fromBits" ](e);
}
|
2. a2-a8加密前的准备工作.
ready
2.1 a5, a4的加密逻辑(包含两段简单的jsvmp代码, 相对于mtgsig1.1的jsvmp代码, 服主很可能还在练手).
a5, a4
代码中调用的函数也都是简单的运算操作. 例:
[JavaScript] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 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 | Qn = function () {
for ( var n, a, c = 256, r = []; c--; r[c] = n >>> 0) for (a = 8, n = c; a--;) n = 1 & n ? n >>> 1 ^ 3988292384 : n >>> 1;
return function (n) {
if ( "string" == e(n)) {
for ( var a = 0, c = -1; a < n[ "length" ]; ++a) c = r[255 & c ^ n[ "charCodeAt" ](a)] ^ c >>> 8;
return 306674911 ^ c;
}
for (a = 0, c = -1; a < n[ "length" ]; ++a) c = r[255 & c ^ n[a]] ^ c >>> 8;
return 306674911 ^ c;
};
}();
function Z(e) {
var n = [];
return n[0] = e >>> 24 & 255, n[1] = e >>> 16 & 255, n[2] = e >>> 8 & 255, n[3] = 255 & e, n;
}
function X(e) {
for ( var n = [], a = 0; a < e[ "length" ]; a += 2) {
var c = e[ "charAt" ](a) + e[ "charAt" ](a + 1);
c = parseInt(c, 16), n[ "push" ](c);
}
return n;
}
function W(e) {
e = encodeURIComponent(e);
for ( var n = [], a = 0; a < e[ "length" ]; a++) {
var c = e[ "charAt" ](a);
"%" === c ? (c = e[ "charAt" ](a + 1) + e[ "charAt" ](a + 2), c = parseInt(c, 16), n[ "push" ](c), a += 2) : n[ "push" ](c[ "charCodeAt" ](0));
}
return n;
}
function ae(e, n) {
var a = e[ "length" ];
n ^= a;
for ( var c = 0; 4 <= a;) {
var r = 1540483477 * (65535 & (r = 255 & e[c] | (255 & e[++c]) << 8 | (255 & e[++c]) << 16 | (255 & e[++c]) << 24)) + ((1540483477 * (r >>> 16) & 65535) << 16);
n = 1540483477 * (65535 & n) + ((1540483477 * (n >>> 16) & 65535) << 16) ^ (r = 1540483477 * (65535 & (r ^= r >>> 24)) + ((1540483477 * (r >>> 16) & 65535) << 16)), a -= 4, ++c;
}
switch (a) {
case 3:
n ^= (255 & e[c + 2]) << 16;
case 2:
n ^= (255 & e[c + 1]) << 8;
case 1:
n = 1540483477 * (65535 & (n ^= 255 & e[c])) + ((1540483477 * (n >>> 16) & 65535) << 16);
}
return ((n = 1540483477 * (65535 & (n ^= n >>> 13)) + ((1540483477 * (n >>> 16) & 65535) << 16)) ^ n >>> 15) >>> 0 ^ 1540483477;
}
|
2.2 d1, 以及最终mtgsig赋值
d1, mtgsig
|