概要
提示:仅供学习,不得用做商业交易,如有侵权请及时联系
逆向:某团Mtgsig1.2 (补环境)
URL: aHR0cHM6Ly9hY2NvdW50LmRpYW5waW5nLmNvbS9wY2xvZ2luP3JlZGlyPWh0dHBzOi8vbS5kaWFucGluZy5jb20vZHBob21l
目标:请求头Mtgsig
整体架构流程
提示:全扣补环境
1、分析加密入口:搜索 H5guard.sign
2、将整个文件扣下:
url:aHR0cHM6Ly9hcHBzZWMtbW9iaWxlLm1laXR1YW4uY29tL2g1Z3VhcmQvSDVndWFyZC5qcz92PTE3NDYwMjEzODMyNzk=
3、初始化加密环境:
技术名词解释
提示:检测环境数组
直接找到a6生成的位置,以为a6参与了环境计算: gG就是环境数组
这里直接展示一下我补的浏览器环境,基本上跟浏览器一致了
{
//版本号
k1: '3.1.0',
//时间戳
k5: 1746020851587,
//随机生成
sessionId: '5f0eae8fc7e443d9877edb598c683bcd',
// getfp生成的WEBDFPID 后面一段值
k2: '1745824008886IMQOYUOfd79fef3d01d5e9aadc18ccd4d0c95074463',
// // getfp生成的WEBDFPID 前面一段值
k3: 'u53zvu029uuw5730z5x026729ww0x6w48032y11148x979589u2vv091',
k123: {
k7: 16,
k24: 5,
k27: 5,
k28: 3,
k29: 3,
k30: 5,
k45: 7,
k52: 5,
k53: 5,
k54: 5,
k55: 5,
k56: 5,
k57: 5,
k58: 5,
k59: 5,
k62: 16,
k63: 5,
k70: 0,
k72: 3
},
// Navigator.platform
k25: 'Win32',
k27: '',
k68: [ 0, 0, 0, 0, 0 ],
// sessionStorage、localStorage、indexedDB、openDatabase、chrome、document、plugins、getOwnPropertyDescriptor、permissions、createElement、WebGLRenderingContext、getContext、AudioContext
k50: '00ceea200',
k61: 0,
reload: [Function (anonymous)],
k0: 1746020851,
k7: '',
k62: '',
k63: '',
k52: [],
k53: [],
k54: [],
k55: [],
k56: [],
k57: [],
k58: [],
k59: [],
// href 和 origin
k6: [
'https://脱敏/pclogin',
'https://脱敏/'
],
// navigator的属性或方法 、history的属性或方法 、window的属性或方法
k8: 'ffffffffffffffffffffff3ffffffffffdfbfffffffffffffffffffffffffc',
//document.readyState / performance.timing.domContentLoadedEventStart/domContentLoadedEventEnd/domLoading
k9: 'loading|0|0|1746020851601',
//[[screen["width"], screen["height"]], [screen["availWidth"], screen["availHeight"]], screen["colorDepth"], screen["pixelDepth"]]
k11: [ [ 1536, 864 ], [ 1536, 824 ], 24, 24 ],
//document["documentElement"]["clientWidth"] / window["innerWidth"]
k12: [ 1536, 715 ],
//window["sessionStorage"]
k13: 1,
//window["localStorage"]
k14: 1,
//window["pageYOffset"]
k15: 0,
//window["document"]["body"]["scrollTop"]
k16: 0,
//window["devicePixelRatio"]
k17: 1.25,
//window["length"]
k18: 0,
//window["performance"]["memory"]["jsHeapSizeLimit"]
k19: 2172649472,
//navigator["languages"]
k20: [ 'zh-CN', 'zh' ],
//navigator["language"]
k21: 'zh-CN',
//navigator["deviceMemory"]
k22: 8,
//navigator["hardwareConcurrency"]
k23: 8,
//navigator["doNotTrack"]
k24: '',
//window["navigator"]["plugins"] /name
k26: [
'PDF Viewer',
'Chrome PDF Viewer',
'Chromium PDF Viewer',
'Microsoft Edge PDF Viewer',
'WebKit built-in PDF'
],
//navigator["oscpu"]
k28: null,
//navigator["cpuClass"]
k29: null,
//avigator["vendorSub"]
k30: '',
//navigator["maxTouchPoints"]
k31: 0,
//navigator["vendor"]
k32: 'Google Inc.',
//navigator["cookieEnabled"] ? "yes" : ""
k33: 'yes',
// canvas.toDAataUrl
k34: 'data:image/png;base64,xxx',
//对canvas指纹进行魔改md5加密
k36: '174b4e8b63ec5d15ad9da6186992f4bc',
// navigator["userAgent"]
k37: 'Mozilla/5.0 xxx/537.36',
//history["length"]
k38: 3,
//getParameter --- UNMASKED_VENDOR_WEBGL
k39: 'Google Inc. (Intel)',
// getParameter --- UNMASKED_RENDERER_WEBGL
k40: 'ANGLE (Intel, Intel(R) UHD Graphics (0x00008A56) Direct3D11 vs_5_0 ps_5_0, D3D11)',
// getParameter ---- VENDOR
k41: 'WebKit',
// getParameter ---- RENDERER
k42: 'WebKit WebGL',
// getParameter ---- VERSION
k43: 'WebGL 1.0 (OpenGL ES 2.0 Chromium)',
k45: '',
// matchMedia
k46: 'srgb',
// new Date()["getTimezoneOffset"]()
k48: -480,
// timeZone
k49: 'Asia/Shanghai',
// sessionStorage /localStorage/indexedDB
k51: '1|1|1',
// tostring检测、多层tostring
k64: {
parse: {
function: 'function parse() { [native code] }',
toString: [Object]
},
stringify: {
function: 'function stringify() { [native code] }',
toString: [Object]
},
decodeURI: {
function: 'function decodeURI() { [native code] }',
toString: [Object]
},
decodeURIComponent: {
function: 'function decodeURIComponent() { [native code] }',
toString: [Object]
},
encodeURI: {
function: 'function encodeURI() { [native code] }',
toString: [Object]
},
encodeURIComponent: {
function: 'function encodeURIComponent() { [native code] }',
toString: [Object]
},
escape: {
function: 'function escape() { [native code] }',
toString: [Object]
},
unescape: {
function: 'function unescape() { [native code] }',
toString: [Object]
},
atob: {
function: 'function atob() { [native code] }',
toString: [Object]
},
btoa: {
function: 'function btoa() { [native code] }',
toString: [Object]
}
},
// document["getElementsByTagName"]("script") / getAttribute -src
k65: [
'//脱敏/js/xxx.min.js',
'https://脱敏/yoda.xxx.js',
'//脱敏/async_dependencies.xxx.js',
'//脱敏/logan_2.1.5.js',
'//脱敏/owl_1.9.3.js',
'//脱敏/lx.js',
'https://脱敏/xxx/xxx.js'
],
// 检测bom原型和原型链上的toString 和 getOwnPropertyDescriptor
k66: {
Window: {
function: 'function Window() { [native code] }',
typeof: 'function',
Object: [Object],
toString: [Object]
},
Navigator: {
function: 'function Navigator() { [native code] }',
typeof: 'function',
Object: [Object],
toString: [Object]
},
window: {
function: '[object Window]',
typeof: 'object',
Object: [Object],
toString: [Object]
},
navigator: {
function: '[object Navigator]',
typeof: 'object',
Object: [Object],
toString: [Object]
}
},
// 三个对象的configurable
k67: { location: false, document: false, top: false },
// RTCPeerConnection异步加载的onicecandidate事件
k44: '1020839364',
// encry加密得到
k71: 'fuTAVPQM5XjsHGg6Vc==',
k72: '',
// getfp 进行dom操作创建标签span,字体判断得到
k10: 'Arial,Courier,Courier New,Georgia...............',
// span offsetWidth offsetHeight ["monospace", "sans-serif", "serif"] 对比计算得到
k60: 'ffff7ffff8',
k4: 1746020851755,
// OfflineAudioContext异步操作事件得到
k35: '124.04347527516074',
// navigator["getBattery"] 异步操作得到
k47: [ 0.99, true, 'Infinity' ]
}
函数保护,过多层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);
补充点:RTCPeerConnection、getBattery、OfflineAudioContext三个异步
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
}
// 创建电池管理器对象原型
const BatteryManager = {
level: 1,
charging: true,
chargingTime: 0,
dischargingTime: Infinity,
onchargingchange: null,
onlevelchange: null,
toString: function() {
return `BatteryManager {
charging: ${this.charging},
level: ${this.level},
chargingTime: ${this.chargingTime},
dischargingTime: ${this.dischargingTime}
}`
}
}
getBattery = function getBattery() {
return Promise.resolve({
__proto__: BatteryManager,
// 动态参数配置(示例值)
level: 0.99,
charging: true,
dischargingTime: 'Infinity' // 2小时放电时间
})
}
RTCPeerConnection = function RTCPeerConnection() {
return proxy({
createDataChannel: function createDataChannel() { },
createOffer: function createOffer() {
this.onicecandidate({
candidate:{
"candidate": "candidate:1020839364 1 udp 1677729535 xxxx 56455 typ srflx raddr 0.0.0.0 rport 0 generation 0 ufrag 7Ocn network-cost 999",
"sdpMid": "0",
"sdpMLineIndex": 0,
"usernameFragment": "7Ocn"
}
});
return new Promise(function (resolve, reject) {
resolve(proxy({
type: 'offer',
sdp: 'offerSdp',
then: function then() {
},
}, 'RTCSessionDescription'));
});
},
setLocalDescription: function setLocalDescription() {
},
}, 'RTCPeerConnection');
};
webkitRTCPeerConnection = RTCPeerConnection;
Object.getOwnPropertyDescriptor检测点:
Object.getOwnPropertyDescriptor_ = Object.getOwnPropertyDescriptor;
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(obj, prop) {
var desc = Object.getOwnPropertyDescriptor_(obj, prop);
if (obj + '' === '[object Window]' && prop === 'location') {
return {
configurable: false,
enumerable: true,
get: {location(){}}.location,
set:{location(){}}.location
};
}
if (obj + '' === '[object Window]' && prop === "document") {
return {
configurable: false,
enumerable: true,
get: {document(){}}.document,
set:undefined
};
}
if (obj + '' === '[object Window]' && prop === "top") {
return {
configurable: false,
enumerable: true,
get: {top(){}}.top,
set:undefined
};
}
return desc;
}
这里说一下XML怎么补,不会补就第三方库
XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
XMLHttpRequest.prototype = new XMLHttpRequest();
技术细节
提示:补了一辈子,环境与浏览器都一致了,就是过不了,最后发现js中有空行,离谱
结果:
小结
提示:学习交流群+v主页(+知识星球交流学习)