一
前言
url: aHR0cHM6Ly93d3cuc291dGh3ZXN0LmNvbS8=
二
jsvmp
C++:
void funcAdd(a, b){
return a+b;
}asm:
.text:0000000140001000 sub_140001000 proc near ; CODE XREF: sub_140001020+E↓p
.text:0000000140001000 ; sub_140001020+21↓p
.text:0000000140001000
.text:0000000140001000 arg_0 = dword ptr 8
.text:0000000140001000 arg_8 = dword ptr 10h
.text:0000000140001000
.text:0000000140001000 mov [rsp+arg_8], edx
.text:0000000140001004 mov [rsp+arg_0], ecx
.text:0000000140001008 mov eax, [rsp+arg_8]
.text:000000014000100C mov ecx, [rsp+arg_0]
.text:0000000140001010 add ecx, eax
.text:0000000140001012 mov eax, ecx
.text:0000000140001014 retn
.text:0000000140001014 sub_140001000 endpvmp:
自己搞一个编译器,把汇编指令转为自定义指令,比如把+这个指令对应的add汇编指令搞成一个函数,然后里面各种弯弯绕。
自己维护一个函数的调用栈,变量栈。
上面几行汇编就在vmp这个虚拟机里跑成千上万条,那对逆向分析的人来说,就很难搞清楚这个成千上万到底跑了个啥。jsvmp:
与PC端vmp类似,也是把简单的指令复杂化,具体到Shape的+指令就对应于好几个函数
, function(c) {
c.x[c.x.length - 2] = c.x[c.x.length - 2] + c.x[c.x.length - 1]; //c.x就是局部变量栈
c.x.length -= 1
}
, function(c) {
var E = j[c.W];
var F = j[c.W + 1];
c.W += 2;
var T = c.y.c(E);
var a = T[F];
var i = c.x[c.x.length - 1];
c.x[c.x.length - 1] = i + a
}
其他各种运算符,比如- & | > < == ! 等等都是如此,对应于一个函数。这样做的目的就是可以自行维护一个函数调用栈和变量栈
三
处理jsvmp的思路
四
实战Shape
(obj.member=value) -> (66) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, Array(2),
{…}, {…}, {…}, {…}, {…}, {…}, Array(2), {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…},
{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}] 34 (2) [Array(0), Array(13)]
下面是收集信息的明文结果(这里贴的是我直接通过Ee30zvqlwf-A参数,反向解密取到的,因为Shape是一边序列化一边加密的,所以是断不到明文瞬间的。我这里用反向解密拿到)
解密成员:29
Binary size: 308
35 2E 30 20 28 57 69 6E 64 6F 77 73 20 4E 54 20 53 46 48 32 40 87 105 110 100 111 119 115 32 78 84 32 5.0.(Windows.NT.
31 30 2E 30 3B 20 57 69 6E 36 34 3B 20 78 36 34 49 48 46 48 59 32 87 105 110 54 52 59 32 120 54 52 10.0;.Win64;.x64
29 20 41 70 70 6C 65 57 65 62 4B 69 74 2F 35 33 41 32 65 112 112 108 101 87 101 98 75 105 116 47 53 51 ).AppleWebKit/53
37 2E 33 36 20 28 4B 48 54 4D 4C 2C 20 6C 69 6B 55 46 51 54 32 40 75 72 84 77 76 44 32 108 105 107 7.36.(KHTML,.lik
65 20 47 65 63 6B 6F 29 20 43 68 72 6F 6D 65 2F 101 32 71 101 99 107 111 41 32 67 104 114 111 109 101 47 e.Gecko).Chrome/
31 32 32 2E 30 2E 30 2E 30 20 53 61 66 61 72 69 49 50 50 46 48 46 48 46 48 32 83 97 102 97 114 105 122.0.0.0.Safari
2F 35 33 37 2E 33 36 00 84 32 30 30 33 30 31 30 47 53 51 55 46 51 54 0 132 50 48 48 51 48 49 48 /537.36..2003010
37 00 47 65 63 6B 6F 00 37 1F 88 28 03 4D 6F 7A 55 0 71 101 99 107 111 0 55 31 136 40 3 77 111 122 7.Gecko.7..(.Moz
69 6C 6C 61 00 00 80 00 00 00 00 00 00 F8 3F 18 105 108 108 97 0 0 128 0 0 0 0 0 0 248 63 24 illa..........?.
39 23 18 93 31 2F 4E 65 74 73 63 61 70 65 00 3C 57 35 24 147 49 47 78 101 116 115 99 97 112 101 0 60 9#..1/Netscape.<
0B 47 6F 6F 67 6C 65 20 49 6E 63 2E 00 20 2D 20 11 71 111 111 103 108 101 32 73 110 99 46 0 32 45 32 .Google.Inc...-.
50 38 2B 20 50 4D 6F 7A 69 6C 6C 61 2F 35 2E 30 80 56 43 32 80 77 111 122 105 108 108 97 47 53 46 48 P8+.PMozilla/5.0
20 28 57 69 6E 64 6F 77 73 20 4E 54 20 31 30 2E 32 40 87 105 110 100 111 119 115 32 78 84 32 49 48 46 .(Windows.NT.10.
30 3B 20 57 69 6E 36 34 3B 20 78 36 34 29 20 41 48 59 32 87 105 110 54 52 59 32 120 54 52 41 32 65 0;.Win64;.x64).A
70 70 6C 65 57 65 62 4B 69 74 2F 35 33 37 2E 33 112 112 108 101 87 101 98 75 105 116 47 53 51 55 46 51 ppleWebKit/537.3
36 20 28 4B 48 54 4D 4C 2C 20 6C 69 6B 65 20 47 54 32 40 75 72 84 77 76 44 32 108 105 107 101 32 71 6.(KHTML,.like.G
65 63 6B 6F 29 20 43 68 72 6F 6D 65 2F 31 32 32 101 99 107 111 41 32 67 104 114 111 109 101 47 49 50 50 ecko).Chrome/122
2E 30 2E 30 2E 30 20 53 61 66 61 72 69 2F 35 33 46 48 46 48 46 48 32 83 97 102 97 114 105 47 53 51 .0.0.0.Safari/53
37 2E 33 36 00 57 69 6E 33 32 00 22 2F A0 01 07 55 46 51 54 0 87 105 110 51 50 0 34 47 160 1 7 7.36.Win32."/...
14 00 A5 01 20 0 165 1 ....这个成员在收集的65个成员里占到第29位,当然这个到底占数组哪个位置不是固定的!
这也是Shape最难处理的地方,不同时段获取到的Shape.js对应的这个占位是不同的!
跟code流直接相关。意味着必须把code跑一遍才能拿到这个位置。收集过程可以打日志分析函数调用取到
(call) -> 45170 Arguments(3) ['5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.…KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36', Array(4), 3, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['20030107', Array(109), 108, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['Gecko', Array(118), 117, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 1028, Array(124), 123, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, -21334, Array(127), 126, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['Mozilla', Array(130), 129, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['', Array(138), 137, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 1.5, Array(139), 138, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 24, Array(148), 147, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 27, Array(149), 148, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 24, Array(150), 149, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 159, Array(152), 151, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['Netscape', Array(154), 153, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, -21334, Array(163), 162, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['Google Inc.', Array(166), 165, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 1440, Array(178), 177, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 2560, Array(180), 179, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 1400, Array(182), 181, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 2560, Array(184), 183, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36', Array(186), 185, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 45170 Arguments(3) ['Win32', Array(298), 297, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 1515, Array(304), 303, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 20, Array(309), 308, callee: (...), Symbol(Symbol.iterator): ƒ]
(call) -> 68549 Arguments(4) [ƒ, 0, Array(310), 309, callee: (...), Symbol(Symbol.iterator): ƒ]上面每一次函数call。都会把字符串或者其他类型数字序列化为字节集,这个时候就直接进行异或加密了。最终取到一个加密后的字节集
[35, 73, 182, 48, 124, 183, 46, 145, 161, 62, 250, 241, 195, 207, 25, 135, 17, 139, 212, 207, 240, 106, 59, 222, 246, 54, 55, 207,
3, 188, 64, 9, 71, 111, 178, 37, 183, 163, 194, 142, 193, 236, 143, 68, 199, 4, 150, 174, 243, 184, 245, 139, 123, 139, 242, 254,
161, 52, 53, 91, 198, 227, 165, 104, 86, 14, 163, 81, 77, 91, 255, 254, 69, 174, 12, 63, 45, 21, 148, 34, 121, 161, 38, 11, 226,
216, 52, 222, 4, 98, 22, 20, 52, 185, 150, 169, 205, 214, 3, 105, 95, 33, 238, 41, 35, 86, 32, 98, 129, 103, 254, 216, 228, 214,
159, 8, 80, 95, 218, 39, 74, 59, 233, 41, 34, 62, 234, 131, 152, 161, 113, 235, 197, 58, 105, 142, 184, 112, 195, 125, 99, 6, 229,
227, 248, 134, 54, 147, 17, 38, 159, 222, 44, 249, 78, 108, 233, 2, 155, 172, 26, 65, 192, 154, 78, 150, 144, 31, 205, 140, 229,
157, 23, 183, 32, 237, 214, 122, 127, 223, 53, 169, 175, 171, 181, 198, 25, 149, 150, 233, 30, 41, 224, 120, 114, 193, 216, 164,
184, 47, 196, 45, 207, 76, 85, 45, 165, 229, 224, 204, 233, 250, 70, 99, 191, 171, 225, 120, 162, 111, 231, 254, 193, 174, 1, 241,
37, 38, 16, 55, 89, 238, 28, 47, 58, 183, 169, 162, 45, 130, 127, 163, 95, 26, 66, 198, 137, 183, 102, 173, 55, 77, 203, 101, 100,
164, 131, 53, 161, 146, 137, 83, 153, 250, 173, 189, 242, 79, 146, 78, 212, 85, 144, 228, 238, 169, 93, 19, 154, 107, 54, 49, 51,
214, 120, 233, 129, 254, 31, 118, 15, 157, 149, 113, 4, 157, 129, 125, 168, 81, 23, 239, 253, 37, 101, 89, 119, 197, 31, 31, 61,
48]因为是异或加密的结果,而且异或加密使用了随机数作为起始算子,所以这个字节集的结果不是固定的。
这里的关键就是Shape直接边序列化变进行了异或加密。分析这里真的废键盘!
//t就是编码表 Shape是js里自带的
function VariantBase64(str,t) {
var len = str.length;
var r = new Uint8Array(Math.floor(len * 3 / 4));
var m1, m2, m3, m4, k1, k2, k3;
for (var i = 0, j = 0; i < len; i += 4, j += 3) {
m1 = t.indexOf(str[i]);
m2 = t.indexOf(str[i + 1]);
m3 = t.indexOf(str[i + 2]);
m4 = t.indexOf(str[i + 3]);
k1 = m1 << 2 | m2 >> 4;
k2 = (m2 & 15) << 4 | m3 >> 2;
k3 = (m3 & 3) << 6 | m4;
r[j] = k1;
if (i + 2 < len) {
r[j + 1] = k2
}
if (i + 3 < len) {
r[j + 2] = k3
}
}
return r
}
a: 收集的浏览器信息加密的 b: 参数f+参数a的校验
c: code里字符串解密跑出来的
"LqUN19-tNV_7vDBqS3BjTwImSWByl9bgefykao7k2F7_PcfDTk8bWGEkCs63HonbNBwcao9mMxGoqGUH0X7iyZx6jgn6umUPuysJU0Df-Es8mzMYSJKzjd6xV_k,306"
:"AEBwWCuOAQAAIDGyOzYDrlXg7UWJqv7slOCdALh1laeWUHYLsA_5IphsAz9I"d: code里字符串解密跑出来的
qZEp4vGadEbZjgpzMEtMYCQXWVdjxZiFT824Upytvz2FWqfKHDQ6Z3hMCqqXGt7XJERkUb1mfk-cuxU-51TkxqMTriqPv0wB0wgoNzT0w2J7unIpdtHp7-mnJtkHZiK605vjebwd5QDZU8Ydx4R11TCiiiheFmpwjB8BEu_31G9QCozrAJOV1iVMrgPVOSkeHOoQ4zpcOFTkR8Q,118
: "ABaAhIDBCKGFgQGAAYIQgISigaIAwBGAzvpizi_33wcP-SKYbAM_SP____-_HhmNAL5xVFHc5SurCp9zHqMVMDk"f: js里带的
五
补环境
我参考的B站教程:https://www.bilibili.com/video/BV11o4y1D7m6?p=37&vd_source=e8f93da27c5f30218e12cae3fb0ccd1b
六
展示
七
总结
看雪ID:rushmaster
https://bbs.kanxue.com/user-home-636891.htm
# 往期推荐
2、BFS Ekoparty 2022 Linux Kernel Exploitation Challenge
3、银狐样本分析
球分享
球点赞
球在看
点击阅读原文查看更多