首页
社区
课程
招聘
[原创] 第八届“强网”拟态防御国际精英挑战赛 - Cherry
发表于: 2025-12-3 19:40 1753

[原创] 第八届“强网”拟态防御国际精英挑战赛 - Cherry

2025-12-3 19:40
1753

拟态决赛的时间在工作日,听说有一道 JerryScript 的 Pwn 题。作为苦逼打工人,周五抽空尝试做了一下。当时构造出 8 字节的越界读写后,一直尝试利用,但由于 GC 的原因一直没有成功,时间比较短,如果再多些时间应该也是可以利用成功的

不过在调试过程中,了解了该引擎的一些机制,发现相比 v8 还是简单很多的。赛后与其他师傅交流,才发现原来可以通过 Patch 中的漏洞实现任意长度的越界读写。因此尝试复现了一下,诞生了这篇 writeup。

题目给了几个程序运行的链接库,看了下版本是Ubuntu GLIBC 2.39-0ubuntu8.6,由于我本地位wsl2 ubuntu22版本,所以patch了一下

查看jerryscript的版本信息

接着本地编译一个,最后会看到build/bin目录下有一个jerry的可执行文件

类型的定义位于这个文件中jerryscript/jerry-core/ecma/base/ecma-globals.h

ecma_object_t是类型header的开始部分,其中主要的字段有type、gc_next_cp、u1、u2

其中的u1和u2分别代表properties和prototype相关,不是每一个对象都有这两个字段

type_flags_refs中的Type就指的是类型,但是并不像v8那样细分为object arr、double arr……

其中的refs,这个对于利用的稳定性比较重要,如果产生了越界,可以通过修改这个字段不让改对象被gc回收,从而保持布局的稳定性。

然后笔者在实际利用过程中并没有这样,当时没有意识到,回头翻看源码的时候才发现。所以采用了人为构造函数进行ref,增加ref count

下面是一个简单的图示

接着的gc_next_cp是用于gc回收时扫描对象而设立的字段,u1与properties相关,在受限的情况下,可以采用修改和这个字段的方式进行类型混淆,u2和原型链有关,暂时也没想到这个怎么用

笔者尝试过,当时由于稳定性的原因,没有构造出很好用的原语,等待后续研究……

下面是ecma_extended_object_t结构体

简化完毕其实是这样。ecma_object_t object和一个union u

其中的object就是上方的通用类型的header,对于复杂类型会使用到ecma_extended_object_t,其中的union u会根据不同的类型选择不同的字段,以此定义不同对象的属性字段

下面笔者迁移了部分v8 exploit的知识,通过ai写出了一个针对于jerryscript调试的gdb插件,提升了调试的效率

这里以dataview为例子

dataview的定义

arraybuffer的定义

实际内存中是这样的,后方的0x10是对应的byte_offset。0x64eccc323748是arraybuffer的地址

注意下方的0x41414141,这里是对应的inline表示,这个并不利于后续的利用,这个是利用的后话了

如何让arraybuffer分配出一个raw pointer呢?这里只需要提高arraybuffer分配的大小即可,我这里提升到了0x1000

diff的内容

删去了一个对于nan的检查,定位源码可以找到代码的上下文,调用函数是[A] ecma_op_to_integer,从而可以找到上层的调用上下文分别是[B] ecma_op_to_length和[C] ecma_op_to_index函数

接着就是更上层的调用查找,对于ecma_op_to_length来说,更多的是倾向于被字符串和regexp的处理,如果存在漏洞,那么品相也不一定很好,所以我这里继续看了ecma_op_to_index的上层调用

ecma_op_to_index的上层调用如下,这里可以看到很具有代表意义的两个对象,dataview和typearray,如果熟悉v8 exploit的话,这里两个对象的嫌疑最大 ,事实也确实如此,所以接下来继续审计dataview相关的实现

typearray的代码似乎没有很明显的漏洞,因此主要审计了dataview

首先我们得看一下jerryscript中的dataview对象的结构,所有对象的结果为与这个文件下jerryscript/jerry-core/ecma/base/ecma-globals.h

可以看到使用了ecma_extended_object_t的header,这个是对于复杂对象的header,其中集成了ecma_object_t的内容。接着又一个buffer_p指针,这个其实指向了Arraybuffer,接着是对应的byte_offset,用户索引Arraybuffer中的偏移

接着看Arraybuffer的对象结构,结构很简单,其中的buffer_p也就类似于v8中的backingstore

接着可以动态的看一下,测试代码入下

其中地址0x62e46178e5f0中的dword 0x10就是这里设置的byte_offset

同时dataview还支持这样的语法,也就是会有一个view_offset,下发设置了view_offset为0x10,但是索引了0x20的位置,这个是不合法的,会报错

审计代码路径位于jerryscript/jerry-core/ecma/operations/ecma-dataview-object.c

先审计ecma_op_dataview_create这个函数,关于dataview对象的创建,代码如下

这里首先会通过参数列表获取到buffer,这个就是Arraybuffer,接着会检查这个用户传入的Arraybuffer的值是否合法,也就是真实类型是否为Arraybuffer

接着通过参数列表为offset赋值,同时检查是否有问题,可以看到上方[a]处调用了ecma_op_to_index,这个函数涉及到nan的处理,正常遇到nan会将nan清空为0,并返回正常的状态码ECMA_VALUE_EMPTY,但是这里没有清空,所以会正常绕过这个检查,并保留原有的nan的值

接着获取Arraybuffer的长度,并赋值给buffer_byte_length。然后进入if (offset > buffer_byte_length)判断

问题其实就出现在这个地方,这里的比较逻辑是将nan的值从栈上取出来,赋值给xmm0,也就是浮点数寄存器,接着调用comisd进行比较。

需要注意的在 x86/x64 汇编中,comisd 指令在遇到 NaN 时,如果任一操作数是 NaN,它会设置 ZF=1, PF=1, CF=1,接下来的jbe,它的跳转条件是 CF=1 或 ZF=1,所以这里只要涉及到NaN的比较,这里都会被解释成offset <= length,结果就是绕过这个bound check

调试下eflag,没有比较之前是这样

比较之后是这样,成功绕过了这个检查

现在可以得到一个结论,对于这个检查if (offset > buffer_byte_length)

offset = NaN 时,可以直接pass

同样的,这个绕过模式还可以传播为(NaN + arb_val > buffer_byte_length)→false,所以我们可以在NaN后面加上任意偏移,这个也就是上方的[b]处,if (offset + byte_length_to_index > buffer_byte_length)

进入[b]处也很简单,参数是三个就行,也就用到了上方的语法

这里,我将view_byte_length设置为0xfffffff,buffer_byte_length仅为0x100,但是由于offset是nan,所以此时的eflag如下,也就绕过了bound check

最终的NaN被类型转化为uint32_t变成0,但是view_byte_length成功赋值为0xffffffff。至此我们已经成功构造了一个存在越界的dataview对象,我们现在需要接着分析对于dataview的get和set操作,看一下是否可以将这个漏洞扩大,变成一个可以越界读写的原语

有了阅读ecma_op_dataview_create的经验,我们其实只需要找这个函数中对于边界检查的部分,通过最后的对象属性赋值部分来验证猜想,所以这个函数的代码被精简如下

构造的调试代码如下,这里是构造了一个dv的越界越界读操作

首先分析上面的源码

注释1-3部分是对于dataview header和arraybuffer header的检查,如果说单纯修改指针,那么这个检查过不去是没用的

接着直接来到上方[a]部分,也就是这里的边界检查if (get_index + element_size > (ecma_number_t) view_size),这个逻辑很正常,就是检查用户传入的index+取出的elment size是否超过了views_size。

但是需要注意的是这里的view_size已经被我们修改成了0xffffffff,所以这里相当于直接绕过了这个检查

下方的getindex是0x200,已经超过了arraybuffer的长度,但是由于view_size被修改,所以越界了,后续就是存值取值的操作

由于笔者也是第一次接触jerryscript的利用,所以最后的脚本经过大量调试得到,所以笔者这里就解释下写利用的思路

我们之前已经得到了一个越界的dv,现在需要思考如何可控。

上面提到了可以通过申请0x1000这样length的arraybuffer,这样就可以让arraybuffer不inline表示,从而分配出一个raw pointer。因此可以通过一个越界的dv去读取内存后方arraybuffer中的buffer_p字段,那么现在至少存在了一个jerry heap的地址。

接着的问题是如何去定位这个arraybuffer,首先我需要保证我的越界dv地址在受害arraybuffer的前方,所以需要调试一下,这里发现是没有问题的

最简单的定位思路就是写一个特征值,但问题是这样只能扫描到特征值的位置,我们通过特征值的位置无法定位到arraybuffer指向的位置。像下面红框中一样,只能扫描到这个值,但是无法反推。

解决这个问题就需要思考arraybuffer的特征,arraybuffer的特征由前面的0x10个字节的header决定,下发的四个字段中有type、gc_next、prototype……

因此我选取了Type、ProtoType、ByteLength,这三个字段在我堆喷出来的对象中是一致的,所以我可以通过header的字段来确定受害arraybuffer的位置,那么相邻的就是jerry_global_heap段上的值

可以得到这样的一个leak,通过减去0x11a30可以得到一个段开头的地址,但是这个是随机的,根据你写的脚本和环境决定

所以为了稳定性我进行了如下的计算,最后的情况是在多0x9000和少0x9000的情况下摆动

可以看到jerry_global_heap起始地址是这个段的开头+0x280

同时这个jerry_global_heap开头的一段内存上是存在函数指针的值,所以我们接下来需要思考如何去利用这个jerry_global_heap来泄漏出code_base、libc等值

通过上方的思路,确实定位到了受害arraybuffer的位置,但是由于这里的arraybuffer是堆喷出来的(如下所示),所以我还需要确定这个arrybuffer的具体位置

确定受害arraybuffer的思路是也很清晰,我这里已经可以越界读定位到受害arraybuffer的header,所以可以通过越界写修改arraybuffer的byteLength字段,然后遍历所有的arraybuffer来检查哪一个对象的byteLength被修改了,至此我们已经可以准确定位arraybuffer了

定位到arraybuffer,下面的任意读写就是修改buffer_p字段,然后调用dataview的get/set方法即可

这里是为了提高任意读写的稳定性,如何笔者发现完成一次任意读写这里就会触发gc移动,如果此时的buffer_p是一个gc无法回收的地址,那么就会程序崩溃,所以解决思路也很简单,任意读写完毕之后,把原本的buffer_p再修改回去。

同时,为了防止原本布置的victim对象被gc回收,可以通过如下方式增加ref count

也可以通过上面笔者提到的思路,直接利用越界去修改ref count的值,这样也可以

存在任意读写之后,可以通过读jerry_global_heap段开头的一些handler函数的值,确定code base的值,从而定位到got,然后泄漏位于libc中函数的值

这里笔者由于很久没有接触house of打法,已经不知道2.39应该怎么做了,所以这里采用了通过environ泄漏栈地址的方式,然后劫持main函数的返回地址,实现rop

本地测试时堆地址会在这两个之前变化,一个没打通试另外一个就可以了

成功则会有如下显示

➜  jerry ./jerry --version                               
Version: 3.0.0 (b7069350)
➜  jerry ./jerry --version                               
Version: 3.0.0 (b7069350)
git clone https://github.com/jerryscript-project/jerryscript.git
cd jerryscript
git checkout b7069350
patch -p1 < ../patch
python tools/build.py --debug --lto=off
git clone https://github.com/jerryscript-project/jerryscript.git
cd jerryscript
git checkout b7069350
patch -p1 < ../patch
python tools/build.py --debug --lto=off
typedef struct
{
  /** type : 4 bit : ecma_object_type_t or ecma_lexical_environment_type_t
                     depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV
      flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
                      ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_BLOCK
      refs : 10 / 26 bit (max 1022 / 67108862) */
  ecma_object_descriptor_t type_flags_refs;
 
  /** next in the object chain maintained by the garbage collector */
  jmem_cpointer_t gc_next_cp;
 
  /** compressed pointer to property list or bound object */
  union
  {
    jmem_cpointer_t property_list_cp; /**< compressed pointer to object's
                                       *   or declerative lexical environments's property list */
    jmem_cpointer_t bound_object_cp; /**< compressed pointer to lexical environments's the bound object */
    jmem_cpointer_t home_object_cp; /**< compressed pointer to lexical environments's the home object */
  } u1;
 
  /** object prototype or outer reference */
  union
  {
    jmem_cpointer_t prototype_cp; /**< compressed pointer to the object's prototype  */
    jmem_cpointer_t outer_reference_cp; /**< compressed pointer to the lexical environments's outer reference  */
  } u2;
} ecma_object_t;
typedef struct
{
  /** type : 4 bit : ecma_object_type_t or ecma_lexical_environment_type_t
                     depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV
      flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
                      ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_BLOCK
      refs : 10 / 26 bit (max 1022 / 67108862) */
  ecma_object_descriptor_t type_flags_refs;
 
  /** next in the object chain maintained by the garbage collector */
  jmem_cpointer_t gc_next_cp;
 
  /** compressed pointer to property list or bound object */
  union
  {
    jmem_cpointer_t property_list_cp; /**< compressed pointer to object's
                                       *   or declerative lexical environments's property list */
    jmem_cpointer_t bound_object_cp; /**< compressed pointer to lexical environments's the bound object */
    jmem_cpointer_t home_object_cp; /**< compressed pointer to lexical environments's the home object */
  } u1;
 
  /** object prototype or outer reference */
  union
  {
    jmem_cpointer_t prototype_cp; /**< compressed pointer to the object's prototype  */
    jmem_cpointer_t outer_reference_cp; /**< compressed pointer to the lexical environments's outer reference  */
  } u2;
} ecma_object_t;
| 31 ......................... 6 | 5 ...... 4 | 3 ........ 0 |
|          Reference Count       |    Flags   |     Type     |
|             (26 bits)          |   (2 bits) |    (4 bits)  |
| 31 ......................... 6 | 5 ...... 4 | 3 ........ 0 |
|          Reference Count       |    Flags   |     Type     |
|             (26 bits)          |   (2 bits) |    (4 bits)  |
typedef struct
{
  ecma_object_t object; /**< object header */
 
  /**
   * Description of extra fields. These extra fields depend on the object type.
   */
  union
  {
    ecma_built_in_props_t built_in; /**< built-in object part */
 
    /**
     * Description of objects with class.
     *
     * Note:
     *     class is a reserved word in c++, so cls is used instead
     */
    struct
    {
      uint8_t type; /**< class type of the object */
      /**
       * Description of 8 bit extra fields. These extra fields depend on the type.
       */
      union
      {
        uint8_t arguments_flags; /**< arguments object flags */
        uint8_t error_type; /**< jerry_error_t type of native error objects */
#if JERRY_BUILTIN_DATE
        uint8_t date_flags; /**< flags for date objects */
#endif /* JERRY_BUILTIN_DATE */
#if JERRY_MODULE_SYSTEM
        uint8_t module_state; /**< Module state */
#endif /* JERRY_MODULE_SYSTEM */
        uint8_t iterator_kind; /**< type of iterator */
        uint8_t regexp_string_iterator_flags; /**< flags for RegExp string iterator */
        uint8_t promise_flags; /**< Promise object flags */
#if JERRY_BUILTIN_CONTAINER
        uint8_t container_flags; /**< container object flags */
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_TYPEDARRAY
        uint8_t array_buffer_flags; /**< ArrayBuffer flags */
        uint8_t typedarray_type; /**< type of typed array */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
      } u1;
      /**
       * Description of 16 bit extra fields. These extra fields depend on the type.
       */
      union
      {
        uint16_t formal_params_number; /**< for arguments: formal parameters number */
#if JERRY_MODULE_SYSTEM
        uint16_t module_flags; /**< Module flags */
#endif /* JERRY_MODULE_SYSTEM */
        uint16_t iterator_index; /**< for %Iterator%: [[%Iterator%NextIndex]] property */
        uint16_t executable_obj_flags; /**< executable object flags */
#if JERRY_BUILTIN_CONTAINER
        uint16_t container_id; /**< magic string id of a container */
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_TYPEDARRAY
        uint16_t typedarray_flags; /**< typed array object flags */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
      } u2;
      /**
       * Description of 32 bit / value. These extra fields depend on the type.
       */
      union
      {
        ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */
        ecma_value_t target; /**< [[ProxyTarget]] or [[WeakRefTarget]] internal property */
#if JERRY_BUILTIN_TYPEDARRAY
        ecma_value_t arraybuffer; /**< for typedarray: ArrayBuffer reference */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
        ecma_value_t head; /**< points to the async generator task queue head item */
        ecma_value_t iterated_value; /**< for %Iterator%: [[IteratedObject]] property */
        ecma_value_t promise; /**< PromiseCapability[[Promise]] internal slot */
        ecma_value_t sync_iterator; /**< IteratorRecord [[Iterator]] internal slot for AsyncFromSyncIterator */
        ecma_value_t spread_value; /**< for spread object: spreaded element */
        int32_t tza; /**< TimeZone adjustment for date objects */
        uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
        uint32_t arguments_number; /**< for arguments: arguments number */
#if JERRY_MODULE_SYSTEM
        uint32_t dfs_ancestor_index; /**< module dfs ancestor index (ES2020 15.2.1.16) */
#endif /* JERRY_MODULE_SYSTEM */
      } u3;
    } cls;
 
    /**
     * Description of function objects.
     */
    struct
    {
      jmem_cpointer_tag_t scope_cp; /**< function scope */
      ecma_value_t bytecode_cp; /**< function byte code */
    } function;
 
    /**
     * Description of array objects.
     */
    struct
    {
      uint32_t length; /**< length property value */
      uint32_t length_prop_and_hole_count; /**< length property attributes and number of array holes in
                                            *   a fast access mode array multiplied ECMA_FAST_ACCESS_HOLE_ONE */
    } array;
 
    /**
     * Description of bound function object.
     */
    struct
    {
      jmem_cpointer_tag_t target_function; /**< target function */
      ecma_value_t args_len_or_this; /**< length of arguments or this value */
    } bound_function;
 
    /**
     * Description of implicit class constructor function.
     */
    struct
    {
      ecma_value_t script_value; /**< script value */
      uint8_t flags; /**< constructor flags */
    } constructor_function;
  } u;
} ecma_extended_object_t;
typedef struct
{
  ecma_object_t object; /**< object header */
 
  /**
   * Description of extra fields. These extra fields depend on the object type.
   */
  union
  {
    ecma_built_in_props_t built_in; /**< built-in object part */
 
    /**
     * Description of objects with class.
     *
     * Note:
     *     class is a reserved word in c++, so cls is used instead
     */
    struct
    {
      uint8_t type; /**< class type of the object */
      /**
       * Description of 8 bit extra fields. These extra fields depend on the type.
       */
      union
      {
        uint8_t arguments_flags; /**< arguments object flags */
        uint8_t error_type; /**< jerry_error_t type of native error objects */
#if JERRY_BUILTIN_DATE
        uint8_t date_flags; /**< flags for date objects */
#endif /* JERRY_BUILTIN_DATE */
#if JERRY_MODULE_SYSTEM
        uint8_t module_state; /**< Module state */
#endif /* JERRY_MODULE_SYSTEM */
        uint8_t iterator_kind; /**< type of iterator */
        uint8_t regexp_string_iterator_flags; /**< flags for RegExp string iterator */
        uint8_t promise_flags; /**< Promise object flags */
#if JERRY_BUILTIN_CONTAINER
        uint8_t container_flags; /**< container object flags */
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_TYPEDARRAY
        uint8_t array_buffer_flags; /**< ArrayBuffer flags */
        uint8_t typedarray_type; /**< type of typed array */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
      } u1;
      /**
       * Description of 16 bit extra fields. These extra fields depend on the type.
       */
      union
      {
        uint16_t formal_params_number; /**< for arguments: formal parameters number */
#if JERRY_MODULE_SYSTEM
        uint16_t module_flags; /**< Module flags */
#endif /* JERRY_MODULE_SYSTEM */
        uint16_t iterator_index; /**< for %Iterator%: [[%Iterator%NextIndex]] property */
        uint16_t executable_obj_flags; /**< executable object flags */
#if JERRY_BUILTIN_CONTAINER
        uint16_t container_id; /**< magic string id of a container */
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_TYPEDARRAY
        uint16_t typedarray_flags; /**< typed array object flags */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
      } u2;
      /**
       * Description of 32 bit / value. These extra fields depend on the type.
       */
      union
      {
        ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */
        ecma_value_t target; /**< [[ProxyTarget]] or [[WeakRefTarget]] internal property */
#if JERRY_BUILTIN_TYPEDARRAY
        ecma_value_t arraybuffer; /**< for typedarray: ArrayBuffer reference */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
        ecma_value_t head; /**< points to the async generator task queue head item */
        ecma_value_t iterated_value; /**< for %Iterator%: [[IteratedObject]] property */
        ecma_value_t promise; /**< PromiseCapability[[Promise]] internal slot */
        ecma_value_t sync_iterator; /**< IteratorRecord [[Iterator]] internal slot for AsyncFromSyncIterator */
        ecma_value_t spread_value; /**< for spread object: spreaded element */
        int32_t tza; /**< TimeZone adjustment for date objects */
        uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
        uint32_t arguments_number; /**< for arguments: arguments number */
#if JERRY_MODULE_SYSTEM
        uint32_t dfs_ancestor_index; /**< module dfs ancestor index (ES2020 15.2.1.16) */
#endif /* JERRY_MODULE_SYSTEM */
      } u3;
    } cls;
 
    /**
     * Description of function objects.
     */
    struct
    {
      jmem_cpointer_tag_t scope_cp; /**< function scope */
      ecma_value_t bytecode_cp; /**< function byte code */
    } function;
 
    /**
     * Description of array objects.
     */
    struct
    {
      uint32_t length; /**< length property value */
      uint32_t length_prop_and_hole_count; /**< length property attributes and number of array holes in
                                            *   a fast access mode array multiplied ECMA_FAST_ACCESS_HOLE_ONE */
    } array;
 
    /**
     * Description of bound function object.
     */
    struct
    {
      jmem_cpointer_tag_t target_function; /**< target function */
      ecma_value_t args_len_or_this; /**< length of arguments or this value */
    } bound_function;
 
    /**
     * Description of implicit class constructor function.
     */
    struct
    {
      ecma_value_t script_value; /**< script value */
      uint8_t flags; /**< constructor flags */
    } constructor_function;
  } u;
} ecma_extended_object_t;
typedef struct
{
  ecma_object_t object;
 
  union
  {
    struct
    {
      uint8_t type;  
       
      union {
        uint8_t array_buffer_flags;
        uint8_t typedarray_type;   
      } u1;
       
      union {
        uint16_t typedarray_flags;
      } u2;
       
      union {
        uint32_t length;       
        ecma_value_t arraybuffer;
        ecma_value_t value;    
      } u3;
    } cls;
 
    struct
    {
      uint32_t length;                    
      uint32_t length_prop_and_hole_count;
    } array;
 
    struct
    {
      jmem_cpointer_tag_t scope_cp;   
      ecma_value_t bytecode_cp;       
    } function;
     
    struct
    {
      jmem_cpointer_tag_t target_function;
      ecma_value_t args_len_or_this;      
    } bound_function;
 
  } u;
} ecma_extended_object_t;
typedef struct
{
  ecma_object_t object;
 
  union
  {
    struct
    {
      uint8_t type;  
       
      union {
        uint8_t array_buffer_flags;
        uint8_t typedarray_type;   
      } u1;
       
      union {
        uint16_t typedarray_flags;
      } u2;
       
      union {
        uint32_t length;       
        ecma_value_t arraybuffer;
        ecma_value_t value;    
      } u3;
    } cls;
 
    struct
    {
      uint32_t length;                    
      uint32_t length_prop_and_hole_count;
    } array;
 
    struct
    {
      jmem_cpointer_tag_t scope_cp;   
      ecma_value_t bytecode_cp;       
    } function;
     
    struct
    {
      jmem_cpointer_tag_t target_function;
      ecma_value_t args_len_or_this;      
    } bound_function;
 
  } u;
} ecma_extended_object_t;
let ab = new ArrayBuffer(0x100);
let dv = new DataView(ab,0x10,0x20);
dv.setUint32(0x00,0x41414141,true);
let ab = new ArrayBuffer(0x100);
let dv = new DataView(ab,0x10,0x20);
dv.setUint32(0x00,0x41414141,true);
typedef struct
{
  ecma_extended_object_t header; /**< header part */
  ecma_object_t *buffer_p; /**< [[ViewedArrayBuffer]] internal slot */
  uint32_t byte_offset; /**< [[ByteOffset]] internal slot */
} ecma_dataview_object_t;
typedef struct
{
  ecma_extended_object_t header; /**< header part */
  ecma_object_t *buffer_p; /**< [[ViewedArrayBuffer]] internal slot */
  uint32_t byte_offset; /**< [[ByteOffset]] internal slot */
} ecma_dataview_object_t;
typedef struct
{
  ecma_extended_object_t extended_object; /**< extended object part */
  void *buffer_p; /**< pointer to the backing store of the array buffer object */
  void *arraybuffer_user_p; /**< user pointer passed to the free callback */
} ecma_arraybuffer_pointer_t;
typedef struct
{
  ecma_extended_object_t extended_object; /**< extended object part */
  void *buffer_p; /**< pointer to the backing store of the array buffer object */
  void *arraybuffer_user_p; /**< user pointer passed to the free callback */
} ecma_arraybuffer_pointer_t;
diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c
index cf0c9fde..5c1b7aa2 100644
--- a/jerry-core/ecma/operations/ecma-conversion.c
+++ b/jerry-core/ecma/operations/ecma-conversion.c
@@ -905,7 +905,6 @@ ecma_op_to_integer (ecma_value_t value, /**< ecma value */
   /* 3 */
   if (ecma_number_is_nan (number))
   {
-    *number_p = ECMA_NUMBER_ZERO;
     return ECMA_VALUE_EMPTY;
   }
diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c
index cf0c9fde..5c1b7aa2 100644
--- a/jerry-core/ecma/operations/ecma-conversion.c
+++ b/jerry-core/ecma/operations/ecma-conversion.c
@@ -905,7 +905,6 @@ ecma_op_to_integer (ecma_value_t value, /**< ecma value */
   /* 3 */
   if (ecma_number_is_nan (number))
   {
-    *number_p = ECMA_NUMBER_ZERO;
     return ECMA_VALUE_EMPTY;
   }
ecma_value_t
ecma_op_to_integer (ecma_value_t value, /**< ecma value */
                    ecma_number_t *number_p) /**< [out] ecma number */
{// [A]
......
 
  ecma_number_t number = *number_p;
 
  /* 3 */
  if (ecma_number_is_nan (number))
  {
    return ECMA_VALUE_EMPTY;
  }
 
 ......
 
ecma_value_t
ecma_op_to_length (ecma_value_t value, /**< ecma value */
                   ecma_length_t *length) /**< [out] ecma number */
{//[B]
  /* 1 */
  if (ECMA_IS_VALUE_ERROR (value))
  {
    return value;
  }
 
  /* 2 */
  ecma_number_t num;
  ecma_value_t length_num = ecma_op_to_integer (value, &num);
  
 ......
ecma_value_t
ecma_op_to_index (ecma_value_t value, /**< ecma value */
                  ecma_number_t *index) /**< [out] ecma number */
{//[C]
  /* 1. */
  if (ecma_is_value_undefined (value))
  {
    *index = 0;
    return ECMA_VALUE_EMPTY;
  }
 
  /* 2.a */
  ecma_number_t integer_index;
  ecma_value_t index_value = ecma_op_to_integer (value, &integer_index);
ecma_value_t
ecma_op_to_integer (ecma_value_t value, /**< ecma value */
                    ecma_number_t *number_p) /**< [out] ecma number */
{// [A]
......
 
  ecma_number_t number = *number_p;
 
  /* 3 */
  if (ecma_number_is_nan (number))
  {
    return ECMA_VALUE_EMPTY;
  }
 
 ......
 
ecma_value_t
ecma_op_to_length (ecma_value_t value, /**< ecma value */
                   ecma_length_t *length) /**< [out] ecma number */
{//[B]
  /* 1 */
  if (ECMA_IS_VALUE_ERROR (value))
  {
    return value;
  }
 
  /* 2 */
  ecma_number_t num;
  ecma_value_t length_num = ecma_op_to_integer (value, &num);
  
 ......
ecma_value_t
ecma_op_to_index (ecma_value_t value, /**< ecma value */
                  ecma_number_t *index) /**< [out] ecma number */
{//[C]
  /* 1. */
  if (ecma_is_value_undefined (value))
  {
    *index = 0;
    return ECMA_VALUE_EMPTY;
  }
 
  /* 2.a */
  ecma_number_t integer_index;
  ecma_value_t index_value = ecma_op_to_integer (value, &integer_index);
#if JERRY_BUILTIN_DATAVIEW
/**
 * Description of DataView objects.
 */
typedef struct
{
  ecma_extended_object_t header; /**< header part */
  ecma_object_t *buffer_p; /**< [[ViewedArrayBuffer]] internal slot */
  uint32_t byte_offset; /**< [[ByteOffset]] internal slot */
} ecma_dataview_object_t;
#endif /* JERRY_BUILTIN_DATAVIEW */
#if JERRY_BUILTIN_DATAVIEW
/**
 * Description of DataView objects.
 */
typedef struct
{
  ecma_extended_object_t header; /**< header part */
  ecma_object_t *buffer_p; /**< [[ViewedArrayBuffer]] internal slot */
  uint32_t byte_offset; /**< [[ByteOffset]] internal slot */
} ecma_dataview_object_t;
#endif /* JERRY_BUILTIN_DATAVIEW */
typedef struct
{
  ecma_extended_object_t extended_object; /**< extended object part */
  void *buffer_p; /**< pointer to the backing store of the array buffer object */
  void *arraybuffer_user_p; /**< user pointer passed to the free callback */
} ecma_arraybuffer_pointer_t;
typedef struct
{
  ecma_extended_object_t extended_object; /**< extended object part */
  void *buffer_p; /**< pointer to the backing store of the array buffer object */
  void *arraybuffer_user_p; /**< user pointer passed to the free callback */
} ecma_arraybuffer_pointer_t;
let ab = new ArrayBuffer(0x100);
let dv = new DataView(ab,0x10);
dv.setUint32(0,0x11111111,true);
let ab = new ArrayBuffer(0x100);
let dv = new DataView(ab,0x10);
dv.setUint32(0,0x11111111,true);
let ab = new ArrayBuffer(0x100);
let dv = new DataView(ab,0x10,0x10);
dv.setUint32(0x20,0x11111111,true);// error
let ab = new ArrayBuffer(0x100);
let dv = new DataView(ab,0x10,0x10);
dv.setUint32(0x20,0x11111111,true);// error
ecma_value_t
ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments list */
                         uint32_t arguments_list_len) /**< number of arguments */
{
  JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
  JERRY_ASSERT (JERRY_CONTEXT (current_new_target_p));
 
  ecma_value_t buffer = arguments_list_len > 0 ? arguments_list_p[0] : ECMA_VALUE_UNDEFINED;
 
  /* 2. */
  if (!ecma_is_value_object (buffer))
  {
    return ecma_raise_type_error (ECMA_ERR_ARGUMENT_BUFFER_NOT_OBJECT);
  }
 
  ecma_object_t *buffer_p = ecma_get_object_from_value (buffer);
 
  if (!(ecma_object_class_is (buffer_p, ECMA_OBJECT_CLASS_ARRAY_BUFFER)
        || ecma_object_is_shared_arraybuffer (buffer_p)))
  {
    return ecma_raise_type_error (ECMA_ERR_ARGUMENT_BUFFER_NOT_ARRAY_OR_SHARED_BUFFER);
  }
 
  /* 3. */
  ecma_number_t offset = 0;
 
  if (arguments_list_len > 1)
  {
    ecma_value_t offset_value = ecma_op_to_index (arguments_list_p[1], &offset);//[a]
    if (ECMA_IS_VALUE_ERROR (offset_value))
    {
      return offset_value;
    }
  }
 
  /* 4. */
  if (ecma_arraybuffer_is_detached (buffer_p))
  {
    return ecma_raise_type_error (ECMA_ERR_ARRAYBUFFER_IS_DETACHED);
  }
 
  /* 5. */
  ecma_number_t buffer_byte_length = ecma_arraybuffer_get_length (buffer_p);
 
  /* 6. */
  if (offset > buffer_byte_length)
  {
    return ecma_raise_range_error (ECMA_ERR_START_OFFSET_IS_OUTSIDE_THE_BOUNDS_OF_THE_BUFFER);
  }
 
  /* 7. */
  uint32_t view_byte_length;
  if (arguments_list_len > 2 && !ecma_is_value_undefined (arguments_list_p[2]))
  {
    /* 8.a */
    ecma_number_t byte_length_to_index;
    ecma_value_t byte_length_value = ecma_op_to_index (arguments_list_p[2], &byte_length_to_index);
 
    if (ECMA_IS_VALUE_ERROR (byte_length_value))
    {
      return byte_length_value;
    }
 
    /* 8.b */
    if (offset + byte_length_to_index > buffer_byte_length)//[b]
    {
      return ecma_raise_range_error (ECMA_ERR_START_OFFSET_IS_OUTSIDE_THE_BOUNDS_OF_THE_BUFFER);
    }
 
    JERRY_ASSERT (byte_length_to_index <= UINT32_MAX);
    view_byte_length = (uint32_t) byte_length_to_index;
  }
  else
  {
    /* 7.a */
    view_byte_length = (uint32_t) (buffer_byte_length - offset);
  }
 
  /* 9. */
  ecma_object_t *prototype_obj_p =
    ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target_p), ECMA_BUILTIN_ID_DATAVIEW_PROTOTYPE);
  if (JERRY_UNLIKELY (prototype_obj_p == NULL))
  {
    return ECMA_VALUE_ERROR;
  }
 
  /* 10. */
  if (ecma_arraybuffer_is_detached (buffer_p))
  {
    ecma_deref_object (prototype_obj_p);
    return ecma_raise_type_error (ECMA_ERR_ARRAYBUFFER_IS_DETACHED);
  }
 
  /* 9. */
  /* It must happen after 10., because uninitialized object can't be destroyed properly. */
  ecma_object_t *object_p =
    ecma_create_object (prototype_obj_p, sizeof (ecma_dataview_object_t), ECMA_OBJECT_TYPE_CLASS);
 
  ecma_deref_object (prototype_obj_p);
 
  /* 11 - 14. */
  ecma_dataview_object_t *dataview_obj_p = (ecma_dataview_object_t *) object_p;
  dataview_obj_p->header.u.cls.type = ECMA_OBJECT_CLASS_DATAVIEW;
  dataview_obj_p->header.u.cls.u3.length = view_byte_length;
  dataview_obj_p->buffer_p = buffer_p;
  dataview_obj_p->byte_offset = (uint32_t) offset;
 
  return ecma_make_object_value (object_p);
} /* ecma_op_dataview_create */
ecma_value_t
ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments list */
                         uint32_t arguments_list_len) /**< number of arguments */
{
  JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
  JERRY_ASSERT (JERRY_CONTEXT (current_new_target_p));
 
  ecma_value_t buffer = arguments_list_len > 0 ? arguments_list_p[0] : ECMA_VALUE_UNDEFINED;
 
  /* 2. */
  if (!ecma_is_value_object (buffer))
  {
    return ecma_raise_type_error (ECMA_ERR_ARGUMENT_BUFFER_NOT_OBJECT);
  }
 
  ecma_object_t *buffer_p = ecma_get_object_from_value (buffer);
 
  if (!(ecma_object_class_is (buffer_p, ECMA_OBJECT_CLASS_ARRAY_BUFFER)
        || ecma_object_is_shared_arraybuffer (buffer_p)))
  {
    return ecma_raise_type_error (ECMA_ERR_ARGUMENT_BUFFER_NOT_ARRAY_OR_SHARED_BUFFER);
  }
 
  /* 3. */
  ecma_number_t offset = 0;
 
  if (arguments_list_len > 1)
  {
    ecma_value_t offset_value = ecma_op_to_index (arguments_list_p[1], &offset);//[a]
    if (ECMA_IS_VALUE_ERROR (offset_value))
    {
      return offset_value;
    }
  }
 
  /* 4. */
  if (ecma_arraybuffer_is_detached (buffer_p))
  {
    return ecma_raise_type_error (ECMA_ERR_ARRAYBUFFER_IS_DETACHED);
  }
 
  /* 5. */
  ecma_number_t buffer_byte_length = ecma_arraybuffer_get_length (buffer_p);
 
  /* 6. */
  if (offset > buffer_byte_length)
  {
    return ecma_raise_range_error (ECMA_ERR_START_OFFSET_IS_OUTSIDE_THE_BOUNDS_OF_THE_BUFFER);
  }
 
  /* 7. */
  uint32_t view_byte_length;
  if (arguments_list_len > 2 && !ecma_is_value_undefined (arguments_list_p[2]))
  {
    /* 8.a */
    ecma_number_t byte_length_to_index;
    ecma_value_t byte_length_value = ecma_op_to_index (arguments_list_p[2], &byte_length_to_index);
 
    if (ECMA_IS_VALUE_ERROR (byte_length_value))
    {
      return byte_length_value;
    }
 
    /* 8.b */
    if (offset + byte_length_to_index > buffer_byte_length)//[b]
    {
      return ecma_raise_range_error (ECMA_ERR_START_OFFSET_IS_OUTSIDE_THE_BOUNDS_OF_THE_BUFFER);
    }
 
    JERRY_ASSERT (byte_length_to_index <= UINT32_MAX);
    view_byte_length = (uint32_t) byte_length_to_index;
  }
  else
  {
    /* 7.a */
    view_byte_length = (uint32_t) (buffer_byte_length - offset);
  }
 
  /* 9. */
  ecma_object_t *prototype_obj_p =
    ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target_p), ECMA_BUILTIN_ID_DATAVIEW_PROTOTYPE);
  if (JERRY_UNLIKELY (prototype_obj_p == NULL))
  {
    return ECMA_VALUE_ERROR;
  }
 
  /* 10. */
  if (ecma_arraybuffer_is_detached (buffer_p))
  {

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

最后于 2025-12-3 21:55 被flyyyy编辑 ,原因:
上传的附件:
收藏
免费 4
支持
分享
最新回复 (2)
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
这篇教程详细讲解了使用Frida对iOS应用进行逆向分析的过程,涵盖了从侦查到漏洞利用的完整流程,适合学习iOS安全和逆向分析技术。????
2025-12-13 11:07
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
这篇教程详细讲解了使用Frida对iOS应用进行逆向分析的过程,涵盖了从侦查到漏洞利用的完整流程,适合学习iOS安全和逆向分析技术。????
2025-12-13 11:15
0
游客
登录 | 注册 方可回帖
返回