文章目录
- 概要
- 整体架构流程
- 小结
概要
提示:仅供学习,不得用做商业交易,如有侵权请及时联系!
逆向:某花顺股票数据
URL:aHR0cHM6Ly9xLjEwanFrYS5jb20uY24v
目的:hexin-v(cookie)
整体架构流程
提示:分析-调试-猜想-实现-执行
一、hook进行断点
(function () {
'use strict';
var cookieTemp = '';
Object.defineProperty(document, 'cookie', {
set: function (val) {
if (val.indexOf('v') != -1) {
debugger;
}
console.log('Hook捕获到cookie设置->', val);
cookieTemp = val;
return val;
},
get: function () {
return cookieTemp;
},
});
})();
继续往上跟栈,找到值生成的地方:
二、这里我们直接补环境,直接将该js文件全部扣下到node里面,并挂上代理:
my_Proxy = function (obj_, obj_name, proxy=true) {
function set_traverse_object(tarrget, obj, recursion_layers) {
recursion_layers -= 1;
console.log();
for (let prop in obj) {
const value = obj[prop];
const tg_name = `${tarrget}.${prop.toString()}`;
const value_type = get_value_type(value);
if (value && value_type === "object" && recursion_layers >= 1) {
set_traverse_object(tg_name, value, recursion_layers);
continue
}
if (value && value.toString() !== '[object Object]') {
console.log(`setter hook->${tg_name}; value-> ${value}; typeof-> ${value_type}`);
continue
}
console.log(`setter hook->${tg_name}; value-> ${value}; typeof-> ${value_type}\n`)
}
}
function new_handel(target_name, obj, number) {
return new Proxy(obj, my_handler(target_name, number))
}
function get_value_type(value) {
if (Array.isArray(value)) {
return 'Array'
}
return typeof value;
}
function my_handler(target_name, number) {
return {
set: function (obj, prop, value) {
const value_type = get_value_type(value);
const tg_name = `${target_name}.${prop.toString()}`;
if (value && value_type === "object") {
set_traverse_object(tg_name, value, number)
} else {
console.log(`setter hook->${tg_name}; value-> ${value}; typeof-> ${value_type}`)
}
return Reflect.set(obj, prop, value);
},
get: function (obj, prop) {
const tg_name = `${target_name}.${prop.toString()}`;
const value = Reflect.get(obj, prop);
let value_type = get_value_type(value);
if (value && value_type === 'object') {
return new_handel(tg_name, value, number)
}
console.log(`getter hook->${tg_name}; value-> ${value}; typeof-> ${value_type}\n`);
return value
},
deleteProperty(target, propKey) {
// 没有实现链式输出
let result = Reflect.deleteProperty(target, propKey);
let value_type = get_value_type(result);
console.log(`delete hook-> ${propKey}, result-> ${result}; typeof-> ${value_type}\n`);
return result;
}
}
}
if (!(proxy === true)){
return obj_;
}
return new Proxy(obj_, my_handler(obj_name, 30));
};
function monitorWindow(obj, obj_str) {
// 设置打印字符串长度
const MAX_VALUE_LENGTH = 70;
/**
截取 value 值,用于在日志中输出时限制字符串长度,避免日志过长。
@param {Object} value - 需要被截取的值。
@returns {Object} 返回截取后的字符串值。
*/
function truncateValue(value) {
if (typeof value === "string" && value.length > MAX_VALUE_LENGTH) {
return value.substring(0, MAX_VALUE_LENGTH) + "...";
}
if (typeof value !== "object") {
return value;
}
const keys = Object.keys(value);
const result = {};
if (keys.length > 2) {
result[keys[0]] = value[keys[0]].toString().substring(0, MAX_VALUE_LENGTH) + "...";
}
return "{" + Object.entries(result).map(([k,v])=>`${k}: ${v}`).join(", ") + "}";
}
/**
序列化 value 值,用于在日志中输出时处理对象或方法。
@param {Object} value - 需要被序列化的值。
@returns {Object} 返回序列化后的字符串值。
*/
function serializeValue(value) {
if (typeof value === "object") {
try {
return JSON.stringify(value);
} catch {
return value;
}
}
return value;
}
/**
* 创建代理处理程序,用于对被代理对象的属性访问、属性设置、方法调用等进行监听并打印操作日志。
* @param {Object} name - 对象名。
* @returns {Object} 返回代理处理程序。
*/
function createHandler(name) {
function shouldSkipKey(key, name) {
if (key === 'window' || key === 'self' || key === 'global' || key === 'globalThis' || key === name || key === "_globalObject") {
return true;
}
if (typeof key === 'string' && (key.startsWith('__') || key.endsWith('__'))) {
return true;
}
return String(key) === "Symbol(impl)" || String(key) === "Element" || String(key) === "prototype" || truncateValue(serializeValue(name)).includes("Symbol(impl)");
}
return {
get(target, key, receiver) {
// 打印调用栈
// console.log(new Error().stack);
// target=Object.defineProperty(target)
// 获取属性值
const value = target[key];
// 不打印toString和valueOf特定的信息
if (key === Symbol.unscopables || key === 'toString' || key === 'valueOf') {
return Reflect.get(target, key, receiver);
}
// 内部属性
if (shouldSkipKey(key, name)) {
// debugger
if (typeof key != 'number') {
console.log(`访问: "${(String(key) + "\"内部属性").padEnd(28, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
}
return value;
}
// 处理代理函数的构造函数
if (typeof value === 'function' && value.hasOwnProperty('prototype')) {
try {
new value
// console.log(`调用了构造函数: ${String(key).padEnd(22, " ")} |"参数": ${JSON.stringify(value)}`);
return new Proxy(value,createHandler(`${String(name)}.${String(key)}`))
} catch (e) {}
}
// 处理代理对象的属性访问和设置()
if (typeof value === 'function' && !value.hasOwnProperty('prototype')) {
return function getFunc(...args) {
try {
var result = Reflect.apply(value, target, args);
console.log(`调用了函数: ${(String(key)).padEnd(27, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|参数= ${truncateValue(serializeValue(args))}`);
return result
} catch (e) {// return Reflect.apply(value, target, args[1])
}
}
}
// 处理代理对象的属性访问和设置(递归调用)
if (value != null && (typeof value === 'object')) {
if ('number' === typeof key) {
console.log('key:', key);
console.log(`访问: "${(String(key) + "\"属性").padEnd(30, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
}
return new Proxy(value,createHandler(`${String(name)}.${String(key)}`));
}
if (typeof value === 'function') {
// 在Node上和windows有些差异,node有函数也有prototype,所以需要继续回调
return new Proxy(value,createHandler(`${String(name)}.${String(key)}`));
} else {
// 不进行代理的属性或方法
if (key != 'toJSON') {
console.log(`获取: "${(String(key) + "\"属性").padEnd(30, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
}
}
return value;
},
set(target, key, value, receiver) {
// 打印调用栈
// console.log(new Error().stack);
console.log(`设置对象: "${(String(key) + "\"").padEnd(28, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
return Reflect.set(target, key, value, receiver);
},
apply(target, thisArg, args) {
// 打印调用栈
// console.log(new Error().stack);
console.log(`调用了函数: ${(String(name)).padEnd(27, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|参数= ${truncateValue(serializeValue(args))}`);
return Reflect.apply(target, thisArg, args);
},
construct(target, args, newTarget) {
// 打印调用栈
// console.log(new Error().stack);
console.log(`调用了构造函数: ${String(target.name).padEnd(23, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|参数= ${JSON.stringify(args)}`);
return Reflect.construct(target, args, newTarget);
},
};
}
return new Proxy(obj,createHandler(obj_str));
};
直接搜索:var rt;,给它定义成全局变量
挂上代理,我们直接补上window、document、navigator、location
继续将undefined改为浏览器对应的值:
下面的自己慢慢补吧,直接划一波水,帖一波最后的环境值:
window = global;
addEventListener = function () { };
document = {
head: {},
getElementsByTagName: function (res) {
return []
},
createElement: function (res) {
if (res === 'canvas') {
return {
getContext: function (res) {
if (res === 'webgl2') {
return {}
}
}
}
}
return {}
},
addEventListener: function () { },
documentElement:{}
};
navigator = {
plugins: {
length: 2,
'0': {
name:'Chromium PDF Plugin'
},
'1': {
name:'Chromium PDF Viewer'
}
},
userAgent: 'Mozilla/5.0 (Windows NT 10.0; JiSu) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.3.1.7 Safari/537.36',
javaEnabled: function () {
return false
},
webdriver: false,
doNotTrack: null,
language: 'zh-CN',
languages: ['zh-CN', 'zh'],
platform: 'Win32',
vendor: 'Google Inc.',
appVersion:'5.0 (Windows NT 10.0; JiSu) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.3.1.7 Safari/537.36'
};
location = {
"ancestorOrigins": {},
"href": "https://脱密处理/",
"origin": "https://脱密处理",
"protocol": "https:",
"host": "脱密处理",
"hostname": "脱密处理",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
};
XMLHttpRequest = function () { }
window.hasOwnProperty_ = hasOwnProperty;
hasOwnProperty = function (res) {
if (res === 'fetch') {
return true
}
return window.hasOwnProperty_(res)
}
Window = function () {
}
三、最终就是实现python
小结
提示:学习交流群:v:wzwzwz0613拉进群