本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
本篇文章都是在网络其他文章的基础上进行分析的,因此有些地方可能可能会发出怀疑你是怎么找到的,当然我会尽量写详细点。
AST还原
还原代码网络上还是很多,找找也能用,但还是有部分代码需要自己写下的。
const a = ["9bfdeef5f8eff2f4f5", "13727e77",....] // 大数组
function b(c, d) {
var e = a[c -= 0];
...// 就是老是进来的那个方法
}
const vis1 = {
"CallExpression"(path) {
let {callee, arguments} = path.node;
if (types.isIdentifier(callee, {'name': 'b'})) {
try {
let value = eval(path.toString())
path.replaceWith(types.valueToNode(value));
} catch (e) {
console.log(e);
}
}
}
}
traverse(ast, vis1)
有几个地方会还原失败了,但是都打印出来了,手动还原下就行。
调用
万事都有个开头,所以我们也要先知道他是调用哪个方法生成的。实际上只要你网络上搜索的多就能找到,无需自己去跟了。
window.H5guard.init({参数到自己的浏览器里去搜索})
window.H5guard.sign({参数后面说})
补环境
像这种大厂的肯定会检测原型链的,所以补的时候尽量都补到原型链上
文件导入
下载整个H5guard.js文件,然后用require('./H5guard.js');导入下,免得代码太长补的时候恶心到自己。
a6
文章看多了就知道加密中的a6就是加密后的环境参数。a6的组成部分在头部有个明显的h1.标识,如果你有对js代码进行ast还原,那么直接搜索h1.就能找到生成位置了。
没还原也没事,根据网上的文章分析,搜索!1,找到类似gU(kz, !1, kt)的代码也行……
所以把最终环境补成a6加密前的样子就行了,当然有部分环境是不在a6内的,你也要补!
k3
只要你执行了js文件,那他就会发送请求获取k3的值,但是实际上让他不发送请求使用k2的值也是可以的。因此推荐是补下sendBeacon和XMLHttpRequest,但是实际内容不要去实现即可。
XMLHttpRequest = function XMLHttpRequest() {
console.log('XMLHttpRequest-->')
}
Navigator.prototype.sendBeacon = function (url, data) {
console.log('window.navigator.sendBeacon-->', url, data)
}
k66
嵌套的toString,网络上也有文章给出补的代码(但是没给出使用方法)举个例子
!(function () {
"use strict";
const $toString = Function.toString;
const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));
const mytoString = function () {
return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
};
function set_native(func, key, value) {
Object.defineProperty(func, key, {
"enumerable": false,
"configurable": true,
"writable": true,
"value": value
})
};
delete Function.prototype['toString'];
set_native(Function.prototype, "toString", mytoString);
set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }");
this.func_set_native = function (func) {
set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol, func.name || ''}() { [native code] }`)
}
}).call(globalThis);
// 下面是这段代码的使用方法
func_set_native(btoa)
func_set_native(atob)
func_set_native(Window)
func_set_native(Navigator)
k35
补的是音频类相关的?同样使用网络上的代码,同样会报错
offauidio = proxy({
createOscillator: function createOscillator() {
return proxy({
frequency: {
setValueAtTime: function setValueAtTime() {
},
},
connect: function connect() {
},
start: function start() {
},
disconnect: function disconnect() {
}
}, 'OscillatorNode')
},
createDynamicsCompressor: function createDynamicsCompressor() {
return proxy({
connect: function connect() {
},
threshold: {
setValueAtTime: function setValueAtTime() {
},
},
knee: {
setValueAtTime: function setValueAtTime() {
},
},
ratio: 0,
reduction: {
setValueAtTime: function setValueAtTime() {
},
},
attack: {
setValueAtTime: function setValueAtTime() {
},
},
release: {
setValueAtTime: function setValueAtTime() {
},
},
disconnect: function disconnect() {
}
}, 'DynamicsCompressorNode')
},
currentTime: 0,
destination: {},
startRendering: function startRendering() {
},
}, 'OfflineAudioContext');
Object.defineProperty(offauidio, 'oncomplete', {
set: function (func) {
func({
renderedBuffer: {
getChannelData: function () {
return new Float32Array([...]);
},
}
})
return func
}
})
OfflineAudioContext = function OfflineAudioContext() {
return offauidio
}
AudioContext = function () {
console.log('AudioContext-->')
}
解决:new Float32Array([…]),替换…就行,替换成啥就到自己的浏览器中打断点找到调用这个方法的地方然后copy下就行了。或者把补环境的代码给DeepSeek,让他帮忙生成?
其他
k47,k70等等这些都是异步的,我给的建议是不要加setTimeout = function () {}这段代码,不然就怎么也执行不到了,还有就是直接写成API的形式这样就不用管异步的问题了。
const http = require('http');
http.createServer(async (req, res) => {
try {
const result = await window.H5guard.xxx(); // 调用核心方法
res.end(JSON.stringify({sign: result}));
} catch (err) {
res.statusCode = 500;
res.end('Execution failed');
}
}).listen(3000);
console.log('Server running at http://localhost:3000/');
至于其他的,按理来说只要AST还原了就没啥难度了,基本都看的清楚做了些什么。
调用
相信大家都能快速的找到加密调用位置,直接搜H5guard.sign(settings)都能找到,但是这里出的结果是错误的,自己去和实际请求携带的参数比对下就知道了。
所以这里需要断点到sign方法内,然后稍微看一眼就知道了,实际上就是真实的入参不在是settings的格式而已。