js逆向

根据

保姆级教程—前端加密的对抗(附带靶场) - 先知社区

下了旧版本的jstools

当前数据包的修改(×)

利用js-forward

原理是通过http请求把未加密数据带到burp中自定义修改,然后放到镜像服务器加密后转发回原始服务器

改了一下脚本 burp监听8081

文章说由于cors策略 chrome会报错,这里直接edge

在覆盖中填入脚本生成的js语句

edge也报错cors了 试了一下但是没有解决

js-rpc

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
function Hlclient(wsURL) {
this.wsURL = wsURL;
this.handlers = {
_execjs: function (resolve, param) {
var res = eval(param)
if (!res) {
resolve("没有返回值")
} else {
resolve(res)
}

}
};
this.socket = undefined;
if (!wsURL) {
throw new Error('wsURL can not be empty!!')
}
this.connect()
}

Hlclient.prototype.connect = function () {
console.log('begin of connect to wsURL: ' + this.wsURL);
var _this = this;
try {
this.socket = new WebSocket(this.wsURL);
this.socket.onmessage = function (e) {
_this.handlerRequest(e.data)
}
} catch (e) {
console.log("connection failed,reconnect after 10s");
setTimeout(function () {
_this.connect()
}, 10000)
}
this.socket.onclose = function () {
console.log('rpc已关闭');
setTimeout(function () {
_this.connect()
}, 10000)
}
this.socket.addEventListener('open', (event) => {
console.log("rpc连接成功");
});
this.socket.addEventListener('error', (event) => {
console.error('rpc连接出错,请检查是否打开服务端:', event.error);
});

};
Hlclient.prototype.send = function (msg) {
this.socket.send(msg)
}

Hlclient.prototype.regAction = function (func_name, func) {
if (typeof func_name !== 'string') {
throw new Error("an func_name must be string");
}
if (typeof func !== 'function') {
throw new Error("must be function");
}
console.log("register func_name: " + func_name);
this.handlers[func_name] = func;
return true

}

//收到消息后这里处理,
Hlclient.prototype.handlerRequest = function (requestJson) {
var _this = this;
try {
var result = JSON.parse(requestJson)
} catch (error) {
console.log("请求信息解析错误", requestJson);
return
}
if (!result['action'] || !result["message_id"]) {
console.warn('没有方法或者消息id,不处理');
return
}
var action = result["action"], message_id = result["message_id"]
var theHandler = this.handlers[action];
if (!theHandler) {
this.sendResult(action, message_id, 'action没找到');
return
}
try {
if (!result["param"]) {
theHandler(function (response) {
_this.sendResult(action, message_id, response);
})
return
}
var param = result["param"]
try {
param = JSON.parse(param)
} catch (e) {
}
theHandler(function (response) {
_this.sendResult(action, message_id, response);
}, param)

} catch (e) {
console.log("error: " + e);
_this.sendResult(action, message_id, e);
}
}

Hlclient.prototype.sendResult = function (action, message_id, e) {
if (typeof e === 'object' && e !== null) {
try {
e = JSON.stringify(e)
} catch (v) {
console.log(v)//不是json无需操作
}
}
this.send(JSON.stringify({"action": action, "message_id": message_id, "response_data": e}));
}

1
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");

先调试 然后注册加密函数

1
2
3
4
5
window.enc=l
demo.regAction("enc", function (resolve, param) {
var res = enc(String(param));
resolve(res);
})

成功调用接口

避坑:加密函数l要在调试的时候加入全局函数,退出调试再调用rpc接口,小心油猴影响脚本使用

yakit+rpc

要完成完整的改包操作 首先要根据源码

1
2
3
4
5
6
7
8
9
10
//时间戳
window.time = Date.parse
//requestId
window.id = p
//v函数
window.v1 = v
//签名
window.m = a.a.MD5
//加密
window.enc = l

注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//md5函数
demo.regAction("req", function (resolve,param) {
//请求头
let timestamp = time(new Date());
let requestid = id();
let v_data = JSON.stringify(v1(param));
let sign = m(v_data + requestid + timestamp).toString();
//加密请求体
let encstr = enc(v_data);

let res = {
"timestamp":timestamp,
"requestid":requestid,
"encstr":encstr,
"sign":sign
};
resolve(res);
})

输出一下原始输入

成功伪造 接下来用yakit

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
// 定义加密函数
func getEnc(data){
rsp,req,err = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group=zzz&action=enc&param="+data, false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))
if(err){
return(err)
}

return json.loads(rsp.GetBody())["data"]
}

// beforeRequest 允许发送数据包前再做一次处理,定义为 func(origin []byte) []byte
beforeRequest = func(req) {
//获取请求体
req_body = poc.GetHTTPPacketBody(req)
//加密
res = getEnc(string(req_body))
//获取其他的参数
res = json.loads(res)

//修改其他的请求头
req = poc.ReplaceHTTPPacketHeader(req, "requestId", res["requestid"])
req = poc.ReplaceHTTPPacketHeader(req, "timestamp", res["timestamp"])
req = poc.ReplaceHTTPPacketHeader(req, "sign", res["sign"])

//修改请求体
req = poc.ReplaceHTTPPacketBody(req, res["encstr"])


return []byte(req)
}

// afterRequest 允许对每一个请求的响应做处理,定义为 func(origin []byte) []byte
afterRequest = func(rsp) {
return []byte(rsp)
}

// mirrorHTTPFlow 允许对每一个请求的响应做处理,定义为 func(req []byte, rsp []byte, params map[string]any) map[string]any
// 返回值回作为下一个请求的参数,或者提取的数据,如果你需要解密响应内容,在这里操作是最合适的
mirrorHTTPFlow = func(req, rsp, params) {
return params
}

解读一下 其实就是未加密请求的body,通过rpc接口返回加密后的数据(抓取data解析,看了访问rpc接口的页面就懂了)


js逆向
http://example.com/2025/01/07/js逆向/
作者
z2zQAQ
发布于
2025年1月7日
许可协议