JS逆向之原型链补环境
前置知识:JS逆向之补环境入门_js逆向补环境-CSDN博客
参考资料:Object.getOwnPropertyDescriptor() - JavaScript | MDN
简单回顾一下:
node环境和JS环的只要差异
主要环境
一些指纹常见浏览器指纹字段
非原型链检测
function get_result() {try {if (navigator['userAgent']) {return '正确数值'}else{return '错误数值'}} catch {return '错误数值'}
}console.log(get_result())
在node是返回错误信息
而在浏览器环境里却是正确的值
又不报错,怎么校验正确呢,要么联调,要么吐环境,补环境试试
function get_enviroment(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, ' +// '" 属性值:", ' + 'target[property], ' +'" 属性值类型:", typeof target[property]);\n' +// 'if (typeof target[property] == "undefined"){debugger}' +' return target[property];\n' +' },\n' +' set: function(target, property, value, receiver) {\n' +' console.log("方法:", "set ", "对象:", ' +'"' + proxy_array[i] + '" ,' +'" 属性:", property, ' +'" 属性类型:", ' + 'typeof property, ' +// '" 属性值:", ' + 'target[property], ' +'" 属性值类型:", typeof target[property]);\n' +' return Reflect.set(...arguments);\n' +' }\n' +'}'eval('try{\n' + proxy_array[i] + ';\n'+ proxy_array[i] + '=new Proxy(' + proxy_array[i] + ', ' + handler + ')}catch (e) {\n' + proxy_array[i] + '={};\n'+ proxy_array[i] + '=new Proxy(' + proxy_array[i] + ', ' + handler + ')}')}
}
proxy_array = ['window', 'document', 'location', 'navigator', 'history', 'screen', 'div', 'script']
get_enviroment(proxy_array)
但在爬虫中值错误了,吐出环境然后补环境
过了!
但这毕竟没有效验原型链
原型链检测
用Object.getOwnPropertyDescriptor判断属性是不是从原型获取的。
Object.getOwnPropertyDescriptor()
想在node环境里
navigator = {}
navigator.userAgent = '13242'console.log(Object.getOwnPropertyDescriptor(navigator,'userAgent'))
输出
在浏览器环境
类似简单判断检测
navigator = {}
navigator.userAgent = '13242'
function get_hhh()
{if (Object.getOwnPropertyDescriptor(navigator,'userAgent')){return '错误数据'}else{return '正确数据'}
}
node环境
浏览器环境
判断有没有原型链接检测
在吐环境脚本这里加上Object
吐出环境
有Object对象不要紧,但Object对象里有getOwnPropertyDescriptor这个属性说明有原型链检测。
原型链概念
总结一句话
对象查属性时,先找自己,找不到就沿着 [[Prototype]]
一路向上找,直到 null,这条链路就是原型链。
像类继承
class Person{constructor(name) {this.name = name}drink(){console.log('喝水')}
}class Teacher extends Person{constructor(name, subject) {super(name)this.subject = subject;}introduce(){console.log(`我是${this.name}, 教的${this.subject}`)}
}var teacher = new Teacher('kkk', 'python')
console.log(teacher)
teacher.introduce()
在浏览器输出
你发现对象teacher只有两个属性,却能调用introduce()函数,
点击[[Prototype]],
introduce()函数在他原型里。
像subject是自身属性,判断获取对象“自身”属性,而introduce是原型的属性,判断获取undefined,而对象本身没有属性,去原型也就是父类找,找到null为止。这样的一条类路就是原型链。类也有原型,通过.prototype获取原型
继承于谁,谁就是原型
原型链补属性
navigator = {}
navigator.userAgent = '13242'
在浏览器测试,navigator原型是哪个
Navigator = function Navigator(){}
Navigator.prototype.userAgent = '12132432'
navigator = new Navigator()
console.log(Object.getOwnPropertyDescriptor(navigator, 'userAgent'));
原型链补方法
举例document
document = {}document.createElement = function ()
{}
console.log(Object.getOwnPropertyDescriptor(document, 'createElement'));
在浏览器判断
在原型的原型上
最低原型是大写的Document
Document = function Document(){}
第二是HTMLDocument
HTMLDocument = function HTMLDocument(){}
将他们原型绑定
Object.setPrototypeOf(HTMLDocument.prototype,Document.prototype)
往原型赋值方法
Document.prototype.createElement = function(args) { }
Document = function Document(){}
HTMLDocument = function HTMLDocument(){}
HTMLDocument.prototype = Document
//
Object.setPrototypeOf(HTMLDocument.prototype,Document.prototype)
Document.prototype.createElement = function(args)
{
}document = new HTMLDocument()
console.log(Object.getOwnPropertyDescriptor(document,'createElement'))
console.log(Object.getOwnPropertyDescriptor(document.__proto__,'createElement'))
console.log(Object.getOwnPropertyDescriptor(document.__proto__.__proto__,'createElement'))
输出
原型链补对象
head标签,也是对象
head = {}
Document = function Document(){}
HTMLDocument = function HTMLDocument(){}
Object.setPrototypeOf(HTMLDocument.prototype,Document.prototype)
Document.prototype.head = {}
console.log(Object.getOwnPropertyDescriptor(document.__proto__.__proto__,'head'))
toString检测
有些环境可能会检测toString
像nodeJS,直接输出toString()
直接输出
在node环境补,直到与浏览器一样
Document = function Document(){}
HTMLDocument = function HTMLDocument(){}//
Object.setPrototypeOf(HTMLDocument.prototype,Document.prototype)
Document.prototype.createElement = function createElement()
{
}
Document.prototype.createElement.toString = function toString()
{return 'function createElement() { [native code] }'
}
document = new HTMLDocument()
console.log(document.createElement)
console.log(Object.getOwnPropertyDescriptor(document,'createElement'))
console.log(Object.getOwnPropertyDescriptor(document.__proto__,'createElement'))
console.log(Object.getOwnPropertyDescriptor(document.__proto__.__proto__,'createElement'))
console.log(Document.prototype.createElement.toString())
多原型补法
window = global
window.addEventListener =function (args){}
已知原型是 这三个
EventTarget = function EventTarget(){}
WindowProperties = function WindowProperties(){}
Window = function Window(){}
两两绑定
Object.setPrototypeOf(WindowProperties.prototype,EventTarget.prototype)
Object.setPrototypeOf(Window.prototype,WindowProperties.prototype)
最后赋值初始化对象
EventTarget.prototype.addEventListener =function addEventListener(args){ } window = new Window() console.log(Object.getOwnPropertyDescriptor(window.__proto__.__proto__.__proto__,'addEventListener'))
多原型的话,从高到低两两绑定就可以了
EventTarget = function EventTarget(){}
WindowProperties = function WindowProperties(){}
Window = function Window(){}
Object.setPrototypeOf(WindowProperties.prototype,EventTarget.prototype)
Object.setPrototypeOf(Window.prototype,WindowProperties.prototype)
EventTarget.prototype.addEventListener =function addEventListener(args){
}
window = new Window()
console.log(Object.getOwnPropertyDescriptor(window.__proto__.__proto__.__proto__,'addEventListener'))