当前位置: 首页 > news >正文

【js逆向案例四】小红书

网址:aHR0cHM6Ly93d3cueGlhb2hvbmdzaHUuY29tL3VzZXIvcHJvZmlsZS82NDcwOTEyYjAwMDAwMDAwMTAwMzQzNTY/eHNlY190b2tlbj1BQnpwTGlXNU5DSjYxRVJGbXlyTlB2RHFlTFU2ZVNPWmt0LWhIaE9sdmdYdzg9JnhzZWNfc291cmNlPXBjX25vdGU=
网络接口:aHR0cHM6Ly9lZGl0aC54aWFvaG9uZ3NodS5jb20vYXBpL3Nucy93ZWIvdjEvdXNlcl9wb3N0ZWQ/bnVtPTMwJmN1cnNvcj02OGE4MTMwNzAwMDAwMDAwMWIwMzdkNGQmdXNlcl9pZD02NDcwOTEyYjAwMDAwMDAwMTAwMzQzNTYmaW1hZ2VfZm9ybWF0cz1qcGcsd2VicCxhdmlmJnhzZWNfdG9rZW49QUJ6cExpVzVOQ0o2MUVSRm15ck5QdkRxZUxVNmVTT1prdC1oSGhPbHZnWHc4JTNEJnhzZWNfc291cmNlPXBjX25vdGU=

一、找到加密参数

随便找一个博主进去,然后往上滑

点进去之后发现加密参数,然后复制curl,进行网络请求,发现不成功,那就去破解加密参数

二、找到加密参数的位置

首先全局搜索X-s,看了半天,就发现一个符合的,那就在这里打上断点,进行调试

断住之后发现这里有点奇妙

发现这里就是x-s生成的位置,但是在上面有一点需要注意,这里要和想要的网络接口一致

这里发现长度一致,应该就是需要的加密位置

三、破解加密

这里发现v函数里,x是网络接口,然后s为空
然后进去v函数,走到里面,加上断点调试之后你就会发现,最后return返回的值就是我们想要的加密值

先把代码扣下来, 然后在浏览器调试一下,看看她们的值
function seccore_signv2(e, a) {var r = window.toString, c = e;"[object Object]" === r.call(a) || "[object Array]" === r.call(a) || (void 0 === a ? "undefined" : (0,h._)(a)) === "object" && null !== a ? c += JSON.stringify(a) : "string" == typeof a && (c += a);var d = (0,p.Pu)([c].join("")), s = window.mnsv2(c, d), f = {x0: u.i8,x1: "xhs-pc-web",x2: window[u.mj] || "PC",x3: s,x4: a ? void 0 === a ? "undefined" : (0,h._)(a) : ""};return "XYS_" + (0,p.xE)((0,p.lz)(JSON.stringify(f)))}
先从最后看看里面的f,f里面大部分都是定值,除了一个x3不是其他的都是

看s里面的值发现里面c就是上面传入的值,但是d不是,但他的长度是32位,兄弟们想到了什么,MD5加密,这里我试了一下,没有魔改就是MD5加密,剩下的window.mnsv2是后面的重头戏,最后说先接着看return里面的
这里面这两个都是函数,直接开始扣

function tripletToBase64(e) {return c[e >> 18 & 63] + c[e >> 12 & 63] + c[e >> 6 & 63] + c[63 & e]
}function encodeChunk(e, a, r) {for (var c, d = [], s = a; s < r; s += 3)c = (e[s] << 16 & 0xff0000) + (e[s + 1] << 8 & 65280) + (255 & e[s + 2]),d.push(tripletToBase64(c));return d.join("")
}function b64Encode(e) {for (var a, r = e.length, d = r % 3, s = [], f = 16383, u = 0, l = r - d; u < l; u += f)s.push(encodeChunk(e, u, u + f > l ? l : u + f));return 1 === d ? (a = e[r - 1],s.push(c[a >> 2] + c[a << 4 & 63] + "==")) : 2 === d && (a = (e[r - 2] << 8) + e[r - 1],s.push(c[a >> 10] + c[a >> 4 & 63] + c[a << 2 & 63] + "=")),s.join("")
}function encodeUtf8(e) {for (var a = encodeURIComponent(e), r = [], c = 0; c < a.length; c++) {var d = a.charAt(c);if ("%" === d) {var s = parseInt(a.charAt(c + 1) + a.charAt(c + 2), 16);r.push(s),c += 2} elser.push(d.charCodeAt(0))}return r
}function seccore_signv2(e, a) {let d = CryptoJs.MD5(e).toString()let s = window.mnsv2(e, d)let f = {x0: "4.2.6",x1: "xhs-pc-web",x2: "Mac OS",x3: s,x4: ""};return "XYS_" + b64Encode(encodeUtf8(JSON.stringify(f)))
}console.log(seccore_signv2("/api/sns/web/v1/user_posted?num=30&cursor=68a81307000000001b037d4d&user_id=6470912b0000000010034356&image_formats=jpg,webp,avif&xsec_token=ABzpLiW5NCJ61ERFmyrNPvDqeLU6eSOZkt-hHhOlvgXw8%3D&xsec_source=pc_note", ''));
接下来就是最重要的那个window.mnsv2函数了,这里直接断点,进去,发现他是在虚拟机里面生成的,这里想一下,说明他是JSVMP的可能性是不是很大,JSVMP的特点就是在虚拟机中生成,主要就是在前面有一个eval()函数生成,最后输出的,那就在最上边打上断点,然后刷新页面

然后一直点这个,你就会发现进入这个函数里面了

这里就是那个混淆函数生成的位置,然后接下来,你把刚才的虚拟函数扣下来你会发现,这不是一个自启动函数,没法调用,缺少调用的,你在看看刚才eval()输出的位置,它是由两个eval()输出的,那么就想一下接下来的就是那个启动函数,点进去扣出来

就是把这两个文件都单独放进去一个文件,或者两个文件都行,然后进行调用
然后接下来就是对这两个文件进行补环境,环境代理放进去开始补环境

四、补环境

补环境代码
!(function(){const $toString = Function.prototype.toString;const symbol = Symbol();    // 独一无二的属性const myToString = function (){return typeof this === 'function' && this[symbol] || $toString.call(this);}function safeFunction(func, key, value){Object.defineProperty(func, key, {enumerable: false,configurable: true,writable: true,value: value,})};delete Function.prototype.toString;safeFunction(Function.prototype, "toString", myToString);safeFunction(Function.prototype.toString, symbol, 'function toString() { [native code] }');globalThis.safeFunction = function(func, funcname){safeFunction(func, symbol, `function ${funcname || func.name || ''}() { [native code] }`);}})();
function obj_toString(obj, name) {Object.defineProperty(obj, Symbol.toStringTag, {value: name,});
}   // 主要就是过toString()检测function watch(obj, obj_name) {// 如果 obj 是 undefined 或 null,返回原值if (obj === undefined || obj === null) {console.log(`警告: "${obj_name}" 是 ${obj === null ? 'null' : 'undefined'},跳过代理`);return obj;}// 如果不是对象类型(包括函数),也返回原值if (typeof obj !== 'object' && typeof obj !== 'function') {console.log(`警告: "${obj_name}" 不是对象或函数类型,而是 ${typeof obj},跳过代理`);return obj;}const handler = {get(target, property, receiver) {if (property==='toJSON'){return target[property];}console.log(`方法: get  | 对象: "${obj_name}" | 属性: ${typeof property === 'symbol' ? property.toString() : property} | 属性类型: ${typeof property} | 属性值类型: ${typeof target[property]}`);return Reflect.get(target, property, receiver);},set(target, property, value, receiver) {console.log(`方法: set  | 对象: "${obj_name}" | 属性: ${typeof property === 'symbol' ? property.toString() : property} | 属性类型: ${typeof property} | 属性值类型: ${typeof value}`);return Reflect.set(target, property, value, receiver);},has(target, property) {console.log(`方法: has  | 对象: "${obj_name}" | 属性: ${typeof property === 'symbol' ? property.toString() : property} | 属性类型: ${typeof property} | 检查自身或原型链属性是否存在`);return Reflect.has(target, property);},ownKeys(target) {console.log(`方法: ownKeys  | 对象: "${obj_name}" | 获取自身可枚举属性键`);return Reflect.ownKeys(target);},getOwnPropertyDescriptor(target, property) {console.log(`方法: getOwnPropertyDescriptor  | 对象: "${obj_name}" | 属性: ${typeof property === 'symbol' ? property.toString() : property} | 属性类型: ${typeof property} | 获取属性描述符`);return Reflect.getOwnPropertyDescriptor(target, property);},defineProperty(target, property, descriptor) {console.log(`方法: defineProperty  | 对象: "${obj_name}" | 属性: ${typeof property === 'symbol' ? property.toString() : property} | 属性类型: ${typeof property} | 定义或修改属性描述符: ${JSON.stringify(descriptor)}`);return Reflect.defineProperty(target, property, descriptor);},deleteProperty(target, property) {console.log(`方法: deleteProperty  | 对象: "${obj_name}" | 属性: ${typeof property === 'symbol' ? property.toString() : property} | 属性类型: ${typeof property} | 删除属性`);return Reflect.deleteProperty(target, property);},getPrototypeOf(target) {console.log(`方法: getPrototypeOf  | 对象: "${obj_name}" | 获取原型链`);return Reflect.getPrototypeOf(target);},setPrototypeOf(target, proto) {console.log(`方法: setPrototypeOf  | 对象: "${obj_name}" | 设置新原型: ${proto ? proto.constructor.name : 'null'}`);return Reflect.setPrototypeOf(target, proto);},// 为函数添加 apply 和 construct 处理器apply(target, thisArg, argumentsList) {console.log(`方法: apply  | 对象: "${obj_name}" | 函数调用 | 参数数量: ${argumentsList.length}`);return Reflect.apply(target, thisArg, argumentsList);},construct(target, argumentsList, newTarget) {console.log(`方法: construct  | 对象: "${obj_name}" | 构造函数调用 | 参数数量: ${argumentsList.length}`);return Reflect.construct(target, argumentsList, newTarget);}};return new Proxy(obj, handler);
}delete __filename;
delete __dirname;function Window(){}
window = global;
window.Buffer = Buffer;
delete global;
delete Buffer;
window.window = window.top = window.self = window;
window.requestAnimationFrame = function requestAnimationFrame() {};
window.requestIdleCallback = function requestIdleCallback() {};
window.DeviceOrientationEvent = function DeviceOrientationEvent(){};
window.DeviceMotionEvent = function DeviceMotionEvent(){};function XMLHttpRequest() {}
XMLHttpRequest.prototype.open = function () {};
XMLHttpRequest.prototype.send = function () {};
XMLHttpRequest.prototype.setRequestHeader = function () {};
XMLHttpRequest.prototype.addEventListener = function () {};
window.XMLHttpRequest = XMLHttpRequest;
window.chrome = {}
window.xsecappid = 'xhs-pc-web';
window.loadts = new Date().toString()
window.addEventListener = function addEventListener(){}
window.MouseEvent = function MouseEvent(){}safeFunction(window.addEventListener)
safeFunction(window.MouseEvent)Object.setPrototypeOf(window, Window.prototype)
// window = watch(window, "window")function Document(){}
function Element(){}safeFunction(Element)
Element.prototype.getAttribute = function getAttribute(){};safeFunction(Element.prototype.getAttribute)
Element.prototype.removeChild = function removeChild(){};safeFunction(Element.prototype.removeChild)
function HTMLElement(){Element.call(this)
};safeFunction(HTMLElement)
HTMLElement.prototype = Object.create(Element.prototype)
HTMLElement.prototype.constructor = HTMLElement;window.HTMLElement = HTMLElement;
function HTMLHtmlElement(){HTMLElement.call(this)
};safeFunction(HTMLElement)
HTMLHtmlElement.prototype = Object.create(HTMLElement.prototype)
HTMLHtmlElement.prototype.constructor = HTMLHtmlElement;function HTMLCollection(){
}// 添加一个基本的 iterator 方法
HTMLCollection.prototype[Symbol.iterator] = function () {return [].values(); // 返回一个空数组的迭代器
};Document.prototype.documentElement = new HTMLHtmlElement();
Document.prototype.getElementsByTagName = function getElementsByTagName(tagName){if (tagName === '*'){return [{"tagName": "html"},{"tagName": "head"},{"tagName": "script"},{"tagName": "meta"},{"tagName": "link"},{"tagName": "style"},{"tagName": "title"},{"tagName": "body"},{"tagName": "div"},{"tagName": "svg"},{"tagName": "defs"},{"tagName": "clippath"},{"tagName": "rect"},{"tagName": "path"},{"tagName": "symbol"},{"tagName": "circle"},{"tagName": "g"},{"tagName": "header"},{"tagName": "a"},{"tagName": "img"},{"tagName": "input"},{"tagName": "use"},{"tagName": "button"},{"tagName": "span"},{"tagName": "ul"},{"tagName": "li"},{"tagName": "picture"},{"tagName": "i"},{"tagName": "p"},{"tagName": "section"},{"tagName": "iframe"}
]}console.log(`对象 => Document.prototype.getElementsByTagName, 获取元素: ${tagName}`)
};safeFunction(Document.prototype.getElementsByTagName)
Document.prototype.addEventListener = function addEventListener(){}function HTMLAllCollection (){this.length = 1181;
};safeFunction(HTMLAllCollection)
function HTMLBodyElement (){HTMLElement.call(this)
};safeFunction(HTMLBodyElement)
HTMLBodyElement.prototype = Object.create(HTMLElement.prototype)
HTMLBodyElement.prototype.constructor = HTMLBodyElement;
Document.prototype.all = new HTMLAllCollection();
Document.prototype.body = new HTMLBodyElement();
Document.prototype.cookie = 'abRequestId=77e39326-85d4-52fe-bfa7-574c973e32de; webBuild=4.81.0; xsecappid=xhs-pc-web; a1=199a4276e3dzm8hkqvytulqmxthamjrfggeyqf1d730000310776; webId=761705c911e959313639e1d34e9d6bb7; gid=yjj04JWY8dkWyjj04JWKdkiyqfu6YxTAhv97dfW1A6C9xvq806VFiA888qy8WWK8WjdyJi0d; unread={%22ub%22:%2268d7af2e000000000e0327db%22%2C%22ue%22:%2268c4e00d000000001b030fde%22%2C%22uc%22:23}; loadts=1759663837296; websectiga=2a3d3ea002e7d92b5c9743590ebd24010cf3710ff3af8029153751e41a6af4a3';safeFunction(Document.prototype.addEventListener)
function HTMLDocument(){}
Object.setPrototypeOf(HTMLDocument.prototype, Document.prototype)
document = new HTMLDocument()
// safeFunction(HTMLDocument)
// obj_toString(document, 'HTMLDocument')
// document = watch(document, "document");
window.document = document;
window.HTMLDocument = HTMLDocument;function Navigator(){}
Navigator.prototype.appCodeName = "Mozilla";
Navigator.prototype.appName = "Netscape";
Navigator.prototype.language = "zh-CN";
Navigator.prototype.languages = ["zh-CN","zh","en"
];
Navigator.prototype.platform = "MacIntel";
Navigator.prototype.product = "Gecko";
Navigator.prototype.productSub = "20030107";
function PermissionStatus(){this.state = "denied"this.then = function then(){}
};safeFunction(PermissionStatus)
function Permissions(){
}
Permissions.prototype.query = function query() {// console.log("对象 => navigator.permissions.query " + "调用方法: query", arguments[0])return Promise.resolve(new PermissionStatus())
};safeFunction(Permissions.prototype.query)
Navigator.prototype.permissions = new Permissions()
Navigator.prototype.userAgent = "";
Navigator.prototype.vendor = "Google Inc.";
Navigator.prototype.webdriver = false;
navigator = new Navigator()
// navigator = watch(navigator, "navigator");
window.navigator = navigator;
window.Navigator = Navigator;function Storage(){}
sessionStorage = new Storage()
// sessionStorage = watch(sessionStorage, "sessionStorage");
window.sessionStorage = sessionStorage;localStorage = new Storage()
// localStorage = watch(localStorage, "localStorage");
window.localStorage = localStorage;
window.Storage = Storage;function Location(){}
Location.prototype = {"ancestorOrigins": {},"href": "https://bf5b000000001001945f?xsec_token=AB3TbsCqzVXoWzLIZU5EZiXQBkisr5haqXi5iXIV2NtO0=&xsec_source=pc_note","origin": "https:shu.com","protocol": "https:","host": "www..com","hostname": "www.xiaohongshu.com","port": "","pathname": "/user/00000001001945f","search": "?xsec_token=AB3TbsCqzVXoWzLIZU5EZiXQBkisr5haqXi5iXIV2NtO0=&xsec_source=pc_note","hash": ""
}
location = new Location()
// location = watch(location, "location");
window.location = location;
window.Location = Location;function History(){}
history = new History()
// history = watch(history, "history");
window.history = history;
window.History = History;function Screen(){}
screen = new Screen()
// screen = watch(screen, "screen");
window.screen = screen;
window.Screen = Screen;

http://www.dtcms.com/a/564694.html

相关文章:

  • Next.js路由系统
  • 6、webgl 基本概念 + 四边形纹理
  • 【weblogic】XML反序列化漏洞
  • 20-控制流多次异步
  • Python Seaborn详解:让数据可视化更简单、更美观的利器
  • 基于c 的网站开发河北邢台路桥建设公司网站
  • VivaCut 4.4.0 | 专业的视频剪辑编辑制作工具,有非常多的特效,可替代剪映
  • CY5-α-酮戊二酸,(CY5-α-Ketoglutarate, CY5-α-KG)
  • Matlab模拟对流方程迎风格式验证
  • LeetCode 面试经典 150_二叉树_相同的树(68_100_C++_简单)(DFS)
  • LeetCode算法日记 - Day 91: 最长数对链
  • 潍坊哪个网站建设公司好wordpress刷新才显示
  • 在 Hive 中NULL的理解
  • 如何让UE5的插件Ultra Dynamic Sky的光照对齐真实时间?
  • 【问题解决】用pnpm创建的 Vue3项目找不到 .eslintrc.js文件 及 后续的eslint配置的解决办法
  • Kubernetes Pod 基本原理:全面详解
  • 有关于cnb自动化的脚本补全
  • Hive三大连接操作全解析
  • css3新增过渡
  • Hive 中的 COALESCE 函数作用
  • 网站建设内部下单流程图赣州的免费网站建设
  • 广东顺德网站建设instagram wordpress
  • Linux连接Doris:MySQL与Beeline指南
  • 【金仓数据库】ksql 指南(四) —— 创建与管理表(KingbaseES 数据存储核心)
  • Swift项目生成Framework流程以及与OC的区别
  • C++多线程同步与互斥
  • Python Jupyter Notebook 完全指南:从入门到精通
  • 站点查询wordpress 外贸网站
  • CSP集训错题集 第八周 主题:基础图论
  • 基于C语言 HTTP 服务器客户端的实验