WebAssembly内存结构学习记录

news2024/9/24 17:15:12

参考:

大文件上传深入研究:https://juejin.cn/post/6870837414852886542

Worker+Wasm切片上传:https://juejin.cn/post/7221003401996091429

Wasm实现MD5文件编码:https://juejin.cn/post/7319541565318398003

SharedArrayBuffer与幽灵漏洞:https://juejin.cn/post/7300106933745909771

Wasm多线程:https://42yeah.github.io/webassembly/2019/01/14/wasm-threading.html

WebAssembly学习记录:https://blog.csdn.net/qq_37464878/article/details/138202363?spm=1001.2014.3001.5501

阿里巴巴基于Wasm的WebC平台技术会议:https://www.bilibili.com/video/BV1vy411q7Lm/?spm_id_from=333.999.0.0

1.内存结构

1.1 JavaScript内存结构

Text: 代码段

Heap: 堆区

Stack: 栈区

1.2 C内存结构

Text: 代码段

Data: 已初始化全局变量数据段(int a = 1;

Bss: 未初始化全局变量数据段(int a;

Heap: 堆区

Stack: 栈区

在这里插入图片描述

1.3 WASM内存结构

Local:

  • 存储: 函数作用域局部变量。

  • 解释: Wasm汇编语言可访问,C语言中无法直接访问。

  • 举例: 下图的 add函数是C语言提供,里面用local声明了几个局部变量。

Global:

  • 存储: 全局变量。

  • 解释: 引入WebAssembly时从JavaScript注入全局变量。Wasm汇编语言可访问,C语言中无法直接访问。

  • 举例: 下图的 import "wasi_snapshot_preview1"等等表示需要从JavaScript导入全局变量与之对应。fd_xxx等内容是引入了头文件 #include <iostream>导致必须配置的。

在这里插入图片描述

Linear Memory:

  • 存储: 是缓冲区ArrayBuffer或SharedArrayBuffer。
  • 解释: 是线性内存区域,内存单元地址连续。
    • Stack:
      • 存储: 操作栈。
      • 解释: 存储函数局部变量。局部变量和Local的局部变量一一对应,地址是Local的逻辑地址。
      • 原因: Local地址不希望被访问,没有开放C语言访问权限,因此创建Stack区域。
    • Data:
      • 存储: 全局变量。
      • 解释: c语言定义的全局变量存储在Data。
      • 举例: add函数是c语言提供,实现 a + b + 全局变量效果。断点上面两行表示从线性内存1024位置取出值放入栈顶。右侧可以看到栈顶的值已经变成全局变量123。

Table:

  • 存储: 函数的指针
  • 解释: func表示将函数放入table表中
  • 举例: 下图的代码新建了一个函数的指针的表 (table $__indirect_function_table (;0;) (export "__indirect_function_table") 2 2 funcref)

在这里插入图片描述

注:下图提到的“StackPointer”和“MemoryBase”是LLVM编译器的产物,如果使用EMSCRIPTEN不一定有这两个内容

在这里插入图片描述

2.内存交换

2.1 JavaScript和Wasm的内存交换

回顾&类比JavaScript和Worker交换内存

拷贝

ArrayBuffer+MessageChannel

移动

ArrayBuffer+MessageChannel+transferable(postMessage配置)

共享

SharedArrayBuffer+Atomics(上锁)

JavaScript访问Wasm内存

加载完WebAssembly后Wasm默认导出自己的线性内存,JavaScript通过memory对象访问内存 (最大大概16MB)

一般是JavaScript通过调用Wasm函数返回指针或变量配合memory对象访问内存。

c++

// 导出:申请内存函数
// JavaScript可以申请Wasm内存
int* createIntArray(int length) {
 return new int[length];
}

// 导出:写入内存函数
// JavaScript可以写入Wasm内存
void writeToArray(int* arr, int index, int value) {
 arr[index] = value;
} 

// 导出:快排函数
// 基于上述操作JavaScript可以实现和Wasm交互的快速排序
int* qSort(int* arr, int length) {		
 std::sort(arr, arr + length);
 return arr;
}

JavaScript

// 加载WebAssembly
const importObject = {
 wasi_snapshot_preview1: {
     proc_exit: function (code) {
         console.log(`Process exited with code ${code}`);
     },
 },
};
const result = await WebAssembly.instantiateStreaming(fetch(fileName), importObject);

const data = new Int32Array(
 result.instance.exports.memory.buffer,
 // wasm函数返回的指针
 pointer,
 length
);

Wasm访问Javascript内存

ArrayBuffer:

不能访问。JavaScript传来的数据统一被拷贝到ArrayBuffer缓冲区中,进入Wasm的内存区域。

在这里插入图片描述

SharedArrayBuffer:

不能访问。但是可以利用SharedArrayBuffer共享缓冲区,JavaScript调用Wasm导出的函数时把SharedArrayBuffer传给Wasm。此时JavaScript和Wasm可以同时读写同一个缓冲区。

注:SharedArrayBuffer目前默认不支持使用,需要特殊配置响应头,因为共享缓冲区可能导致安全问题

2.2 SharedArrayBuffer安全性

2.2.1 幽灵漏洞

内存工作原理

  • 结构: CPU——高速缓存——内存

预测执行

  • 预测: Intel芯片在2000年左右对CPU执行速度进行优化。对于条件语句,CPU会预测执行结果,会直接忽视条件尝试执行某个分支,并忽视数组越界,内存权限等限制条件,原因是条件计算完后会统一判断。等到条件计算完毕后再决定是否回滚刚才的操作。

  • 回滚: CPU的执行结果会尽可能存入缓存,但是回滚不会消除缓存中的执行结果。

旁信道攻击

  • 遍历: 对数据进行暴力破解,根据程序响应时间来判断破解是否正确。
  • 举例: 比如破解密码,1234567,猜测密码为199999和猜测密码为99999程序反应时间有细微不同,因为1是正确的,一旦访问到会被尽可能放入高速缓存。这样程序响应这两个密码都是错误的时候,199999的响应速度会稍微快一点。

幽灵漏洞举例:

利用预测执行和旁信道攻击来访问没有权限的内存,利用系统的响应速度来判断是否获取成功,获取成功可以直接去高速缓存中获取目标值

2.2.2 高精度计时器

背景

幽灵漏洞的攻击思路是根据读取数据的时间差来判断是否访问到目标内存。但是很早之前浏览器已经降低了 setTimeoutperformance.now可以获取的时间戳的精度,这样来避免攻击者获取到微小的CPU时间差。

制作高精度计时器

创建worker,和主线程共享sharedArrayBuffer区域。worker中通过for循环每次给sharedArrayBuffer的某个区域递增微量的值。

主线程中进行幽灵漏洞攻击,在访问某个内存值前后分别获取sharedArrayBuffer指定位置的值,用差值来表示访问时间,获取高精度时间差。

注意:这个操作非sharedArrayBuffer不可,如果主线程和worker没有共享内存区域,那么必须通过postMessage通信,时间有损耗

高精度计时器举例

Worker

self.onmessage = (event) => {
 const view = new Int8Array(event?.data)
 let time = 0
 while(true) {
     view[0] = time
     time += 0.00001
 }
}

Main

const sharedArrayBuffer = new SharedArrayBuffer(1)
const worker = new Worker('你的worker')
worker.postMessage(sharedArrayBuffer)

setTimeout(() => {
 const startTime = sharedArrayBuffer[0] 
 // 你的幽灵攻击代码 0.0003
 const endTime = sharedArrayBuffer[0]
 // 利用高精度时间来分析你的幽灵攻击过程
}, 
// 等待Worker启动的时间
time) 
2.2.3 安全限制

在ES6开始浏览器就支持SharedArrayBuffer,但是由于上述安全问题会默认禁用该能力。想启用该能力必须配置HTML页面的响应头。

跨源嵌入策略:COEP

Cross-Origin-Embedder-Policy: require-corp

限制嵌入的非同源请求。例如嵌入的资源如果没有配置CORS或CORP跨域,那么请求直接会被拒绝

跨源开放策略:COOP

Cross-Origin-Opener-Policy: same-origin

限制打开的非同源资源交互。例如window.open新打开的页面或使用的worker不允许和原页面通信,除非同源。

副作用举例:

如果background背景图使用了非同源资源,配置上述响应头会导致资源无法加载。

2.3 内存交换问题

拷贝限制:

  • 解释: JavaScript不能直接向wasm传递引用或指针,需要拷贝数据。

  • 举例:

    • 场景: 在处理文件的场景下,JavaScript向wasm传递数据一般通过缓冲区(ArrayBuffer)的视图(TypedArray)进行传递。
    • 内存交换: 缓冲区和视图都不会把缓冲区内容读入内存,但是传递给wasm处理时必须将数据读入内存(拷贝过程)。因为wasm的隔离性,wasm只能读取自己的内存。
    • 副作用: 但是好消息是wasm的内存建立在缓冲区,读写速度不慢,也不占用浏览器内存。

大小限制:

  • 解释: wasm的内存有限制,容易溢栈。
  • 举例:
    • 场景1: 上面1.3中给出的图例中展示了emscripten编译的wasm,C语言和JavaScript都是默认操作,内存上限为16MB。已经达到了上限。
    • 场景2: 在npm发布的一些基于wasm的包(比如hash-wasm),wasm的内存上限可能是64KB,仅允许一次扩容,到128KB。

安全限制:

  • 解释: wasm的内存一般不通过SharedArrayBuffer交换,有安全问题,使用需要配置html页面的响应头。

3.多线程能力

3.1 Wasm多线程

在wasm内部启用多线程需要额外配置编译时的emscripten指令,并且浏览器必须配置开启SharedArrayBuffer。原因是底层依托于浏览器环境,多线程还是需要借助Worker实现。

#include <iostream>
#include <thread>

void count(void) {
 for (int i = 1; i <= 3; i++) {
     std::cout << "Counting " << i << std::endl;
 }
}

int main(void) {
 for (int i = 0; i < 3; i++) {
     std::thread worker(count);
     worker.detach();
 }
 return 0;
}

3.2 Worker+Wasm多线程

不启用SharedArrayBuffer,通过JavaScript实现多线程。每个Web Worker中都引入Wasm进行计算,替换Worker中的JavaScript计算。

Worker+Wasm对文件MD5编码:

下面是一个worker的代码。worker引入hash-wasm,里面引用wasm进行md5运算。

hash-wasm本身不支持在wasm中开启多线程,因此借助worker传入大文件切片来让wasm做编码实现多线程能力。

import SparkMD5 from 'spark-md5'
import { createMD5 } from 'hash-wasm'

/** @constant {string} WebAssembly编码模式 */
const WASM = 'wasm'
/** @constant {string} Javascript编码模式 */
const ORIGIN = 'origin'

// eslint-disable-next-line
self.onmessage = (event) => {
encodeFile(event?.data?.mode, event?.data?.buffer)
}

/**
 * @function encodeByWasm
 * @param {ArrayBuffer} 文件切片内容
 * @returns {Promise} 文件切片编码结果
 * @description 通过WebAssembly对文件MD5编码
 */
const encodeByWasm = async (arrayBuffer) => {
  return createMD5()
    .then((encoder) => {
      // 创建:操作缓冲区的视图
      const buffer = arrayBuffer instanceof ArrayBuffer ? arrayBuffer : new ArrayBuffer()
      const view = new Uint8Array(buffer)
      // 编码:依据当前片段编码
      encoder?.update?.(view)
      // 保存:当前片段的编码结果
      const state = encoder?.save()
      return state
    })
    .catch((err) => {
      console.warn('EncodeByWasm Error', err)
      return null
    })
}

/**
 * @function encodeByOrigin
 * @param {ArrayBuffer} 文件切片内容
 * @returns {Promise} 文件切片编码结果
 * @description 通过Javascript对文件MD5编码
 */
const encodeByOrigin = (arrayBuffer) => {}

/**
 * @param {string} mode 编码模式
 * @param {ArrayBuffer} arrayBuffer 文件切片
 */
const encodeFile = (mode, arrayBuffer) => {
  const codeFunction =
    mode === WASM ? encodeByWasm : mode === ORIGIN ? encodeByOrigin : () => Promise.resolve()
  codeFunction(arrayBuffer).then((result) => {
    // eslint-disable-next-line
    self.postMessage(result)
  })
}

4.浏览器上运行环境

4.1 运行环境综述

在这里插入图片描述

上述的效果是在浏览器端从不同层面模拟一个本不属于浏览器的运行环境。

模拟器类

解释:

只模拟硬件,模拟CPU,寄存器,磁盘,网卡等功能。在该环境上运行的内容,必须是操作系统镜像。

举例:

运行windows2000镜像。https://bellard.org/jslinux/vm.html?url=https://bellard.org/jslinux/win2k.cfg&mem=192&graphic=1&w=1024&h=768

系统接口类

解释:

在模拟了硬件的基础上再次模拟了操作系统,具有文件系统,进程调度,网络管理等操作系统功能。在该环境上运行的内容,必须实现系统接口(调用操作系统功能的函数)。

举例:

运行底层的高级程序语言,C/C++等。https://browsix.org/

WebContainer类

解释:

模拟了硬件,操作系统和系统接口。在该环境上运行的内容,可以是偏高层的高级程序设计语言,不需要实现系统接口和操作系统交互。

举例:

运行JavaScript,Python等等。https://stackblitz.com/

BrowserNode类

解释:

是更高层的模拟。是WebContainer的一个具体方向,只能运行NodeJS相关代码。

举例:

专用的NodeJS运行环境。https://stackblitz.com/

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

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

相关文章

Python | 使用Pygments生成漂亮的代码段截图

在创建技术文档或教程时&#xff0c;包含代码段的图像以说明特定的示例或概念可能会有所帮助。但是&#xff0c;对代码文件进行屏幕截图可能看起来不专业&#xff0c;并且难以阅读。本文将探索如何使用库pygments将编程代码转换为Python中美丽的图像片段。 Pygments库 Pygmen…

基于Java+SpringBoot+Vue+MySQL的失物招领管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的失物招领管理系统【附源码文档】、前后…

Java 入门指南:Java 并发编程 —— 并发容器 LinkedBlockingQueue

BlockingQueue BlockingQueue 是Java并发包&#xff08;java.util.concurrent&#xff09;中提供的一个阻塞队列接口&#xff0c;它继承自 Queue 接口。 BlockingQueue 中的元素采用 FIFO 的原则&#xff0c;支持多线程环境并发访问&#xff0c;提供了阻塞读取和写入的操作&a…

JavaEE---Spring MVC(4)

MVC学习小案例1 在这里我们要实现一个计算器的功能 在这之前,先解决一个bug! 写好代码之后开始运行,运行发现不对,sum计算不出来,然后我百思不得其解, 1.对着后端代码一顿输出,还是没觉得有问题. 2.对着前端代码一顿输出,也没看出任何问题 3.是不是我前后端交互出错了呢?查找…

Python案例 | 四阶龙格库塔法简介

1.引言 在数值分析中&#xff0c;龙格-库塔法&#xff08;Runge-Kutta methods&#xff09;是用于非线性常微分方程的解的重要的一类隐式或显式迭代法。这些技术由数学家卡尔龙格和马丁威尔海姆库塔于1900年左右发明。 龙格-库塔(Runge-Kutta)方法是一种在工程上应用广泛的高…

工厂验收(FAT)和现场验收(SAT)的含义

工厂验收&#xff08;Factory Acceptance Test&#xff0c;FAT&#xff09;和现场验收&#xff08;Site Acceptance Test&#xff0c;SAT&#xff09;是在工程领域中常见的术语&#xff0c;用于确保设备在制造商及用户之间达成一致的验收标准&#xff0c;保证设备能够正常、安全…

【图灵完备 Turing Complete】游戏经验攻略分享 Part.2 算术运算

算术运算部分算是开始有难度了。 前几关按照自己思路来&#xff0c;二进制速算应该没问题。 画真值表&#xff0c;卡诺图&#xff0c;推表达式。 下面几关&#xff0c;几个输出信号分开来看&#xff0c;有三个输出就画三个卡诺图&#xff0c;有几个画几个&#xff0c;分而治之。…

Shadow Dom 是什么

概念 官方&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/API/Web_components/Using_shadow_DOM 核心&#xff1a;影子 DOM&#xff08;Shadow DOM&#xff09;允许你将一个 DOM 树附加到一个元素上&#xff0c;并且使该树的内部对于在页面中运行的 JavaScript 和…

Java笔试面试题AI答之正则表达式(3)

文章目录 13. 简述Java String支持哪几种使用正则表达式的方法&#xff1f;14. 请列举常见校验数字的表达式 &#xff1f;15. 请列举常见校验字符的表达式 &#xff1f;1. 汉字2. 英文和数字3. 特定长度的字符串4. 由26个英文字母组成的字符串5. 由数字和26个英文字母组成的字符…

JVM面试(五)垃圾回收机制和算法

概述 了解Java虚拟机的垃圾回收机制&#xff08;Garbage Collection&#xff0c;简称GC&#xff09;&#xff0c;我们也要像其作者John McCarthy一样&#xff0c;思考一下三个问题&#xff1a; 哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&#xff1f; 虽…

pytorch+深度学习实现图像的神经风格迁移

本文的完整代码和部署教程已上传至本人的GitHub仓库&#xff0c;欢迎各位朋友批评指正&#xff01; 1.各代码文件详解 1.1 train.py train.py 文件负责训练神经风格迁移模型。 加载内容和风格图片&#xff1a;使用 utils.load_image 函数加载并预处理内容和风格图片。初始化…

网络攻击全解析:主动、被动与钓鱼式攻击的深度剖析

在当今这个互联网高度普及与深度融合的时代&#xff0c;网络攻击&#xff0c;这一赛博空间的隐形威胁&#xff0c;正以前所未有的频率和复杂度挑战着网络安全乃至国家安全的底线。为了更好地理解并防范这些威胁&#xff0c;本文将深入剖析网络攻击的主要类型——主动攻击、被动…

程序设计基础

一、程序 1.什么是程序&#xff1f; 程序可以看作是对一系列动作的执行过程的描述。 计算机程序是指为了得到某种结果而由计算机等具有信息处理能力的装置执行的代码化指令序列。 程序的几个性质&#xff1a; ● 目的性 ● 分步性 ● 有限性 ● 可操作性 ● 有序性 2…

Splasthop 安全远程访问帮助企业对抗 Cobalt Strike 载荷网络攻击

一、背景 根据 FreeBuf&#xff08;标题为&#xff1a;潜藏系统2个月未被发现&#xff0c;新型网络攻击瞄准中国高价值目标&#xff09;和 The Hacker News&#xff08;标题为&#xff1a;New Cyberattack Targets Chinese-Speaking Businesses with Cobalt Strike Payloads&a…

农产品自主供销系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;农产品管理&#xff0c;资讯信息管理&#xff0c;订单管理&#xff0c;资讯回复管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;农产品&#xff0c;购物车&#xff0c;我的 开发系统&#…

接口自动化测试学习 —— Mock服务实现

1.Mock实现原理和实现机制 在某些时候&#xff0c;后端在开发接口的时候&#xff0c;处理逻辑非常复杂&#xff0c;在测试的时候&#xff0c;后端在未完成接口的情况下该如何去测试呢&#xff1f; 我们需要测试&#xff0c;但是有些请求又需要修改一下参数&#xff0c;或者改变…

说明书keithley2420吉时利2410数字源表

说明书keithley2420吉时利2410数字源表 产品概述 Keithley 2420 高压源表是一款 60W 仪器&#xff0c;设计用于提供和测量 5V&#xff08;源&#xff09;和 1V&#xff08;测量&#xff09;至 60V 的电压和 100pA 至 3A 的电流。2420 型的生产测试应用包括必须在更高电流水平下…

微信和苹果叫板的资本

这两天&#xff0c;关于苹果用户还能不能使用微信这么一个新闻炒得沸沸扬扬的。其实&#xff0c;在很多年前我就说过&#xff0c;腾讯和苹果必有一战。那么这一战到了今天终于到来了。 原因其实也很简单。这个事件的背后&#xff0c;并不是简单的腾讯和苹果彼此之间抽成争夺的问…

pr瘦脸怎么操作?

相信大家平时在拍摄自己的日常生活的时候&#xff0c;通常为了保证视频的清晰度往往都会选择原相机进行拍摄&#xff0c;原相机拍摄自然就会清清楚楚的将我们的真实展现出来&#xff0c;特别是脸部肥大~那么&#xff0c;这么大的一张脸这么可以瘦下去呢&#xff1f;其实使用PR软…

glsl着色器学习(五)

接下来是创建buffer&#xff0c;设置顶点位置&#xff0c;法线&#xff0c;顶点索引等。 const cubeVertexPositions new Float32Array([1, 1, -1,1, 1, 1, 1, -1, 1, 1, -1, -1,-1, 1, 1, -1, 1, -1,-1, -1, -1,-1, -1, 1,-1, 1, 1,1, 1, 1,1, 1, -1,-1, 1, -1,-1, -1, -1,1…