JS逆向之浏览器补环境(一)

JS逆向之浏览器补环境(一)

简介

今天分享是是浏览器环境检测以及node js补环境

image-20220316154027340

我们点击检测设备信息看发出的请求,可以看到是sign和data

image-20220316154144257

这个data看起来像base64,我们试一下,发现不是

image-20220316154314765

分析加密位置

image-20220316154405883

可以看到经过混淆了

image-20220316154448202

我们选中看一下

image-20220316154508608

image-20220316154606258

那我们接下来就知道了,要逆向的两个参数变量

_0x392f2d
_0xd9e63f

我们直接把整个文件拷贝到webstrom里,看一下这两个变量在哪里定义的,可以看到在这

image-20220316154803280

由于我们只需要这两个变量,所以下面的代码可以删除了,变成这样

image-20220316154849200

追踪检测

然后引入proxy检测对象变化的代码

proxy.js

let _window = {
    
};
let _stringify = JSON.stringify;
JSON.stringify = function (Object) {
    // ?? 的意思是,如果 ?? 左边的值是 null 或者 undefined,那么就返回右边的值。
    if ((Object?.value ?? Object) === global) {
        return "global";
    }
    return _stringify(Object);
};

function getMethodHandler(WatchName) {
    let methodhandler = {
        apply(target, thisArg, argArray) {
            let result = Reflect.apply(target, thisArg, argArray);
            console.log(`[${WatchName}] apply function name is [${target.name}], argArray is [${argArray}], result is [${result}].`);
            return result;
        },
        construct(target, argArray, newTarget) {
            let result = Reflect.construct(target, argArray, newTarget);
            console.log(`[${WatchName}] construct function name is [${target.name}], argArray is [${argArray}], result is [${JSON.stringify(result)}].`);
            return result;
        }
    };
    return methodhandler;
}

function getObjHandler(WatchName) {
    let handler = {
        get(target, propKey, receiver) {
            let result = Reflect.get(target, propKey, receiver);
            if (result instanceof Object) {
                if (typeof result === "function") {
                    console.log(`[${WatchName}] getting propKey is [${propKey}] , it is function`);
                    //return new Proxy(result,getMethodHandler(WatchName))
                } else {
                    console.log(`[${WatchName}] getting propKey is [${propKey}], result is [${JSON.stringify(result)}]`);
                }
                return new Proxy(result, getObjHandler(`${WatchName}.${propKey}`));
            }
            console.log(`[${WatchName}] getting propKey is [${propKey}], result is [${result}]`);
            return result;
        },
        set(target, propKey, value, receiver) {
            if (value instanceof Object) {
                console.log(`[${WatchName}] setting propKey is [${propKey}], value is [${JSON.stringify(value)}]`);
            } else {
                console.log(`[${WatchName}] setting propKey is [${propKey}], value is [${value}]`);
            }
            return Reflect.set(target, propKey, value, receiver);
        },
        has(target, propKey) {
            let result = Reflect.has(target, propKey);
            console.log(`[${WatchName}] has propKey [${propKey}], result is [${result}]`);
            return result;
        },
        deleteProperty(target, propKey) {
            let result = Reflect.deleteProperty(target, propKey);
            console.log(`[${WatchName}] delete propKey [${propKey}], result is [${result}]`);
            return result;
        },
        getOwnPropertyDescriptor(target, propKey) {
            let result = Reflect.getOwnPropertyDescriptor(target, propKey);
            console.log(`[${WatchName}] getOwnPropertyDescriptor  propKey [${propKey}] result is [${JSON.stringify(result)}]`);
            return result;
        },
        defineProperty(target, propKey, attributes) {
            let result = Reflect.defineProperty(target, propKey, attributes);
            console.log(`[${WatchName}] defineProperty propKey [${propKey}] attributes is [${JSON.stringify(attributes)}], result is [${result}]`);
            return result;
        },
        getPrototypeOf(target) {
            let result = Reflect.getPrototypeOf(target);
            console.log(`[${WatchName}] getPrototypeOf result is [${JSON.stringify(result)}]`);
            return result;
        },
        setPrototypeOf(target, proto) {
            console.log(`[${WatchName}] setPrototypeOf proto is [${JSON.stringify(proto)}]`);
            return Reflect.setPrototypeOf(target, proto);
        },
        preventExtensions(target) {
            console.log(`[${WatchName}] preventExtensions`);
            return Reflect.preventExtensions(target);
        },
        isExtensible(target) {
            let result = Reflect.isExtensible(target);
            console.log(`[${WatchName}] isExtensible, result is [${result}]`);
            return result;
        },
        ownKeys(target) {
            let result = Reflect.ownKeys(target);
            console.log(`[${WatchName}] invoke ownKeys, result is [${JSON.stringify(result)}]`);
            return result;
        },
        apply(target, thisArg, argArray) {
            let result = Reflect.apply(target, thisArg, argArray);
            console.log(`[${WatchName}] apply function name is [${target.name}], argArray is [${argArray}], result is [${result}].`);
            return result;
        },
        construct(target, argArray, newTarget) {
            let result = Reflect.construct(target, argArray, newTarget);
            console.log(`[${WatchName}] construct function name is [${target.name}], argArray is [${argArray}], result is [${JSON.stringify(result)}].`);
            return result;
        }
    };
    return handler;
}
_window = Object.assign(global, _window);
const window = new Proxy(Object.create(_window), getObjHandler("window"));
module.exports = {
    window
};

在拷贝到webstrom里的代码进行导入

const {window} = require("../tools/proxy");

然后我们运行之前拷贝到webstrom里的代码

image-20220316160543376

发现在window上需要定义一个XMLHttpRequest,那是定义在window上呢,还是定义在它的原型链上呢,我们可以浏览器里看一下

第一个是检查对象自身的属性,第二是检查所有属性。因此我们需要定义在它的原型上

image-20220316160907768

修改追踪的代码

image-20220316161447079

然后我们打印看一下,发现也没有问题

image-20220316161521002

我们再运行以下之前的代码,发现需要navigator

image-20220316161654173

那我们也补上

let _window = {
    XMLHttpRequest: function (){},
};
let _navigator = {

};
_window = Object.assign(global, _window);
const window = new Proxy(Object.create(_window), getObjHandler("window"));
const navigator = new Proxy(Object.create(_navigator), getObjHandler("navigator"));
module.exports = {
    window,
    navigator,
};

image-20220316161843034

然后又要这个,同理

image-20220316161914701

image-20220316162020706

image-20220316162035672

发现没有问题了,也拿到了sign和data

image-20220316162059446

python调用

然后我们通过python试一下

image-20220316162839091

然后到在线工具里转一下

https://tool.lu/curl/

image-20220316162929633

发现直接被检测到了,就是我们的环境检测没有通过

image-20220316163325740

补环境

我们可以看到有一堆undefined,这些都是我们需要补的环境

image-20220316163459202

然后我们要看一下这个值在浏览器里是怎么样的,并且是定义在对象上还是原型上,比如navigator来说,发现是定义在原型上的。

image-20220316163945631

然后就照着补就行了

注意这个,getOwnPropertyDescriptor是拿的自身属性上的

image-20220316164211915

最后补的结果

let _window = {
    XMLHttpRequest: function (){},
    sessionStorage: function (){},
    localStorage: function (){},
};
let _navigator = {
    userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.39",
    appCodeName: "Mozilla",
    plugins: {
        length: 0
    },
};
let _screen = {
    colorDepth: 24,
    height: 900,
    width: 1440,
};
_window = Object.assign(global, _window);
const window = new Proxy(Object.create(_window), getObjHandler("window"));
const navigator = new Proxy(Object.create(_navigator), getObjHandler("navigator"));
const screen = new Proxy(Object.create(_screen), getObjHandler("screen"));
module.exports = {
    window,
    navigator,
    screen,
};

再跑一次,拿着data和sign去请求,通过!

image-20220316165302878

另一种操作(不推荐)

使用JSDOM自带的浏览器环境

安装

npm install jsdom

使用

const jsdom = require("jsdom");
const {JSDOM} = jsdom;


const {window} = new JSDOM(``);
const navigator = window.navigator;
const screen = window.screen;
// 这个是缺啥补啥 基本都齐了
window.XMLHttpRequest = function XMLHttpRequest() {
};
module.exports = {
    window,
    navigator,
    screen
};

导入

image-20220316180345893

但是会出现各式各样的问题,不推荐

image-20220316180416200

先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

猜你喜欢

转载自blog.csdn.net/m0_67401660/article/details/126061398