您的当前位置:首页正文

一个案例入门补环境

2024-10-17 来源:个人技术集锦

此分享只用于学习用途,不作商业用途,若有冒犯,请联系处理

反爬前置信息

站点: aHR0cDovLzEyMC4yMTEuMTExLjIwNjo4MDkwL3hqendkdC94anp3ZHQvcGFnZXMvaW5mby9wb2xpY3k=
接口: /xjzwdt/rest/xmzInfoDeliveryRest/getInfoDeliveryList

破解结果预览

何谓补环境

补环境其实是 补浏览器有而Node没有的环境,即补BOM和DOM的对象 ,一切环境补的结果都是向浏览器实际结果靠齐,入门补环境只需要记住缺啥补啥这个技巧,当运行提示缺少某个环境,则直接在浏览器运行该环境是啥结果然后补上该结果。

反爬机制

站点有两个反爬项, 请求体加密 响应结果解密

逆向研究

补环境处理的是关键代码,所以我们还是要定位到关键代码位置拿到关键代码

找到接口的调用堆栈,点击下面图片标识的堆栈进入代码

1 处打上断点重新发起请求,在 2 处可以看到这里已经实现 请求体加密 了,那我们得往前走,也就是点击 3 处标识堆栈

然后在 1 处打上断点重新发起请求,点击 2 处进入函数引用代码位置

这里就能看到关键代码了,它重新封装了ajax, 请求体加密 响应结果解密 都是在这里进行的

但是我们要补的不是这个位置,因为我们又不是直接构建请求的,我们要破解的只是加解密,所以要补的是 window.sm2Util.encrypt window.sm2Util.aesDecrypt ,而它们都在 sm2Util.js 文件中,接下来我们直接补 sm2Util.js 代码就行。

注意直接拿全部代码,不要格式化

补环境

先直接运行代码,发现报下面所示错误,这是因为 window 不是 Node 的环境,这里一般是使用 global 替代

补好 window 环境后再次运行报下面所示错误,继续补 navigator

补好 navigator 环境后再次运行报下面所示错误,这是因为在浏览器环境下 exports undefined ,但是在Node环境下 exports Object 对象,所以这里我们要处理

补好 exports 后就不会报错了

打印看看发现能拿到想要的方法了,这里就初步补好环境了,要确定是否真正补全了还得运行一下代码,我们就拿调试时拿到的请求体加密原文进行调试

ok,这里测试的 请求体加密 成功了,说明 encrypt 补好了,接下来测试下 响应文本解密 ,直接拿接口返回的响应文本测试即可

ok,这里测试的 响应文本解密 也成功了,也就说明咱们补好了。

补环境补充-挂代理

上面讲解遇到缺失的环境都是对象本身,所以我们能直接知道缺了啥,然后对此做出处理。

但是如果缺失的是对象某个参数呢,比如下图所示我们是没法知道是哪个对象哪个参数出的问题的。大家可能会说不是有代码位置提示吗,但是这是在明文代码下能清楚提示,遇到混淆代码就不行了,所以我们需要 挂代理

所谓 挂代理 其实就是使用 Proxy 对象,它是一种对象代理机制,可以在对象和函数之间添加一个中间层,从而实现对对象和函数的拦截和控制。

使用下面这段代码,添加想要监控的对象

function getEnv(proxy_array) {    for (var i = 0; i < proxy_array.length; i++) {        handler = `{\n            get: function(target, property, receiver) {\n                   console.log('方法:get','    对象:${proxy_array[i]}','    属性:',property,'    属性类型:',typeof property,'    属性值类型:',typeof target[property]);                   return target[property];            },            set: function(target, property, value, receiver){\n                    console.log('方法:set','    对象:${proxy_array[i]}','    属性:',property,'    属性类型:',typeof property,'    属性值类型:',typeof target[property]);                    return Reflect.set(...arguments);            }        }`;        eval(`            try {                ${proxy_array[i]};                ${proxy_array[i]} = new Proxy(${proxy_array[i]}, ${handler});            } catch (e) {                ${proxy_array[i]} = {};                ${proxy_array[i]} = new Proxy(${proxy_array[i]}, ${handler});            }        `)    }}

这样它会打印出调用的对象、属性等信息,这不就清晰多了。

我们在本案例测试,可以看到代码使用的全部环境了,然后看到哪些环境或者属性是 undefined 就把它补好。

代码展示

import jsonimport subprocessfrom functools import partialimport requestssubprocess.Popen = partial(subprocess.Popen, encoding="utf-8")  # 修改全局编码import execjs  # 必须在修改编码后引入with open('sm2Utils.js', 'r', encoding='utf8') as fr:    str_data = fr.read()js_code = execjs.compile(str_data)headers = {    "Accept": "application/json, text/javascript, */*; q=0.01",    "Accept-Language": "zh-CN,zh;q=0.9",    "Content-Type": "application/json;charset=UTF-8",    "Origin": "Origin",    "Referer": "Referer",    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",    "X-Requested-With": "XMLHttpRequest",    "encrypt": "1"}url = "url "params = {    "foreSessionClusterIntercept": "true"}post_data = {"token": "Epoint_WebSerivce_**##0601",             "params": {"categuids": "4bcbbec7-2428-403a-8eed-b0db5c0e01a5", "titlename": "", "currpage": 0,                        "pagesize": 10}}print('encrypt data: ', json.dumps(post_data, separators=(',', ':')))data = js_code.call('encrypt', json.dumps(post_data, separators=(',', ':')))print('encrypt result: ', data)response = requests.post(url, headers=headers, params=params, data=data, verify=False)print('request result: ', response.text)decrypt_result = js_code.call('decrypt', response.text)print('decrypt result: ', decrypt_result)
显示全文