wasm的逆向之旅一

news2024/10/7 8:30:52

目录

概要

技术名词解释

1、WebAssembly 指令集概览

1)基本结构

2)数据类型

3)模块和函数

4)指令概览

        1.i32 整数运算

        2.i32 浮点数运算(用法同整数运算)

         3.逻辑运算和位移(用法同整数运算)

        4.内存访问指令

        6.控制流指令

        7.模块和导出指令

        8.其他常见指令

实战wasm补环境

实战wasm反编译还原算法

小结


概要

1.wasm 补环境

2.反编译分析伪代码

3.wasm 的指令学习

wasm-reference-manual/WebAssembly.md at master · sunfishcode/wasm-reference-manual · GitHubWebAssembly Reference Manual. Contribute to sunfishcode/wasm-reference-manual development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#instructions

4.wabt反编译 

Releases · WebAssembly/wabt · GitHubThe WebAssembly Binary Toolkit. Contribute to WebAssembly/wabt development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/WebAssembly/wabt/releases5.gcc反编译

MSYS2Software Distribution and Building Platform for Windowsicon-default.png?t=N7T8https://www.msys2.org/

技术名词解释

1、WebAssembly 指令集概览

        WebAssembly的指令集可以分为以下几类:数值操作、内存访问、控制流、模块定义和导入导出等。以下是每个类别中一些常见的指令及其功能

1)基本结构

        WebAssembly的指令集由一系列字节码组成,每个字节码对应一个特定的操作码(opcode)。

2)数据类型

        WebAssembly支持的数据类型包括整数类型和浮点数类型。整数类型可以是8位(i8)、16位(i16)、32位(i32)或64位(i64);浮点数类型可以是32位(f32)或64位(f64)。

3)模块和函数

        WebAssembly代码以模块(module)的形式组织,每个模块包含函数(function)和相关的全局变量、内存(memory)和表格(table)等。函数由一组指令序列构成。

4)指令概览

        1.i32 整数运算
i32 指令描述
i32.add32位有符号整数的加法运算
i32.sub32位有符号整数的减法运算
i32.mul32位有符号整数的乘法运算
i32.div_s有符号32位整数的除法
i32.div_u无符号32位整数的除法
i32.rem_s有符号32位整数的求余运算
i32.rem_u无符号32位整数的求余运算

示例代码👇

(func (param i32 i32) (result i32)
  local.get 0    ;; 获取函数的第一个参数(整数1)
  local.get 1    ;; 获取函数的第二个参数(整数2)
  i32.add)       ;; 将栈顶的两个整数相加,并将结果作为函数的返回值

代码注解

  • (func (param i32 i32) (result i32)):定义了一个函数,它接受两个参数(两个32位有符号整数),并返回一个32位有符号整数作为结果。

  • local.get 0local.get 1:这两个指令分别将函数的第一个和第二个参数加载到本地变量栈上。在WebAssembly中,参数从索引0开始。

  • i32.add:这是一个整数加法指令,它从栈顶弹出两个整数值,将它们相加,然后将结果推送回栈顶。在这个例子中,它将栈顶的两个整数(即函数的两个参数)相加。

执行过程

  • 当函数被调用时,传递给函数的两个参数被存储在本地变量中(索引0和索引1)。

  • local.get 0 将第一个参数加载到栈顶。

  • local.get 1 将第二个参数加载到栈顶。

  • i32.add 从栈顶弹出这两个参数,执行加法操作,并将结果再次推送到栈顶,作为函数的返回值。

        2.i32 浮点数运算(用法同整数运算)
f32 指令描述
f32.add32位浮点数的加法运算
f32.sub32位浮点数的减法运算
f32.mul32位浮点数的乘法运算
f32.div32位浮点数的除法
f64 指令描述
f32.add64位浮点数的加法运算
f32.sub64位浮点数的减法运算
f32.mul64位浮点数的乘法运算
f32.div64位浮点数的除法
         3.逻辑运算和位移(用法同整数运算)
运算和位移指令描述
i32.and32位整数的按位与、按位或和按位异或操作
i32.or32位整数的按位与、按位或和按位异或操作
i32.xor32位整数的按位与、按位或和按位异或操作
i32.shl32位整数的左移、有符号右移和无符号右移操作
i32.shr_s32位整数的左移、有符号右移和无符号右移操作
i32.shr_u32位整数的左移、有符号右移和无符号右移操作
        4.内存访问指令

WebAssembly允许程序直接访问内存,执行加载和存储操作。这对于处理大量数据或者与Web页面交互非常有用。

1.内存加载和存储

i32.loadi64.loadf32.loadf64.load:从内存中加载指定类型的数据。
i32.storei64.storef32.storef64.store:将指定类型的数据存储到内存中。

load示例代码👇

(func (param i32) (result i32)
  local.get 0    ;; 获取函数的第一个参数(内存地址)
  i32.load)       ;; 加载指定内存地址处的整数并将其作为结果返回

代码注解:

  • (func (param i32) (result i32)):定义了一个函数,它接受一个32位整数作为参数,并返回一个32位整数作为结果。

  • local.get 0:这个指令将函数的第一个参数(索引为0的本地变量)加载到栈顶。在WebAssembly中,参数从索引0开始。

  • i32.load:这是一个内存加载指令,它从内存中加载一个32位整数值到栈顶。在这个例子中,它加载的地址是栈顶的值(即函数的参数)所指向的内存地址处的32位整数值。

执行过程

  • 当函数被调用时,传递给函数的32位整数参数被存储在本地变量中(索引0)。

  • local.get 0 将参数加载到栈顶,即将要加载的内存地址。

  • i32.load 从内存中加载存储在指定地址处的32位整数值,并将加载的值推送回栈顶,作为函数的返回值。

store示例代码👇

(func (param i32 f32)
  local.get 0    ;; 获取第一个参数(内存地址)
  local.get 1    ;; 获取第二个参数(要存储的浮点数)
  f32.store)     ;; 将栈顶的浮点数存储到指定内存地址

代码注解:

  • (func (param i32 f32)):定义了一个函数,它接受一个32位整数(作为内存地址)和一个32位浮点数作为参数。

  • local.get 0local.get 1:这两个指令分别将函数的第一个和第二个参数加载到本地变量栈上。在WebAssembly中,参数从索引0开始。

  • f32.store:这是一个内存存储指令,它将栈顶的32位浮点数值存储到指定内存地址处。在这个例子中,它将第一个参数(内存地址)指向的位置存储为第二个参数(32位浮点数)的值。

执行过程

  • 当函数被调用时,传递给函数的第一个参数是一个32位整数,表示要存储数据的内存地址。

  • 第二个参数是一个32位浮点数,即要存储到内存中的数据。

  • local.get 0 将第一个参数加载到栈顶,即内存地址。

  • local.get 1 将第二个参数加载到栈顶,即要存储的浮点数值。

  • f32.store 将栈顶的浮点数值存储到栈顶的地址处。

2.内存增长

memory.size:获取当前内存的大小。

示例代码👇

(memory 1)

(func $getMemorySize (result i32)
  memory.size)

代码注解:

  • memory 1:这个指令定义了一个大小为1页(64KB)的静态内存。在实际应用中,内存可以根据需求定义为更大的页面数。

  • $getMemorySize 函数定义了一个没有参数的函数,返回当前内存的页数作为32位整数。

执行过程:

  • memory 1 指令定义了一个1页(64KB)大小的静态内存。这个内存是WebAssembly模块的一部分,可以在模块内部进行操作和访问。

  • $getMemorySize 函数通过 memory.size 指令获取当前内存的页数。

  • memory.size 指令将当前内存的页数推送到栈顶,作为函数的返回值。


 

memory.grow:增加内存的大小。
示例代码👇

(memory 1)  ;; 定义一个1页(64KB)大小的内存

(func $growMemory (param i32) (result i32)
  local.get 0        ;; 获取函数参数,表示要增加的页数
  memory.grow        ;; 增加内存的页数
  memory.size)       ;; 获取新的内存页数

代码注解:

  • $growMemory 函数定义了一个接受一个 i32 类型参数(表示要增加的页数)和返回一个 i32 类型结果(表示新的内存页数)的函数。

  • memory 1 指令定义了一个大小为1页(64KB)的静态内存,作为示例中的初始内存。

  • memory.grow 指令用于增加内存的页数。它会尝试增加内存的页数,成功时返回新的内存页数,失败时返回-1。

执行过程

  • memory 1 指令定义了一个1页(64KB)大小的静态内存。
  • $growMemory 函数通过 local.get 0 获取函数的第一个参数,即要增加的页数。
  • memory.grow 指令尝试增加内存的页数。如果成功,它将新的内存页数推送到栈顶;如果失败(例如超过了内存限制),则推送-1。
  • memory.size 指令获取当前内存的页数,作为函数的返回值。

        6.控制流指令

WebAssembly支持灵活的控制流结构,包括条件执行、循环和函数调用

1.基本控制流

blockloopifelseend:定义基本块、循环和条件执行及其结束

示例代码👇

(func (param i32) (result i32)
  block            ;; 定义一个块
    local.get 0    ;; 将函数的第一个参数加载到栈顶
    i32.const 0    ;; 将常数0推送到栈顶
    i32.eq         ;; 比较栈顶的两个值是否相等,结果入栈(0或1)
    if             ;; 如果条件为真,则执行下面的指令
      i32.const 1  ;; 将常数1推送到栈顶(即条件为真时的返回值)
    else           ;; 如果条件为假,则执行下面的指令
      local.get 0  ;; 再次将函数的第一个参数加载到栈顶
      i32.const 1  ;; 将常数1推送到栈顶
      i32.sub      ;; 将栈顶的两个值相减,计算递减后的值
    end            ;; 结束条件分支
  end              ;; 结束块
)

代码注解:

  • 这段代码实现了一个简单的逻辑:如果参数为0,则返回1;否则返回参数减去1。

  • 使用 blockend 封装了整个逻辑块,使得条件分支(ifelse)可以安全地组织和执行。

  • 这种结构允许在WebAssembly中实现基本的条件逻辑和数学运算,用于构建更复杂的算法和函数。

执行过程:

  1. 函数参数和块定义

    • 函数接受一个 i32 类型的参数,并返回一个 i32 类型的结果。

    • block 指令定义了一个块,用于封装条件分支和相关操作。

  2. 条件分支

    • local.get 0 将函数的第一个参数(索引为0的本地变量)加载到栈顶。

    • i32.const 0 将常数0推送到栈顶。

    • i32.eq 指令比较栈顶的两个值是否相等,如果相等则将1推送到栈顶;否则将0推送到栈顶。

  3. 条件分支执行

    • if 指令根据前面比较的结果(0或1),决定执行哪个分支:

      • 如果条件为真(栈顶值为1),则执行 i32.const 1,将常数1推送到栈顶作为函数的返回值。

      • 如果条件为假(栈顶值为0),则执行 local.get 0i32.const 1i32.sub,依次将函数参数加载到栈顶,推送常数1,并计算栈顶两个值的差,作为函数的返回值。

  4. 块结束

    • end 指令结束条件分支和块定义。

示例代码👇

(func (param i32) (result i32)
  local.get 0    ;; 获取函数的第一个参数(整数)
  i32.const 10    ;; 将常数10推送到栈顶
  i32.lt_s        ;; 比较栈顶的两个整数,如果第一个小于第二个则推送1,否则推送0
  if              ;; 如果比较结果为真(栈顶值为1),则执行以下指令
    i32.const 1   ;; 将常数1推送到栈顶
    return        ;; 返回栈顶的值并结束函数
  end             ;; 结束条件分支
  i32.const 2     ;; 如果比较结果为假(栈顶值为0),将常数2推送到栈顶
  return)         ;; 返回栈顶的值并结束函数

代码注解:

  • 这段代码定义了一个函数,接受一个 i32 类型的参数作为整数,并返回一个 i32 类型的整数结果。

  • local.get 0 将函数的第一个参数(整数)加载到栈顶。

  • i32.const 10 将常数10推送到栈顶。

  • i32.lt_s 指令比较栈顶的两个整数,如果第一个整数小于第二个整数,则推送1到栈顶;否则推送0到栈顶。

  • if 指令根据比较的结果(栈顶值为1或0)决定执行不同的分支:

    • 如果比较结果为真(即第一个参数小于10),则执行 i32.const 1 将常数1推送到栈顶,并使用 return 返回栈顶的值并结束函数。

    • 如果比较结果为假(即第一个参数不小于10),则执行 i32.const 2 将常数2推送到栈顶,并使用 return 返回栈顶的值并结束函数。

执行过程:

  • 当这个函数被调用时,它假定参数是一个有效的 i32 类型整数。

  • i32.lt_s 比较栈顶的整数和常数10,如果小于10则执行条件分支中的第一个分支(推送常数1并返回),否则执行第二个分支(推送常数2并返回)。

2.函数调用和返回

call:调用函数。

return:从函数返回。

示例代码👇

(func $add (param i32 i32) (result i32)
  local.get 0    ;; 获取第一个参数
  local.get 1    ;; 获取第二个参数
  i32.add)       ;; 将两个参数相加并返回结果

(func $run (result i32)
  i32.const 5     ;; 常数5压入栈顶作为第一个参数
  i32.const 7     ;; 常数7压入栈顶作为第二个参数
  call $add       ;; 调用函数add,将返回值推送到栈顶
  return)         ;; 返回栈顶的值并结束函数

$add代码注解:

  • $add 是函数的名称,接受两个 i32 类型的整数参数,并返回一个 i32 类型的整数结果。

  • local.get 0 将第一个参数(栈中的第一个值)复制到栈顶。

  • local.get 1 将第二个参数(栈中的第二个值)复制到栈顶。

  • i32.add 将栈顶的两个整数相加,并将结果推送回栈顶作为函数的返回值。

$run代码注解:

  • 这个函数没有名称,只返回一个 i32 类型的整数。

  • i32.const 5 将常数5推送到栈顶,作为第一个参数。

  • i32.const 7 将常数7推送到栈顶,作为第二个参数。

  • call $add 调用之前定义的 $add 函数,执行加法操作,并将结果推送到栈顶。

  • return 返回栈顶的值作为函数的结果,并结束函数的执行。

执行过程:

  • 先将常数5和7分别压入栈顶作为参数。

  • 然后,调用 $add 函数进行加法运算。

  • $add 函数执行完毕后,将结果推送到栈顶。

  • 最后,使用 return 返回栈顶的值(加法结果)并结束函数的执行。

        7.模块和导出指令

WebAssembly代码以模块的形式组织,可以定义函数、全局变量、表格和内存等,还可以将这些元素导出给外部JavaScript环境。

WebAssembly代码以模块的形式组织,可以定义函数、全局变量、表格和内存等,还可以将这些元素导出给外部JavaScript环境。

1.模块定义

modulefuncglobaltablememory:定义模块、函数、全局变量、表格和内存等。

示例代码👇

(module
  (func $add (param i32 i32) (result i32)   ;; 定义一个名为 $add 的函数,接受两个 i32 类型的参数,并返回一个 i32 类型的结果
    local.get 0    ;; 获取第一个参数
    local.get 1    ;; 获取第二个参数
    i32.add)       ;; 将两个参数相加并返回结果

  (export "add" (func $add))   ;; 导出函数 $add,使其可在模块外部调用,并命名为 "add"
)

代码注解:

  • 模块定义

    • module 是 Wasm 模块的起始关键字,用于定义一个模块。

  • 函数定义

    • (func $add (param i32 i32) (result i32) ...):定义了一个名为 $add 的函数,它有两个 i32 类型的参数 (param i32 i32),并且返回一个 i32 类型的结果 (result i32)

    • local.get 0local.get 1 分别用于获取函数的第一个和第二个参数,将它们压入栈顶。

    • i32.add 指令将栈顶的两个整数相加,并将结果推送回栈顶作为函数的返回值。

  • 导出函数

    • (export "add" (func $add)):通过 export 指令将函数 $add 导出为模块的公共接口。导出时使用字符串 "add" 作为函数的外部名称,以便外部 JavaScript 或其他环境可以调用它。

JavaScript中的导出示例代码👇

// 假设模块实例已经加载和实例化
const wasmInstance = ...;  // 加载和实例化的 WebAssembly 模块实例

// 调用 WebAssembly 导出的函数
const result = wasmInstance.exports.add(3, 4);
console.log(result);  // 输出结果为 7

2.导出和导入

export:导出函数、全局变量等至外部JavaScript环境。

import:导入外部函数、全局变量等至模块内部。
示例代码👇

(module
  (func $externalFunction (import "env" "externalFunction") (param i32) (result i32))   ;; 导入一个名为 externalFunction 的函数
  (export "internalFunction" (func $internalFunction))   ;; 导出一个名为 internalFunction 的函数
)

代码注解:

  • 导入函数定义

    • (func $externalFunction (import "env" "externalFunction") (param i32) (result i32)):定义了一个名为 $externalFunction 的函数,它是从外部导入的函数。在模块中,使用 import 关键字指定导入函数的名称和命名空间。

    • import "env" "externalFunction" 表示将名为 "externalFunction" 的函数从命名空间为 "env" 的环境中导入。这种导入通常用于从宿主环境(如 JavaScript)中导入函数。

  • 导出函数定义

    • (export "internalFunction" (func $internalFunction)):使用 export 关键字将模块中的函数 $internalFunction 导出,以便模块外部的其他代码可以调用它。

    • "internalFunction" 是导出函数的外部名称,可以通过这个名称在外部环境中引用该函数。

注意事项

  • 导入函数:通过 import 关键字可以在 WebAssembly 模块中导入来自宿主环境的函数或其他模块的函数。这种机制使得 WebAssembly 可以与宿主环境进行交互,执行特定的功能或操作。

  • 导出函数:通过 export 关键字可以将模块中定义的函数、变量或表导出,使它们对外部可见和可调用。

JavaScript中的示例用法

// 加载和实例化 WebAssembly 模块
const module = new WebAssembly.Module(/* 模块的二进制数据 */);
const instance = new WebAssembly.Instance(module, {
  env: {
    externalFunction: function(param) {
      // 实现 externalFunction 的具体逻辑
      return param * 2;  // 例如,简单地将参数乘以 2 并返回
    }
  }
});

// 调用导出的 internalFunction
const result = instance.exports.internalFunction();
console.log(result);  // 输出 internalFunction 的返回值

        8.其他常见指令

除了上述基本的指令外,还有一些用于栈操作、类型转换和异常处理等的指令。更多指令请阅读官方文档

1.栈操作

drop:丢弃栈顶元素。

示例代码👇

(func (param i32 i32) (result i32)   ;; 定义一个函数,接受两个 i32 类型的参数,返回一个 i32 类型的结果
  local.get 0    ;; 获取第一个参数,将其压入栈顶
  local.get 1    ;; 获取第二个参数,将其压入栈顶
  i32.add        ;; 将栈顶的两个整数相加,并将结果压入栈顶
  drop           ;; 丢弃栈顶的值(即相加后的结果)
  local.get 0    ;; 获取第一个参数的值,将其压入栈顶作为函数的返回值
)

代码注解:

  • 数签名

    • (func (param i32 i32) (result i32)):定义了一个函数,该函数接受两个 i32 类型的参数,并且返回一个 i32 类型的结果。

  • 指令解释

    • local.get 0local.get 1:这两条指令用于分别获取函数的第一个和第二个参数,并将它们的值推送到栈顶。

    • i32.add:将栈顶的两个整数相加,并将相加后的结果推送到栈顶。

    • drop:丢弃栈顶的值。在这里,它被用来丢弃相加后的结果,表示我们不需要该值,只是将第一个参数的值作为结果返回。

    • local.get 0:获取函数的第一个参数的值,并将其作为函数的返回值推送到栈顶。

执行过程:

  • 参数传递

    • 将两个参数依次压入栈顶,栈顶为第二个参数,次栈顶为第一个参数。

  • 加法操作

    • 使用 i32.add 将栈顶的两个整数相加,将相加后的结果推送到栈顶。

  • 结果处理

    • 使用 drop 指令丢弃栈顶的结果值,保留第一个参数的值在栈顶。

  • 返回值

    • 最后使用 local.get 0 获取并返回第一个参数的值作为函数的结果。

select:条件选择指令。

(func (param i32 i32 i32) (result i32)   ;; 定义一个函数,接受三个 i32 类型的参数,并返回一个 i32 类型的结果
  local.get 0    ;; 获取第一个参数,将其压入栈顶
  if             ;; 进入条件分支判断
    local.get 1  ;; 如果第一个参数为真(非零),则获取第二个参数的值并将其推送到栈顶
  else           ;; 否则(第一个参数为假,即为零),执行以下分支
    local.get 2  ;; 获取第三个参数的值并将其推送到栈顶
  end            ;; 条件分支结束
)

代码注解:

  • 函数签名

    • (func (param i32 i32 i32) (result i32)):定义了一个函数,接受三个 i32 类型的参数,并返回一个 i32 类型的结果。

  • 指令解释

    • local.get 0:获取函数的第一个参数,并将其值推送到栈顶。

    • if:条件分支的开始标志,表示后续指令是一个条件判断。

    • local.get 1:在条件为真(非零)时执行的指令块,获取第二个参数的值并将其推送到栈顶。

    • else:条件为假(第一个参数为零)时执行的指令块的开始标志。

    • local.get 2:在条件为假时执行的指令,获取第三个参数的值并将其推送到栈顶。

    • end:条件分支的结束标志,表示条件判断结束。

执行过程

  • 参数传递

    • 将三个参数依次压入栈顶,栈顶为第三个参数,次栈顶为第二个参数,最底部为第一个参数。

  • 条件判断

    • 使用 local.get 0 获取第一个参数的值。

    • 使用 if 指令根据第一个参数的值(真或假)选择执行相应的分支。

  • 返回值

    • 根据条件判断的结果,将第二个或第三个参数的值作为函数的返回值推送到栈顶。

2.类型转换

i32.wrap_i64i64.extend_i32_s:类型转换指令,例如从64位整数到32位整数的转换

示例代码👇

i64.const 4294967312   ;; 64 位整数常量
i32.wrap_i64           ;; 将 64 位整数转换为 32 位整数


i32.const -12345   ;; 32 位带符号整数常量
i64.extend_i32_s   ;; 将 32 位整数扩展为 64 位整数

1)i32.wrap_i64 是一条将 64 位整数(i64)转换为 32 位整数(i32)的指令。它用于将一个较大范围的整数(64 位)转换为一个较小范围的整数(32 位),并且仅保留低 32 位的数值部分。如果 64 位整数超出了 32 位整数的表示范围,结果将会截断为低 32 位的值。

2)i64.extend_i32_s 是一条将 32 位带符号整数(i32)转换为 64 位带符号整数(i64)的指令。它用于将一个较小范围的整数(32 位)扩展为一个较大范围的整数(64 位),并保持其符号位不变。

  • gcc的安装
    官网下载傻瓜式安装,打开MSYS2终端(可以通过开始菜单找到MSYS2 64bit)

    1.执行命令来更新软件包数据库和核心软件包:pacman -Syu
    2.在MSYS2终端中执行以下命令来安装GCC:pacman -S mingw-w64-x86_64-gcc
    3.将MSYS2的bin目录添加到系统的环境变量中:C:\msys64\mingw64\bin
    打开“控制面板” -> “系统和安全” -> “系统” -> “高级系统设置”,点击“环境变量”按钮,将上述路径添加到“Path”变量中
    4.验证安装版本:gcc --version
  • wabt 各个可执行文件介绍
    EXE操作描述
    spectest-interp.exe运行和验证WebAssembly规范测试,确保WebAssembly实现符合规范。
    wasm2c.exe

    将WebAssembly二进制文件(.wasm)转换为C代码,可以用于进一步编译和嵌入应用中。

    wasm2wat.exe将WebAssembly二进制文件转换为文本格式(.wat),便于阅读和编辑。
    wasm-decompile.exe反编译WebAssembly二进制文件为更易读的伪代码,便于理解代码结构和逻辑。
    wasm-interp.exe解释和运行WebAssembly二进制文件,适用于测试和调试。
    wasm-objdump.exe显示WebAssembly二进制文件的内容和结构,类似于Unix系统上的objdump工具。
    wasm-stats.exe显示WebAssembly模块的统计信息,如函数数量、内存使用等。
    wasm-strip.exe从WebAssembly二进制文件中去除不必要的调试信息和符号表,以减小文件大小。
    wasm-validate.exe验证WebAssembly二进制文件的结构和内容是否符合WebAssembly规范。
    wast2json.exe将WebAssembly文本格式文件转换为JSON格式,便于程序化处理。
    wat2wasm.exe将WebAssembly文本格式文件(.wat)转换为二进制格式(.wasm),用于运行和部署。
    wat-desugar.exe处理WebAssembly文本格式文件中的语法糖,将其转换为更基本的格式。
    *.exe --help选项查看详细的使用说明和选项

编译为C: wasm2wat.exe wasm.wasm -o wasm.c
编译伪代码:gcc -std=c99 -Wall -c wasm.c -o wasm.o
之后我们就可以拖入到idea反编译分析伪代码还原算法了

尽管和原始的代码差别较大,但好歹可以开始分析了

编写和编译 Wasm 模块并反编译

官网安装emscripten
2.设置环境变量
C:\Users\*\Desktop\emsdk
C:\Users\*\Desktop\emsdk\upstream\emscripten
3.编写C程序(不一定要C写go、rust都可以,代码都大差不差)

long add_seconds_to_timestamp(long timestamp, int seconds) {
    return timestamp + seconds;
}

int main() {
}

4.使用 Emscripten 编译 hello.c 文件: emcc encrypt.c -o encrypt.wasm -O3 -s WASM=1 --no-entry

5.浏览器打开hello.html,在控制台中就看见输出了我们打印的:Hello, WebAssembly!

实战wasm补环境

通过以上的基础学习与环境安装,我们了解了

实战wasm反编译还原算法

小结

未完成有空待续。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1889549.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计组_机器指令

2024.06.13:计算机组成原理机器指令学习笔记 第13节 机器指令 3.1 指令的作用3.2 指令的格式3.2.1 操作码字段(用户要干什么)3.2.2 (操作数)地址码字段(对谁进行操作)3.2.3 格式分类*(一步步优化&#xff0…

FDL专题:如何在工作中对Kettle任务进行迁移?可以直接调用吗?

IT团队历史数据同步任务过去都用的Kettle来开发,但kettle的定时调度不方便,维护成本高,遇到报错不知道怎么办。苦寻CSDN无果,只得在公司留下一个个深夜加班的背影...... IT经理想到:是否能将任务一步步迁移到一个统一…

易保全推动区块链应用与AI融合创新发展

数字化时代,区块链和人工智能技术作为当下两大“黑科技”,两者的深度结合,正在为企业数字化转型带来前所未有的机遇。 易保全作为国内权威的电子数据存证保全机构,积极探索两者的融合之道,将区块链的去中心化、不可篡…

解锁科研新动力,QtiPlot for Mac——您的数据可视化与分析首选工具!

QtiPlot for Mac,一款专为科研工作者和数据分析爱好者打造的数据可视化与分析神器,它如同科研道路上的得力助手,让复杂的数据分析变得简单直观。🔬📈 这款软件拥有强大的数据导入与处理能力,支持多种数据格…

电脑本机ip地址怎么查?介绍几种简单快捷方法

在数字时代,无论是网络连接、远程操作还是设备识别,IP地址都扮演着至关重要的角色。然而,对于许多电脑用户来说,如何快速准确地查找本机IP地址仍然是一个挑战。虎观代理小二将为您详细介绍几种简单快捷的IP地址查询方法&#xff0…

openssh9.8p1的rpm包

openssh9.8p1的rpm包 centos7下的openssh9.8p1rpm包 安装环境:centos7全系列 已经集成所有依赖到rpm包中,直接安装即可 rpm包下载链接 (免积分下载) 安装命令 tar -zxvf centos7_openssh-9.8.tar cd centos7_openssh-9.8 rpm -Uvh --force --nodeps *…

快速了解GPT-4o和GPT-4区别

GPT-4o简介 在5月14日的OpenAI举行春季发布会上,OpenAI在活动中发布了新旗舰模型“GPT-4o”!据OpenAI首席技术官穆里穆拉蒂(Muri Murati)介绍,GPT-4o在继承GPT-4强大智能的同时,进一步提升了文本、图像及语…

VS开发QT程序图标修改

VS开发QT程序图标修改 1.双击打开UI界面 2.选择编辑资源 3.添加文件 4.选择ico文件 5.ok确定 6.点击保存 7.选择windowsIcon,倒三角图标 8.选择资源 9.选择图标,点击ok 10.保存 编译运行: 任务栏:

电脑免费压缩软件app哪个好?Top15压缩软件良心测评,图文详解!

你是否在寻找一款能够帮助你释放电脑存储空间的免费压缩软件app呢?在当今数字化生活中,文件和媒体内容日益增多,而硬盘空间却总是显得不够用。优秀的压缩工具不仅能节省空间,还能提升系统效率,让你的电脑运行更加流畅。…

Arthas实战(2)- OOM问题排查

一、 准备测试应用 新建一个 SpringBoot应用&#xff0c;写一段有 OOM bug 的代码&#xff1a; RestController RequestMapping public class JvmThreadController {List<TestWrapper> memoryList new ArrayList<>();GetMapping("/test")public Strin…

年份与产地:解锁红酒的秘密密码

在红酒的世界里&#xff0c;年份与产地如同两把神秘的钥匙&#xff0c;它们背后隐藏着红酒不同的魅力与秘密。今天&#xff0c;就让我们一起揭开这层神秘的面纱&#xff0c;探寻年份与产地如何为红酒赋予不同的灵魂&#xff0c;特别是以雷盛红酒为例&#xff0c;感受那份从岁月…

十 .pfc,bus纹波分析与抑制方法

以apfc为例 在分析时用 uin 和 iin 表示输入电压和输入电流&#xff0c;uo 和 io&#xff0c;表示输出电压和输出电流&#xff0c;Uin 和 Iin 表示输入电压和输入电流的幅值&#xff0c;则输入电压和输入电流可以分别表示为&#xff1a; 从式&#xff08;3-3&#xff09;可以…

Python28-1 机器学习算法之决策树

决策树&#xff08;Decision Tree&#xff09; 决策树算法是一种常用的机器学习算法&#xff0c;属于监督学习范畴。它可以用于分类和回归任务&#xff0c;具有易于理解和解释的特点。决策树通过递归将数据分割成更小的子集&#xff0c;构建一个树形结构&#xff0c;其中每个节…

KV260视觉AI套件--PYNQ-DPU-Resnet50

目录 1. 简介 2. 代码解析 3. 全部代码展示 4. 总结 1. 简介 本文以 Resnet50 为例&#xff0c;展示使用 PYNQ 调用 DPU 运行 Resnet50 网络的详细过程&#xff0c;并对其中关键代码做出解释。 PYNQ是一个针对Xilinx Zynq平台的Python开发框架&#xff0c;它允许开发者使…

学校教室NTP电子钟时间是如何同步北京时间的?-讯鹏时钟

在学校教室里&#xff0c;NTP 电子钟精准地显示着时间&#xff0c;与北京时间保持高度同步&#xff0c;为师生们提供了可靠的时间参考。那么&#xff0c;它是如何做到这一点的呢&#xff1f; NTP 电子钟能够与北京时间同步&#xff0c;主要依赖于网络时间协议&#xff08;NTP&a…

准化 | 水系统碳中和标准体系初见成效

2024年5月31日&#xff0c;中华环保联合会发布《团体标准公告 2024年第10号&#xff08;总第78号&#xff09;》&#xff0c;批准发布了由中华环保联合会提出并归口的《废水处理温室气体监测技术规程》(T/ACEF 142-2024)、《工业水系统碳排放核算方法与报告指南》(T/ACEF143-20…

数据驱动:Facebook的广告策略与商业模式

在现代数字经济中&#xff0c;数据已经成为新的石油&#xff0c;驱动着企业的增长和创新。Facebook&#xff0c;作为全球最大的社交媒体平台之一&#xff0c;充分利用其庞大的用户数据和先进的算法技术&#xff0c;建立了一个高度精确和高效的广告生态系统。这不仅推动了平台自…

qtreewidget 美化,htmlcss和qss 不是一个概念!已解决

这种样式的美化&#xff0c; 能气死个人&#xff0c;css 一个单词搞定&#xff0c;非要 在qss中。多少个单词不知道了。 m_tree_widget->setStyleSheet("QTreeView{background:transparent; selection-background-color:transparent;}""QTreeView::branch{b…

PyTorch之nn.Module与nn.functional用法区别

文章目录 1. nn.Module2. nn.functional2.1 基本用法2.2 常用函数 3. nn.Module 与 nn.functional3.1 主要区别3.2 具体样例&#xff1a;nn.ReLU() 与 F.relu() 参考资料 1. nn.Module 在PyTorch中&#xff0c;nn.Module 类扮演着核心角色&#xff0c;它是构建任何自定义神经网…

这次发现的开源版本我愿意称之为最具学习价值的商城系统|商城源码点击进入

这是一款我发现的强大、灵活、易用的商城系统&#xff0c;成为我的的首选商城框架&#xff0c;让我的商城开发事半功倍&#xff01;这款开源商城项目具有多元的商业模式满足了任何使用场景的需求。 有S2B2C供应链商城、B2B2C多商户商城、O2O外卖商城、B2C单商户商城、社区团购、…