![eda61dd7ed885e7ecdb9faae0998faa3.png](https://i-blog.csdnimg.cn/blog_migrate/c776e34ad86570d96d0f3679e667c26b.png)
所有文章首发在我的微信公众号“逆向新手”,更多逆向系列请关注公众号,谢谢!
写在前面
由于最近好多小伙伴问我怎么伪造canvas等浏览器环境,故写了这篇文章供参考。
说到浏览器环境与本地环境,不得不先解释下全局对象。在浏览器环境,全局对象即为 window 对象,而在本地node环境,全局对象为 global 。两者有一定差别,简单点说,window对象下有的方法或属性,global对象不一定有。反之,global对象下有的,window对象基本都有。
我们定义的全局变量或全局方法,都将会挂在全局对象下,因此在本地,可以使用 http://global.XXX 或 XXX 来调用。而浏览器环境中的代码,基本都是通过 http://window.XXX 来调用,所以我们可以在开头定义这么一句:
window = global;
这句的意思就是,定义一个全局变量名为window,给它赋值为global对象,后面即可在本地通过 http://window.XXX 来调用全局属性或方法,这样便契合了浏览器的环境。以下为global对象自带的全部属性与方法:
![9e976f2476088c3e4f8dd8d2d64595ed.png](https://i-blog.csdnimg.cn/blog_migrate/65b1c3ac16810026ba8a2d980ba7a715.jpeg)
但在实际逆向过程中,并不一定非要这么定义,其实都得根据具体代码来写。只要遵循一个原理即可:缺啥补啥。
举例说明
了解了前面的概念后,下面直接开始举例说明吧!以下例子仅供参考,实际运用过程请自行修改。
一、Canvas
要想完美模拟一个环境,首先得先知道它的作用,下面带大家大致了解下Canvas的运行逻辑,具体属性与方法的作用还请自行百度。
1.创建canvas画布
![a21390c85739baf1b0f6af88edf534b0.png](https://i-blog.csdnimg.cn/blog_migrate/03ad5df35de59d00543c682602d87be2.jpeg)
2.修改画布属性:字体、颜色、填充文字等
![ca383117a45bdff4a79129d806e96b8d.png](https://i-blog.csdnimg.cn/blog_migrate/0caae9982fa2add90c47ae3c86a377e9.png)
3.随便再画点圆和路径,最后将画好的转为图片链接
![ccd515bfc551f3b50da3eea8fd1faa60.png](https://i-blog.csdnimg.cn/blog_migrate/3abf086ead295785a166bd1a9460e715.png)
打开这个链接看一下
![ef12526a201a5aaae0810783dcc8f1a1.png](https://i-blog.csdnimg.cn/blog_migrate/7e8903a488882aff8e6c0b5cdf9698c7.jpeg)
逻辑知道了,现在可以开始伪造了。本地不需要这么复杂,只需要看它调用了什么方法,返回了什么值,然后对对象做了什么变化即可。根据上面的逻辑,本地可构造如下:
document = {
createElement: function() {
return canvas
}
};
canvas = {
getContext: function getContext() {
return CanvasRenderingContext2D
},
toDataURL: function toDataURL() {
return "data:image/png;base64,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"
},
};
CanvasRenderingContext2D = {
arc: function arc() {},
stroke: function stroke() {},
fillText: function fillText() {},
};
像font、shadowColor等,只是在为CanvasRenderingContext2D对象赋值,因此不用构造。而arc、stroke等函数的返回值均为undefined,因此直接置空即可。最后运行如下,成功获取链接。
![d9443cf6972ce37011890d1fccb2ee8b.png](https://i-blog.csdnimg.cn/blog_migrate/0f8d8495754fc99b2e1664ce1981a0a6.jpeg)
二、LocalStorage
同样先看下它的运行逻辑。setItem为它设置一对键值对,getItem获取指定键的值,不存在为null,removeItem删除键值对
![084249aec1ee0ebc04a329c09d01d72f.png](https://i-blog.csdnimg.cn/blog_migrate/44a6edc503df663cff849f3954c57247.png)
因此可构造如下:
localStorage = {
removeItem: function (key) {
delete this[key]
},
getItem: function (key) {
return this[key] ? this[key]: null;
},
setItem: function (key, value) {
this[key] = "" + value; // 将数字转为字符串
},
};
运行如下:
![aa2cd3a72c7d3624e76d0d93396a1766.png](https://i-blog.csdnimg.cn/blog_migrate/5abde7198ed906fc1a7420efb293ebb2.jpeg)
三、标签的href属性
首先查看location及创建标签后的href属性值
![13b628e1b0f7e47ec08e86f92322c293.png](https://i-blog.csdnimg.cn/blog_migrate/9302ccce7f30d133340978ba1df78a48.jpeg)
然后多次赋值查看其逻辑
![fe78122d82f0462d90d2beea07ddcbee.png](https://i-blog.csdnimg.cn/blog_migrate/65f6a14c8b324e96935c117c31b5b62e.jpeg)
可以看到大致分为4种情况,我直接用代码表达:
location = {
"href": "https://www.w3school.com.cn/jsref/prop_anchor_href.asp",
"origin": "https://www.w3school.com.cn",
"protocol": "https:",
}
document = {
createElement: function () {
var loc = {
href: ""
};
var temp_href = loc.href;
Object.defineProperty(loc, 'href', {
// Hook loc.href,当为其赋值时,按下面的规则强制改变
get: function () {
return temp_href
},
set: function (val) {
if (val.indexOf('http://') === 0 || val.indexOf('https://') === 0) {
// 1.当值为http://或https://开头时,即为该值
temp_href = val;
} else if (val.indexOf('//') === 0) {
// 2.当值为//开头时,即为location.protocol加上该值
temp_href = location.protocol + val;
} else if (val.indexOf('/') === 0) {
// 3.当值为/开头时,即为location.origin加上该值
temp_href = location.origin + val;
} else {
// 4.除以上3种情况,即为location.href中最后一个/之前的值加上该值
var s = location.href
temp_href = s.substring(0, s.lastIndexOf("/")+1) + val
}
return temp_href
}
});
return loc;
}
}
最终运行成果:
![99f50ce851e0b19b4ef03fd6782b28a1.png](https://i-blog.csdnimg.cn/blog_migrate/4058f1c26fcfb27f1c62a45c26fa9a68.jpeg)
总结
经过上面几个例子说明,可对伪造浏览器环境步骤总结如下:
1.在浏览器中分析需要伪造的环境运行逻辑
2.本地魔改,想怎么写怎么写,最终运行结果一致就行
其实伪造浏览器环境,并没有固定的写法,思维有多发散,伪造得就可以有多骚,真的可以说是天马行空,任你造。本文仅提供思路,欢迎有更好想法的小伙伴一起交流~
欢迎关注我的公众号“逆向新手”,逆向系列将持续更新!