免责声明:这个只是我做的学习记录,内容可能有点混乱,如果你发现了错误请指出来。
相关介绍
到目前为止,我一直在挖掘web漏洞,但是我做的越多,我就越觉得我只是停留在表面上。我想深入挖掘软件层漏洞并深入了解二进制文件。
在观察一段时间后,我认为我需要专注于某些事情。为了达到这一点,我选择了Web浏览器作为挖掘对象,或者更确切地说是选择了Javascript引擎。
大约在同一时间,LiveOverflow开始发布有关该主题的精彩视频:
https://www.youtube.com/watch?v=5tEdSoZ3mmE(部分0x00)
https://www.youtube.com/watch?v=yJewXMwj38s(部分0x01)
我的目标是挖掘出可用漏洞,没有选择JavaScriptCore,而是选择了V8引擎,我将使用Windows / WinDbg作为环境。
编译V8
第一步是在我们的机器上安装V8。以下链接会提供帮助:
https://blog.angularindepth.com/how-to-build-v8-on-windows-and-not-go-mad-6347c69aacd4
http://www.lfdm.net/development/5-how-to-compile-v8-on-windows.html
这个需要一些时间,这两个教程都使用is_debug = false对其进行编译,但是你应该将其设置为true,因为我们需要调试版本。
使用use_jumbo_build = true和is_compoment_build = false将加快构建过程。
现在我编译的是最新版本,但是学习编译旧版本以便在某些时候分析过去的漏洞也是有用的。
运行V8
V8 shell/debugger名为D8,它位于:
[path_to_v8_folder] \ out.gn \ [build_name] \ d8.exe
你应该使用–allow-natives-syntax flag运行它,以便访问DebugPrint等本机函数:
与JavaScript Core相比,V8中对象的内存布局和内部概念完全不同,V8的垃圾回收机制似乎也有不同的工作方式。
内部类型似乎也被不同地调用,即只有整数的数组是PACKED_SMI_ELEMENTS,而具有整数和双精度的数组是PACKED_DOUBLE_ELEMENTS,如果其中有空格,则数组将变为HOLEY而不是PACKED:
调试V8
我使用WinDbg作为调试器
第一步相对简单。运行D8并从WinDbg连接到该进程,也可以直接从WinDbg运行D8可执行文件。完成后,可以按F5继续运行该程序。
让我们尝试创建一个包含几个字符串的数组,并在其上执行DebugPrint:
在“elements”下,看到了存储数组元素的地址 ,在这种情况下,元素是指向字符串的两个指针。我们可以尝试查看WinDbg中数组元素的地址。
我们将看到指向第一个字符串的指针,这是小端存储的,如果我们去那个地址,会找到字符串:
如果用整数数组做相同操作,数组不会由指针组成,而是由我们定义的整数组成:
如果转到“元素”地址会看到它们:
有意思的是,LiveOverflow示例中的整数在他的0x01视频中展示了一些高字节设置为FFFF。那是因为JS Core使用的是NaN-boxing,而V8则没有使用,存储数组的方式似乎有些不同,没有提到结构ID。
看起来这些是JS Core的概念,但我们仍然需要了解V8内部的工作原理。
在结束第一部分之前还有一件事要尝试:可以在Math.max上设置一个断点,首先,我们需要找到该函数以设置断点,可以在WinDbg中搜索这样的符号:
X v8!* Mathmax *
得到结果:
然后设置一个断点:
bp v8!Builtins_MathMax
然后在D8中运行Math.max并且命中断点:
打开调用堆栈窗口,我可以看到用于调用堆栈中的大多数函数的源代码。
谷歌搜索了一下后,我遇到了这个:
https://v8.dev/docs/csa-builtins
事实证明,许多内置函数不是在C ++中完成的,而是在汇编中硬编码或使用CodeStubAssembler基础结构实现。但有些仍然是用C ++编写的。通过浏览源代码,我发现Math.hypot应该是这样的函数之一。所以我尝试在bp v8上设置一个断点!我再次运行触发断点,但结果仍然相同。
我已经在源代码中直接设置了断点,当我点击它时,我能够逐步查看源代码!我也注意到我之前的错误是我在v8上设置了一个断点是在Builtin_MathHypot而不是v8 :: internal :: Builtin_MathHypot。
我对目前的进展还算满意,后面会继续学习JS类型的内存表示。