web逆向中奇葩的document.all
一、简介
document.all是IE 4.0及以上版本的专有属性,是一个表示当前文档的所有对象的数组,不仅包括页面上可见的实体对象,还包括一些不可见的对象,比如html注释等等。在document.all数组里面,元素不分层次,是按照其在文档中出现的先后顺序,平行地罗列的。所以可以用数字索引来引用到任何一个元素。但比较常用的是用对象id来引用一个特定的对象,比如document.all[“id”],随着其他浏览器的发展,由于document.all的兼容性、性能原因已经被废弃,逐渐由getElementById、getElementsByClassName、、getElementsByTagName等方法所替代。但是,document中依然保留这该属性,不过该属性是个对象,却是个undefined类型(可参考下图),而在node中并不能实现一个对象既是object又是undefined类型,所以在逆向中就成了特殊的环境检测
二、通过node插件实现document.all
1.编写node插件需要依赖c++环境,可通过visual studio直接安装就行
2.在项目下新建nodePlugin>faker.cc
#include <node.h>
namespace faker {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Value;
using v8::Context;
using v8::FunctionTemplate;
using v8::Array;
using v8::String;
static void ReturnThis(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(args.This());
}
void DocumentAll(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<FunctionTemplate> desc = FunctionTemplate::New(isolate);
desc->InstanceTemplate()->MarkAsUndetectable();
desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis);
Local<Object> obj = desc->GetFunction(context).ToLocalChecked()
->NewInstance(context).ToLocalChecked();
Local<Array> arr = Local<Array>::Cast(args[0]);
for (uint32_t i = 0; i < arr->Length(); i++) {
Local<Value> value = arr->Get(context, i).ToLocalChecked();
obj->Set(context, String::NewFromUtf8(isolate, std::to_string(i).c_str()).ToLocalChecked(), value);
}
args.GetReturnValue().Set(obj);
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "DocumentAll", DocumentAll);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
}
3.在nodePlugin目录下新建binding.gyp
{
"targets": [
{
"target_name": "faker",
"sources": [ "faker.cc" ]
}
]
}
4.安装gyp环境:npm install -g node-gyp
5.进入nodePlugin目录,生成配置 node-gyp 构建环境:node-gyp configure
6.进入nodePlugin目录,生成插件:node-gyp build
7.在nodePlugin目录下新建testFaker.js测试
const faker = require('./build/Release/faker');
document = {};
document.all = faker.DocumentAll(['a','b']);
function HTMLAllCollection() {}
document.all.__proto__ = new HTMLAllCollection();
console.log("document.all:", document.all);
console.log("typeof document.all:", typeof document.all);
console.log("document.all==undefined:", document.all==undefined);
console.log("Object.getPrototypeOf(document.all):", Object.getPrototypeOf(document.all).toString());
console.log("document.all.__proto__:", document.all.__proto__.toString());
8.运行testFaker.js文件,查看控制台会发现,控制台上虽然document.all输出的是个对象,但是document.all==undefined返回true,与之前浏览器控制台上输出的一模一样