wasm的逆向之旅一

目录

概要

技术名词解释

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.mfbz.cn/a/768668.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Landsat数据从Collection1更改为Collection2

目录 问题解决 问题 需要注意!您使用的是废弃的陆地卫星数据集。为确保功能持续,请在2024年7月1日前更新。 在使用一些以前的代码时会遇到报错,因为代码里面用的是老的数据集 解决 对于地表反射率SR,需要在name中,将C01换为C02&…

weblogic加入第三方数据库代理驱动jar包(Oracle为例)

做的是国企项目,项目本身业务并不复杂,最复杂的却是服务器部署问题,对方给提供的服务器分内网、外网交换网,应用在交换网,数据库在内网,应用不能直接访问内网数据库,只能通过安全隔离网闸访问内…

初学Spring之 IOC 控制反转

Spring 是一个轻量级的控制反转&#xff08;IOC&#xff09;和面向切面编程&#xff08;AOP&#xff09;的框架 导入 jar 包&#xff1a;spring-webmvc、spring-jdbc <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc&l…

OpenCV教程02:图像处理系统1.0(翻转+形态学+滤波+缩放+旋转)

-------------OpenCV教程集合------------- Python教程99&#xff1a;一起来初识OpenCV&#xff08;一个跨平台的计算机视觉库&#xff09; OpenCV教程01&#xff1a;图像的操作&#xff08;读取显示保存属性获取和修改像素值&#xff09; OpenCV教程02&#xff1a;图像处理…

调试 hipcc 的llvm llc gpu目标代码生成模块

源码&#xff1a; hello_vectorAdd.hip: __global__ void vectorAdd(const float *A, const float *B, float *C) {int i blockDim.x * blockIdx.x threadIdx.x;C[i] A[i] B[i] 0.0f; } Makefile: x.O1.s: hello_vectorAdd.hip../../local_amdgpu/bin/clang ./hello_vec…

【C++】#1

关键字&#xff1a; 基本框架、多个main执行、快捷键、cout规则 基本框架&#xff1a; #include <iostream> using namespace std;int main() {//具体内容return 0; } 多个main函数可执行&#xff1a; 常用快捷键&#xff1a; cout规则&#xff1a;

eventloop 事件循环机制 (猜答案)

// eventloop 事件循环机制// console.log(555);setTimeout(() > {console.log(666);})let p new Promise((resolve,reject)>{// 同步执行console.log(111);resolve();});// promise 的回调函数是异步的微任务p.then(v > {console.log(222);}, r > {console.log(r…

pjsip环境搭建、编译源码生成.lib库

使用平台&#xff1a; windows qt(5.15.2) vs(2019)x86 pjsip版本以及第三方库使用 pjsip 2.10 ffmpeg4.2.1 sdl2.0.12pjsip源码链接&#xff1a; https://github.com/pjsip/pjproject源码环境配置 首先创建两个文件夹&#xff0c;分别是include、lib其中include放置ff…

【leetcode64-69二分查找、70-74栈、75-77堆】

二分查找[64-69] 时间复杂度O(log n)&#xff0c;要想到二分排序 35.搜索插入位置 class Solution:def searchInsert(self, nums: List[int], target: int) -> int:left 0right len(nums)-1while left < right: #左闭右闭mid (leftright)//2if nums[mid] < target…

【SpringBoot配置文件读取】无法读取yaml文件中文字符

1. yaml配置文件 注意要将该文件编码格式改为UTF-8 spring:application:name: 好好学习admin:name: 李斯age: 24books:- name: 数据结构desc: 数据书- name: 编译原理desc: 编译书2.配置实体类 Data设置get&#xff0c;set方法Component注册为BeanConfigurationProperties(p…

Android设备信息(DevInfo)

软件介绍 设备信息&#xff08;DevInfo&#xff09;一款评分非常不错的手机硬件及各种信息检测应用&#xff0c;安卓设备硬件检测工具。可以全面查看手机的各种信息、包括&#xff1a;Android系统版本的详细信息、芯片CPU处理器的详细信息、全球卫星定位、测试功能、硬件温度、…

【深度学习】Transformer

李宏毅深度学习笔记 https://blog.csdn.net/Tink1995/article/details/105080033 https://blog.csdn.net/leonardotu/article/details/135726696 https://blog.csdn.net/u012856866/article/details/129790077 Transformer 是一个基于自注意力的序列到序列模型&#xff0c;与基…

Labview绘制柱状图

废话不多说&#xff0c;直接上图 我喜欢用NXG风格&#xff0c;这里我个人选的是xy图。 点击箭头指的地方 选择直方图 插值选择第一个 直方图类型我选的是第二个效果如图。 程序部分如图。 最后吐槽一句&#xff0c;现在看CSDN好多文章都要收费了&#xff0c;哪怕一些简单的入…

比较多种msvcr110.dll丢失的解决方法,哪一种更加方便?

当遇到“msvcr110.dll丢失”这种问题时&#xff0c;这通常意味着你的系统中缺少了Microsoft Visual C 2012 Redistributable的组件。下面我将详细介绍五种解决方法&#xff0c;并对比它们的优点。 一.多种msvcr110.dll丢失的解决方法 方法 1: 重新安装Microsoft Visual C 2012…

《IT 领域准新生暑期预习指南:开启未来科技之旅》

IT专业入门&#xff0c;高考假期预习指南 高考的落幕&#xff0c;只是人生长途中的一个逗号&#xff0c;对于心怀 IT 梦想的少年们&#xff0c;新的征程已然在脚下铺展。这个七月&#xff0c;当分数尘埃落定&#xff0c;你们即将迈向新的知识殿堂&#xff0c;而这个假期&#…

DEPTHAI 2.27.0 发布!

小伙伴们大家好&#xff0c;我们发布了DepthAI 2.27.0版本&#xff0c;本次对DepthAI库有了一些小更新&#xff0c;以下是更新内容。 功能 设置DEPTHAI_ENABLE_FEEDBACK_CRASHDUMP时自动故障转储收集&#xff1b; 漏洞修补 修复深度超出ImageAlign节点时生成PointCloud的问…

安卓手机软件自动运行插件的开发流程及代码科普!

随着智能手机的普及和移动互联网的快速发展&#xff0c;安卓手机软件的需求日益旺盛&#xff0c;为了提高软件的功能性和扩展性&#xff0c;许多开发者选择通过插件的方式为软件添加新功能。 一、安卓手机软件自动运行插件的开发流程 1、明确需求与目标 在开发安卓手机自动运…

STM32——GPIO(点亮LED)

一、GPIO是什么&#xff1f; 1、GPI/O(general porpose intput output):通用输入输出端口的简称&#xff0c;通俗地说&#xff0c;就是我们所学的51单片机的IO口&#xff0c;即P0_0等。但要注意&#xff1a;并非所有的引脚都是GPIO 输出模式下可控制端口输出高低电平&#xf…

echarts-wordcloud:打造个性化词云库

前言 在当今信息爆炸的时代&#xff0c;如何从海量的文本数据中提取有用的信息成为了一项重要的任务。词云作为一种直观、易于理解的数据可视化方式&#xff0c;被广泛应用于文本分析和可视化领域。本文将介绍一种基于 echarts-wordcloud 实现的词云库&#xff0c;通过其丰富的…

uniapp + vue3 + Script Setup 写法变动 (持续更新)

一、uniapp 应用生命周期&#xff1a; https://uniapp.dcloud.net.cn/tutorial/vue3-composition-api.html 注意&#xff1a; 应用生命周期仅可在App.vue中监听&#xff0c;在其它页面监听无效。 二 、uniapp页面生命周期&#xff1a; https://uniapp.dcloud.net.cn/tutori…