├── .gitignore ├── LICENSE ├── Misc └── Web-(Dis)Assembly.pdf ├── README.md └── Tools ├── IDA-Wasm ├── README.md ├── wasm_loader.py └── wasm_processor.py ├── Kaitai-Wasm ├── Makefile ├── requirements.txt ├── tests │ └── hello.wasm ├── vlq_base128_le.ksy ├── wasm-disassembler.py └── webassembly.ksy └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__ 3 | *.pyo 4 | *.pyd 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2019 Sophos Group PLC 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /Misc/Web-(Dis)Assembly.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophoslabs/WebAssembly/8ac3c7183b860599573622aceb207b94de7640f3/Misc/Web-(Dis)Assembly.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly # 2 | 3 | This repository contains some tools developed to help analyzing [WebAssembly format](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md): 4 | 5 | - the `Tools/` contains all the tools including: 6 | - a [Kaitai](https://kaitai.io) module for parsing `.wasm` files 7 | - a [IDA Pro](https://www.hex-rays.com/products/ida) processor and loader for the file format 8 | - the `Misc/` contains the slides for the [presentation on WebAssembly at Shakacon X](https://www.shakacon.org/web-disassembly-in-depth-peek-at-the-vm-running-inside-your-web-browser-by-christophe-alladoum/) 9 | 10 | 11 | -------------------------------------------------------------------------------- /Tools/IDA-Wasm/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly module for IDA Pro # 2 | 3 | To support `.wasm` parsing in IDA Pro, it is required to have IDA Pro 7+ with IDAPython. The installation can be done by copying the files 4 | `wasm_processor.py` (respectively `wasm_loader.py`) into the following directories: 5 | 6 | - `C:\Program Files\IDA 7.x\procs` (resp. `C:\Program Files\IDA 7.x\loaders`) for a system-wide installation (need Admin privileges) 7 | - `%APPDATA%\Hex Rays\IDA\procs` (resp. `%APPDATA%\Hex Rays\IDA\procs`) for a user-specific installation 8 | 9 | ![preview.png](https://i.imgur.com/ROf2pXM.png) 10 | 11 | 12 | ## Known bugs ## 13 | 14 | - Since WASM uses function indexes and not addresses for function calls, the xref support for `call` instructions is not working correctly 15 | - Exports tab does not uses the WASM function declaration 16 | - Imports tab does not uses the WASM header 17 | 18 | -------------------------------------------------------------------------------- /Tools/IDA-Wasm/wasm_loader.py: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | # -*- coding: utf-8 -*- 3 | # 4 | # WebAssembly loader for IDA Pro 7.+ 5 | # 6 | # 7 | # To install, simply copy `wasm_loader.py` in : 8 | # - C:\Program Files\IDA 7.1\loaders (system-wide) 9 | # - %APPDATA%\Hex Rays\IDA\loaders (user only) 10 | # 11 | 12 | from __future__ import print_function 13 | 14 | import io, struct 15 | import idc, idaapi 16 | from idaapi import * 17 | from idc import * 18 | 19 | 20 | # 21 | # Change here to enable verbose output 22 | # 23 | DEBUG = False 24 | 25 | 26 | def enum(**enums): 27 | return type('Enum', (), enums) 28 | 29 | def u8 (x): return struct.unpack(">", 200 | "a_sizeof_fmt": "size %s", 201 | } 202 | 203 | instruc = instrs = [ 204 | ### (name , opcode , description , ida-feature) 205 | ## Feature bits: https://www.hex-rays.com/products/ida/support/sdkdoc/group___c_f__.html 206 | 207 | # Control flow operators 208 | {"name": "unreachable", "opcode": 0x00, "description": "trap immediately", "feature": CF_STOP, "args": []}, 209 | {"name": "nop", "opcode": 0x01, "description": "no operation", "feature": 0, "args": []}, 210 | {"name": "block", "opcode": 0x02, "description": "begin a sequence of expressions, yielding 0 or 1 values", "feature": CF_JUMP, "args": [block_type, ]}, 211 | {"name": "loop", "opcode": 0x03, "description": "begin a block which can also form control flow loops", "feature": CF_JUMP, "args": [block_type, ]}, 212 | {"name": "if", "opcode": 0x04, "description": "begin if expression", "feature": CF_JUMP, "args": [block_type, ]}, 213 | {"name": "else", "opcode": 0x05, "description": "begin else expression of if", "feature": 0, "args": []}, 214 | {"name": "end", "opcode": 0x0b, "description": "end a block, loop, or if", "feature": 0, "args": []}, 215 | {"name": "br", "opcode": 0x0c, "description": "break that targets an outer nested block", "feature": CF_JUMP, "args": [varuint32, ]}, 216 | {"name": "br_if", "opcode": 0x0d, "description": "conditional break that targets an outer nested block", "feature": CF_JUMP, "args": [varuint32, ]}, 217 | {"name": "br_table", "opcode": 0x0e, "description": "branch table control flow construct", "feature": CF_JUMP, "args": []}, 218 | {"name": "return", "opcode": 0x0f, "description": "return zero or one value from this function", "feature": CF_STOP, "args": []}, 219 | 220 | # Call operators 221 | {"name": "call", "opcode": 0x10, "description": "call a function by its index", "feature": CF_CALL, "args": [varuint32, ]}, 222 | {"name": "call_indirect", "opcode": 0x11, "description": "call a function indirect with an expected signature", "feature": CF_CALL , "args": [varuint32, ]}, 223 | 224 | # Parametric operators 225 | {"name": "drop", "opcode": 0x1a, "description": "ignore value", "feature": 0, "args": []}, 226 | {"name": "select", "opcode": 0x1b, "description": "select one of two values based on condition", "feature": 0, "args": []}, 227 | 228 | # Variable access 229 | {"name": "get_local", "opcode": 0x20, "description": "read a local variable or parameter", "feature": CF_USE1, "args": [varuint32, ]}, 230 | {"name": "set_local", "opcode": 0x21, "description": "write a local variable or parameter", "feature": CF_USE1 | CF_CHG1, "args": [varuint32, ]}, 231 | {"name": "tee_local", "opcode": 0x22, "description": "write a local variable or parameter and return the same value", "feature": CF_USE1 | CF_CHG1 | CF_JUMP, "args": [varuint32, ]}, 232 | {"name": "get_global", "opcode": 0x23, "description": "read a global variable", "feature": CF_USE1, "args": [varuint32, ]}, 233 | {"name": "set_global", "opcode": 0x24, "description": "write a global variable", "feature": CF_CHG1, "args": [varuint32, ]}, 234 | 235 | # # Memory-related operators 236 | {"name": "i32.load" , "opcode": 0x28, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 237 | {"name": "i64.load" , "opcode": 0x29, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 238 | {"name": "f32.load" , "opcode": 0x2a, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 239 | {"name": "f64.load" , "opcode": 0x2b, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 240 | {"name": "i32.load8_s" , "opcode": 0x2c, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 241 | {"name": "i32.load8_u" , "opcode": 0x2d, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 242 | {"name": "i32.load16_s" , "opcode": 0x2e, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 243 | {"name": "i32.load16_u" , "opcode": 0x2f, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 244 | {"name": "i64.load8_s" , "opcode": 0x30, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 245 | {"name": "i64.load8_u" , "opcode": 0x31, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 246 | {"name": "i64.load16_s" , "opcode": 0x32, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 247 | {"name": "i64.load16_u" , "opcode": 0x33, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 248 | {"name": "i64.load32_s" , "opcode": 0x34, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 249 | {"name": "i64.load32_u" , "opcode": 0x35, "description": "load from memory", "feature": CF_USE1, "args": [memory_immediate,]}, 250 | {"name": "i32.store" , "opcode": 0x36, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 251 | {"name": "i64.store" , "opcode": 0x37, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 252 | {"name": "f32.store" , "opcode": 0x38, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 253 | {"name": "f64.store" , "opcode": 0x39, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 254 | {"name": "i32.store8" , "opcode": 0x3a, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 255 | {"name": "i32.store16" , "opcode": 0x3b, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 256 | {"name": "i64.store8" , "opcode": 0x3c, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 257 | {"name": "i64.store16" , "opcode": 0x3d, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 258 | {"name": "i64.store32" , "opcode": 0x3e, "description": "store to memory", "feature": CF_USE1, "args": [memory_immediate,]}, 259 | {"name": "current_memory", "opcode": 0x3f, "description": "query the size of memory", "feature": 0, "args": [varuint32,]}, 260 | {"name": "grow_memory" , "opcode": 0x40, "description": "grow the size of memory", "feature": CF_USE1, "args": [varuint32,]}, 261 | 262 | # # Constants 263 | {"name": "i32.const", "opcode": 0x41, "description": "a constant value interpreted as i32", "feature": CF_USE1, "args": [varuint32,]}, 264 | {"name": "i64.const", "opcode": 0x42, "description": "a constant value interpreted as i64", "feature": CF_USE1, "args": [varuint64,]}, 265 | {"name": "f32.const", "opcode": 0x43, "description": "a constant value interpreted as f32", "feature": CF_USE1, "args": [uint32, ]}, 266 | {"name": "f64.const", "opcode": 0x44, "description": "a constant value interpreted as f64", "feature": CF_USE1, "args": [uint64, ]}, 267 | 268 | # Comparison operators 269 | {"name": "i32.eqz", "opcode": 0x45, "description": "", "feature": 0, "args": []}, 270 | {"name": "i32.eq", "opcode": 0x46, "description": "", "feature": 0, "args": []}, 271 | {"name": "i32.ne", "opcode": 0x47, "description": "", "feature": 0, "args": []}, 272 | {"name": "i32.lt_s", "opcode": 0x48, "description": "", "feature": 0, "args": []}, 273 | {"name": "i32.lt_u" , "opcode": 0x49, "description": "", "feature": 0, "args": []}, 274 | {"name": "i32.gt_s" , "opcode": 0x4a, "description": "", "feature": 0, "args": []}, 275 | {"name": "i32.gt_u" , "opcode": 0x4b, "description": "", "feature": 0, "args": []}, 276 | {"name": "i32.le_s" , "opcode": 0x4c, "description": "", "feature": 0, "args": []}, 277 | {"name": "i32.le_u" , "opcode": 0x4d, "description": "", "feature": 0, "args": []}, 278 | {"name": "i32.ge_s" , "opcode": 0x4e, "description": "", "feature": 0, "args": []}, 279 | {"name": "i32.ge_u" , "opcode": 0x4f, "description": "", "feature": 0, "args": []}, 280 | {"name": "i64.eqz", "opcode": 0x50, "description": "", "feature": 0, "args": []}, 281 | {"name": "i64.eq", "opcode": 0x51, "description": "", "feature": 0, "args": []}, 282 | {"name": "i64.ne", "opcode": 0x52, "description": "", "feature": 0, "args": []}, 283 | {"name": "i64.lt_s" , "opcode": 0x53, "description": "", "feature": 0, "args": []}, 284 | {"name": "i64.lt_u" , "opcode": 0x54, "description": "", "feature": 0, "args": []}, 285 | {"name": "i64.gt_s" , "opcode": 0x55, "description": "", "feature": 0, "args": []}, 286 | {"name": "i64.gt_u" , "opcode": 0x56, "description": "", "feature": 0, "args": []}, 287 | {"name": "i64.le_s" , "opcode": 0x57, "description": "", "feature": 0, "args": []}, 288 | {"name": "i64.le_u" , "opcode": 0x58, "description": "", "feature": 0, "args": []}, 289 | {"name": "i64.ge_s" , "opcode": 0x59, "description": "", "feature": 0, "args": []}, 290 | {"name": "i64.ge_u" , "opcode": 0x5a, "description": "", "feature": 0, "args": []}, 291 | {"name": "f32.eq" , "opcode": 0x5b, "description": "", "feature": 0, "args": []}, 292 | {"name": "f32.ne" , "opcode": 0x5c, "description": "", "feature": 0, "args": []}, 293 | {"name": "f32.lt" , "opcode": 0x5d, "description": "", "feature": 0, "args": []}, 294 | {"name": "f32.gt" , "opcode": 0x5e, "description": "", "feature": 0, "args": []}, 295 | {"name": "f32.le" , "opcode": 0x5f, "description": "", "feature": 0, "args": []}, 296 | {"name": "f32.ge" , "opcode": 0x60, "description": "", "feature": 0, "args": []}, 297 | {"name": "f64.eq" , "opcode": 0x61, "description": "", "feature": 0, "args": []}, 298 | {"name": "f64.ne" , "opcode": 0x62, "description": "", "feature": 0, "args": []}, 299 | {"name": "f64.lt" , "opcode": 0x63, "description": "", "feature": 0, "args": []}, 300 | {"name": "f64.gt" , "opcode": 0x64, "description": "", "feature": 0, "args": []}, 301 | {"name": "f64.le" , "opcode": 0x65, "description": "", "feature": 0, "args": []}, 302 | {"name": "f64.ge" , "opcode": 0x66, "description": "", "feature": 0, "args": []}, 303 | 304 | # Numeric operators 305 | {"name": "i32.clz", "opcode": 0x67, "description": "", "feature": 0, "args": []}, 306 | {"name": "i32.ctz", "opcode": 0x68, "description": "", "feature": 0, "args": []}, 307 | {"name": "i32.popcnt", "opcode": 0x69, "description": "", "feature": 0, "args": []}, 308 | {"name": "i32.add", "opcode": 0x6a, "description": "", "feature": 0, "args": []}, 309 | {"name": "i32.sub", "opcode": 0x6b, "description": "", "feature": 0, "args": []}, 310 | {"name": "i32.mul", "opcode": 0x6c, "description": "", "feature": 0, "args": []}, 311 | {"name": "i32.div_s", "opcode": 0x6d, "description": "", "feature": 0, "args": []}, 312 | {"name": "i32.div_u", "opcode": 0x6e, "description": "", "feature": 0, "args": []}, 313 | {"name": "i32.rem_s", "opcode": 0x6f, "description": "", "feature": 0, "args": []}, 314 | {"name": "i32.rem_u", "opcode": 0x70, "description": "", "feature": 0, "args": []}, 315 | {"name": "i32.and", "opcode": 0x71, "description": "", "feature": 0, "args": []}, 316 | {"name": "i32.or", "opcode": 0x72, "description": "", "feature": 0, "args": []}, 317 | {"name": "i32.xor", "opcode": 0x73, "description": "", "feature": 0, "args": []}, 318 | {"name": "i32.shl", "opcode": 0x74, "description": "", "feature": 0, "args": []}, 319 | {"name": "i32.shr_s", "opcode": 0x75, "description": "", "feature": 0, "args": []}, 320 | {"name": "i32.shr_u", "opcode": 0x76, "description": "", "feature": 0, "args": []}, 321 | {"name": "i32.rotl", "opcode": 0x77, "description": "", "feature": 0, "args": []}, 322 | {"name": "i32.rotr", "opcode": 0x78, "description": "", "feature": 0, "args": []}, 323 | {"name": "i64.clz", "opcode": 0x79, "description": "", "feature": 0, "args": []}, 324 | {"name": "i64.ctz", "opcode": 0x7a, "description": "", "feature": 0, "args": []}, 325 | {"name": "i64.popcnt", "opcode": 0x7b, "description": "", "feature": 0, "args": []}, 326 | {"name": "i64.add", "opcode": 0x7c, "description": "", "feature": 0, "args": []}, 327 | {"name": "i64.sub", "opcode": 0x7d, "description": "", "feature": 0, "args": []}, 328 | {"name": "i64.mul", "opcode": 0x7e, "description": "", "feature": 0, "args": []}, 329 | {"name": "i64.div_s", "opcode": 0x7f, "description": "", "feature": 0, "args": []}, 330 | {"name": "i64.div_u", "opcode": 0x80, "description": "", "feature": 0, "args": []}, 331 | {"name": "i64.rem_s", "opcode": 0x81, "description": "", "feature": 0, "args": []}, 332 | {"name": "i64.rem_u", "opcode": 0x82, "description": "", "feature": 0, "args": []}, 333 | {"name": "i64.and", "opcode": 0x83, "description": "", "feature": 0, "args": []}, 334 | {"name": "i64.or", "opcode": 0x84, "description": "", "feature": 0, "args": []}, 335 | {"name": "i64.xor", "opcode": 0x85, "description": "", "feature": 0, "args": []}, 336 | {"name": "i64.shl", "opcode": 0x86, "description": "", "feature": 0, "args": []}, 337 | {"name": "i64.shr_s", "opcode": 0x87, "description": "", "feature": 0, "args": []}, 338 | {"name": "i64.shr_u", "opcode": 0x88, "description": "", "feature": 0, "args": []}, 339 | {"name": "i64.rotl", "opcode": 0x89, "description": "", "feature": 0, "args": []}, 340 | {"name": "i64.rotr", "opcode": 0x8a, "description": "", "feature": 0, "args": []}, 341 | {"name": "f32.abs", "opcode": 0x8b, "description": "", "feature": 0, "args": []}, 342 | {"name": "f32.neg", "opcode": 0x8c, "description": "", "feature": 0, "args": []}, 343 | {"name": "f32.ceil", "opcode": 0x8d, "description": "", "feature": 0, "args": []}, 344 | {"name": "f32.floor", "opcode": 0x8e, "description": "", "feature": 0, "args": []}, 345 | {"name": "f32.trunc", "opcode": 0x8f, "description": "", "feature": 0, "args": []}, 346 | {"name": "f32.nearest", "opcode": 0x90, "description": "", "feature": 0, "args": []}, 347 | {"name": "f32.sqrt", "opcode": 0x91, "description": "", "feature": 0, "args": []}, 348 | {"name": "f32.add", "opcode": 0x92, "description": "", "feature": 0, "args": []}, 349 | {"name": "f32.sub", "opcode": 0x93, "description": "", "feature": 0, "args": []}, 350 | {"name": "f32.mul", "opcode": 0x94, "description": "", "feature": 0, "args": []}, 351 | {"name": "f32.div", "opcode": 0x95, "description": "", "feature": 0, "args": []}, 352 | {"name": "f32.min", "opcode": 0x96, "description": "", "feature": 0, "args": []}, 353 | {"name": "f32.max", "opcode": 0x97, "description": "", "feature": 0, "args": []}, 354 | {"name": "f32.copysign", "opcode": 0x98, "description": "", "feature": 0, "args": []}, 355 | {"name": "f64.abs", "opcode": 0x99, "description": "", "feature": 0, "args": []}, 356 | {"name": "f64.neg", "opcode": 0x9a, "description": "", "feature": 0, "args": []}, 357 | {"name": "f64.ceil", "opcode": 0x9b, "description": "", "feature": 0, "args": []}, 358 | {"name": "f64.floor", "opcode": 0x9c, "description": "", "feature": 0, "args": []}, 359 | {"name": "f64.trunc", "opcode": 0x9d, "description": "", "feature": 0, "args": []}, 360 | {"name": "f64.nearest", "opcode": 0x9e, "description": "", "feature": 0, "args": []}, 361 | {"name": "f64.sqrt", "opcode": 0x9f, "description": "", "feature": 0, "args": []}, 362 | {"name": "f64.add", "opcode": 0xa0, "description": "", "feature": 0, "args": []}, 363 | {"name": "f64.sub", "opcode": 0xa1, "description": "", "feature": 0, "args": []}, 364 | {"name": "f64.mul", "opcode": 0xa2, "description": "", "feature": 0, "args": []}, 365 | {"name": "f64.div", "opcode": 0xa3, "description": "", "feature": 0, "args": []}, 366 | {"name": "f64.min", "opcode": 0xa4, "description": "", "feature": 0, "args": []}, 367 | {"name": "f64.max", "opcode": 0xa5, "description": "", "feature": 0, "args": []}, 368 | {"name": "f64.copysign", "opcode": 0xa6, "description": "", "feature": 0, "args": []}, 369 | 370 | # # Conversions 371 | {"name": "i32.wrap/i64", "opcode": 0xa7, "description": "", "feature": 0, "args": []}, 372 | {"name": "i32.trunc_s/f32", "opcode": 0xa8, "description": "", "feature": 0, "args": []}, 373 | {"name": "i32.trunc_u/f32", "opcode": 0xa9, "description": "", "feature": 0, "args": []}, 374 | {"name": "i32.trunc_s/f64", "opcode": 0xaa, "description": "", "feature": 0, "args": []}, 375 | {"name": "i32.trunc_u/f64", "opcode": 0xab, "description": "", "feature": 0, "args": []}, 376 | {"name": "i64.extend_s/i32", "opcode": 0xac, "description": "", "feature": 0, "args": []}, 377 | {"name": "i64.extend_u/i32", "opcode": 0xad, "description": "", "feature": 0, "args": []}, 378 | {"name": "i64.trunc_s/f32", "opcode": 0xae, "description": "", "feature": 0, "args": []}, 379 | {"name": "i64.trunc_u/f32", "opcode": 0xaf, "description": "", "feature": 0, "args": []}, 380 | {"name": "i64.trunc_s/f64", "opcode": 0xb0, "description": "", "feature": 0, "args": []}, 381 | {"name": "i64.trunc_u/f64", "opcode": 0xb1, "description": "", "feature": 0, "args": []}, 382 | {"name": "f32.convert_s/i32", "opcode": 0xb2, "description": "", "feature": 0, "args": []}, 383 | {"name": "f32.convert_u/i32", "opcode": 0xb3, "description": "", "feature": 0, "args": []}, 384 | {"name": "f32.convert_s/i64", "opcode": 0xb4, "description": "", "feature": 0, "args": []}, 385 | {"name": "f32.convert_u/i64", "opcode": 0xb5, "description": "", "feature": 0, "args": []}, 386 | {"name": "f32.demote/f64", "opcode": 0xb6, "description": "", "feature": 0, "args": []}, 387 | {"name": "f64.convert_s/i32", "opcode": 0xb7, "description": "", "feature": 0, "args": []}, 388 | {"name": "f64.convert_u/i32", "opcode": 0xb8, "description": "", "feature": 0, "args": []}, 389 | {"name": "f64.convert_s/i64", "opcode": 0xb9, "description": "", "feature": 0, "args": []}, 390 | {"name": "f64.convert_u/i64", "opcode": 0xba, "description": "", "feature": 0, "args": []}, 391 | {"name": "f64.promote/f32", "opcode": 0xbb, "description": "", "feature": 0, "args": []}, 392 | 393 | # Reinterpretations 394 | {"name": "i32.reinterpret/f32", "opcode": 0xbc, "description": "", "feature": 0, "args": []}, 395 | {"name": "i64.reinterpret/f64", "opcode": 0xbd, "description": "", "feature": 0, "args": []}, 396 | {"name": "f32.reinterpret/i32", "opcode": 0xbe, "description": "", "feature": 0, "args": []}, 397 | {"name": "f64.reinterpret/i64", "opcode": 0xbf, "description": "", "feature": 0, "args": []}, 398 | 399 | ] 400 | 401 | instruc_end = len(instruc) 402 | 403 | def __init__(self): 404 | processor_t.__init__(self) 405 | self.PTRSZ = 4 406 | self.init_instructions() 407 | self.init_registers() 408 | return 409 | 410 | 411 | # 412 | # Processor callback section 413 | # 414 | 415 | def notify_get_autocmt(self, insn): 416 | for name, itype in self.inames.iteritems(): 417 | if itype == insn.itype: 418 | for wi in self.insns: 419 | if wi.name == name: 420 | return wi.description 421 | 422 | 423 | def notify_emu(self, insn): 424 | dbg("in notify_emu...") 425 | aux = insn.auxpref 426 | ft = insn.get_canon_feature() 427 | 428 | if ft & CF_STOP == 0: 429 | add_cref(insn.ea, insn.ea + insn.size, fl_F) 430 | if ft & CF_JUMP: 431 | if self.insns[insn.itype].name == "if": 432 | nb = 0 433 | while True: 434 | cur = insn.get_next_byte() 435 | nb += 1 436 | if cur in (0x05, 0x0b): # `end` or `else` 437 | break 438 | nb += 1 439 | insn.size -= nb 440 | add_cref(insn.ea, insn.ea + nb, fl_JN) 441 | else: 442 | remember_problem(PR_JUMP, insn.ea) 443 | return 1 444 | 445 | 446 | def notify_out_operand(self, ctx, op): 447 | dbg("in notify_out_operand...") 448 | optype = op.type 449 | fl = op.specval 450 | signed = OOF_SIGNED if fl & FL_SIGNED else 0 451 | ctx.out_value(op, OOFW_IMM | signed | (OOFW_32 if self.PTRSZ == 4 else OOFW_64)) 452 | return True 453 | 454 | 455 | def notify_out_insn(self, ctx): 456 | dbg("in notify_out_insn...") 457 | operands = [] 458 | 459 | ctx.out_mnemonic() 460 | for i in range(UA_MAXOP): 461 | op = ctx.insn[i] 462 | if op.type == o_void: break 463 | operands.append(op) 464 | 465 | for i, op in enumerate(operands): 466 | ctx.out_char(' ') 467 | ctx.out_one_operand(i) 468 | if i != len(operands)-1: 469 | ctx.out_symbol(',') 470 | 471 | ctx.set_gen_cmt() 472 | ctx.flush_outbuf() 473 | return 474 | 475 | 476 | def notify_ana(self, insn): 477 | dbg("in notify_ana...") 478 | self._ana(insn) 479 | return insn.size 480 | 481 | 482 | def ev_out_operand(self, ctx, op): 483 | dbg("in ev_out_operand...") 484 | return 1 485 | 486 | 487 | def ev_out_insn(self, ctx): 488 | dbg("in ev_out_insn...") 489 | return 490 | 491 | 492 | 493 | # 494 | # Processor initialization 495 | # 496 | 497 | 498 | def init_instructions(self): 499 | dbg("Initializing WASM processor instruction set...") 500 | self.inames = {} 501 | self.insns = {} 502 | WasmInstruction = collections.namedtuple("WasmInstruction", ["name" , "opcode" , "description" , "feature", "args"]) 503 | for i, ins in enumerate(self.instrs): 504 | wi = WasmInstruction(**ins) 505 | self.inames[wi.name] = i 506 | self.insns[wi.opcode] = wi 507 | return 508 | 509 | 510 | 511 | def init_registers(self): 512 | self.regs_num = 1 513 | self.reg_names = ["r%d" % d for d in range(0, self.regs_num)] 514 | self.reg_names+= ["CS", "DS"] 515 | self.reg_ids = {} 516 | for i, reg in enumerate(self.reg_names): 517 | self.reg_ids[reg] = i 518 | 519 | self.reg_first_sreg = self.reg_code_sreg = self.reg_ids["CS"] 520 | self.reg_last_sreg = self.reg_data_sreg = self.reg_ids["DS"] 521 | return 522 | 523 | 524 | 525 | # 526 | # Analysis and decoding functions 527 | # 528 | 529 | def _ana(self, insn): 530 | dbg("_ana at 0x%x" % insn.ea) 531 | opcode = insn.get_next_byte() 532 | 533 | if not opcode in self.insns: 534 | raise DecodingError("Unknown opcode 0x%x at offset 0x%x" % (opcode, insn.ea)) 535 | 536 | wi = self.insns[opcode] 537 | 538 | insn.itype = self.inames[wi.name] 539 | insn.size = 1 540 | 541 | dbg("creating insn %s (type=%d, size=%d, ea=%x, ip=%x)" % (wi.name, insn.itype, insn.size, insn.ea, insn.ip)) 542 | 543 | if wi.args: 544 | 545 | for i, arg_t in enumerate(wi.args): 546 | op = insn.ops[i] 547 | 548 | if arg_t is varuint32: 549 | raw_bytes = get_next_bytes(insn, 4) 550 | arg = varuint32(raw_bytes) 551 | op.type = o_imm 552 | op.value = arg.value 553 | op.flags = OF_SHOW 554 | op.specval |= FL_SIGNED 555 | op.addr = insn.ea + insn.size 556 | insn.size += arg.size 557 | dbg("adding VARUINT32 operand (value=%d, size=%d, raw=%s)" % (arg.value, arg.size, repr(raw_bytes))) 558 | continue 559 | 560 | if arg_t is block_type: 561 | raw_bytes = get_next_bytes(insn, 4) 562 | b = block_type(raw_bytes) 563 | op.type = o_imm 564 | op.value = b.value 565 | op.flags = OF_SHOW 566 | op.specval |= FL_SIGNED 567 | op.addr = insn.ea + insn.size 568 | insn.size += b.size 569 | dbg("adding BLOCK_TYPE operand (value=%d, size=%d, raw=%s)" % (b.value, b.size, repr(raw_bytes))) 570 | continue 571 | 572 | if arg_t is memory_immediate: 573 | raw_bytes = get_next_bytes(insn, 8) 574 | mi = memory_immediate(raw_bytes) 575 | op.type = o_imm 576 | op.value = mi.flags 577 | op.flags = OF_SHOW 578 | op.specval |= FL_SIGNED 579 | op.addr = insn.ea + insn.size 580 | insn.size += mi.size 581 | dbg("adding MEMORY_IMMEDIATE operand (value=%d, size=%d, raw=%s)" % (mi.value, mi.size, repr(raw_bytes))) 582 | continue 583 | 584 | # default 585 | op.type = o_void 586 | op.flags = 0 587 | 588 | dbg("opcode %x -> %s, size=%d" % (wi.opcode, wi.name, insn.size)) 589 | return insn.size 590 | 591 | 592 | def PROCESSOR_ENTRY(): 593 | return wasm_processor_t() 594 | -------------------------------------------------------------------------------- /Tools/Kaitai-Wasm/Makefile: -------------------------------------------------------------------------------- 1 | EMCC = emcc 2 | 3 | .PHONY: all clean 4 | 5 | %.html: %.c 6 | $(EMCC) -O0 $^ -s WASM=1 -o $@ 7 | 8 | %.py: %.ksy 9 | kaitai-struct-compiler -t python $^ 10 | 11 | %.js: %.ksy 12 | kaitai-struct-compiler -t javascript $^ 13 | 14 | all: webassembly.py 15 | make -C tests all 16 | 17 | clean: 18 | rm -fr -- __pycache__ *.pyc webassembly.py vlq_base128_le.py 19 | 20 | test: webassembly.py tests/hello.html 21 | ./wasm-disassembler.py tests/hello.wasm 22 | -------------------------------------------------------------------------------- /Tools/Kaitai-Wasm/requirements.txt: -------------------------------------------------------------------------------- 1 | hexdump 2 | kaitaistruct 3 | -------------------------------------------------------------------------------- /Tools/Kaitai-Wasm/tests/hello.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophoslabs/WebAssembly/8ac3c7183b860599573622aceb207b94de7640f3/Tools/Kaitai-Wasm/tests/hello.wasm -------------------------------------------------------------------------------- /Tools/Kaitai-Wasm/vlq_base128_le.ksy: -------------------------------------------------------------------------------- 1 | # -*- mode: yaml -*- 2 | meta: 3 | id: vlq_base128_le 4 | title: Variable length quantity, unsigned integer, base128, little-endian 5 | license: CC0-1.0 6 | ks-version: 0.7 7 | doc: | 8 | A variable-length unsigned integer using base128 encoding. 1-byte groups 9 | consists of 1-bit flag of continuation and 7-bit value, and are ordered 10 | least significant group first, i.e. in little-endian manner 11 | (https://github.com/kaitai-io/kaitai_struct_formats/blob/master/common/vlq_base128_le.ksy) 12 | 13 | seq: 14 | - id: groups 15 | type: group 16 | repeat: until 17 | repeat-until: not _.has_next 18 | types: 19 | group: 20 | doc: | 21 | One byte group, clearly divided into 7-bit "value" and 1-bit "has continuation 22 | in the next byte" flag. 23 | seq: 24 | - id: b 25 | type: u1 26 | instances: 27 | has_next: 28 | value: (b & 0b1000_0000) != 0 29 | doc: If true, then we have more bytes to read 30 | value: 31 | value: b & 0b0111_1111 32 | doc: The 7-bit (base128) numeric value of this group 33 | instances: 34 | len: 35 | value: groups.size 36 | value: 37 | value: >- 38 | groups[0].value 39 | + (len >= 2 ? (groups[1].value << 7) : 0) 40 | + (len >= 3 ? (groups[2].value << 14) : 0) 41 | + (len >= 4 ? (groups[3].value << 21) : 0) 42 | + (len >= 5 ? (groups[4].value << 28) : 0) 43 | + (len >= 6 ? (groups[5].value << 35) : 0) 44 | + (len >= 7 ? (groups[6].value << 42) : 0) 45 | + (len >= 8 ? (groups[7].value << 49) : 0) 46 | doc: Resulting value as normal integer 47 | -------------------------------------------------------------------------------- /Tools/Kaitai-Wasm/wasm-disassembler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- mode: python -*- 3 | # -*- coding: utf-8 -*- 4 | 5 | 6 | __author__ = "Christophe Alladoum" 7 | __version__ = "0.1" 8 | __licence__ = "WTFPL v.2" 9 | __file__ = "wasm-disassembler.py" 10 | __desc__ = """WebAssembly file disassembler, based on Kaitai.io structure parser.""" 11 | __usage__ = """ 12 | {3} version {0}, {1} 13 | by {2} 14 | syntax: {3} [options] args 15 | """.format(__version__, __licence__, __author__, __file__) 16 | 17 | 18 | import sys, os, argparse, struct, binascii 19 | 20 | # katai-generated modules 21 | try: 22 | from kaitaistruct import KaitaiStream, BytesIO 23 | except ImportError: 24 | print("[-] Missing kaitai.io module") 25 | print("[-] Did you install: python -m pip install kaitaistruct") 26 | sys.exit(1) 27 | 28 | try: 29 | import webassembly, vlq_base128_le 30 | except ImportError: 31 | print("[-] Missing Webassembly module") 32 | print("[-] Did you run: ksc -t python webassembly.ksy") 33 | sys.exit(1) 34 | 35 | # external pip modules 36 | import hexdump 37 | 38 | verbose = False 39 | 40 | class WasmInstruction: 41 | mnemonic = None 42 | operands = [] 43 | length = 0 44 | raw = bytearray() 45 | 46 | def __init__(self, data): 47 | opcode = data[0] 48 | if not opcode in opcodes: 49 | raise Exception("Invalid opcode {:02x}".format(opcode)) 50 | 51 | self.mnemonic, nb_arg, arg_funcs = opcodes[opcode] 52 | 53 | length = 0 54 | args = [] 55 | 56 | if nb_arg > 0: 57 | 58 | if self.mnemonic == "br_table": 59 | length, args = branch_table(data[1:]) 60 | 61 | else: 62 | for i in range(nb_arg): 63 | func = arg_funcs[i] 64 | l, v = func(data[1+length:]) 65 | length += l 66 | args.append("%#x" % v) 67 | 68 | self.operands = args 69 | self.length = 1 + length 70 | self.raw = data[0 : self.length] 71 | return 72 | 73 | def __str__(self): 74 | return "{} {}".format(self.mnemonic, ','.join(self.operands)) 75 | 76 | @property 77 | def hexdump(self): 78 | return " ".join(["{:02x}".format(_) for _ in self.raw]) 79 | 80 | 81 | def varint(i): 82 | io = KaitaiStream(BytesIO(i)) 83 | res = vlq_base128_le.VlqBase128Le(io) 84 | return res.len, res.value 85 | 86 | def u8(i): 87 | return 1, struct.unpack(" 0 48 | - id: return_count 49 | type: u1 50 | - id: return_type 51 | type: u1 52 | enum: value_type 53 | if: return_count==1 54 | 55 | resizable_limits_type: 56 | seq: 57 | - id: flags 58 | type: u1 59 | - id: initial 60 | type: vlq_base128_le 61 | - id: maximum 62 | type: vlq_base128_le 63 | if: flags == 1 64 | 65 | table_type: 66 | seq: 67 | - id: element_type 68 | type: u1 69 | enum: elem_type 70 | - id: limits 71 | type: resizable_limits_type 72 | 73 | memory_type: 74 | seq: 75 | - id: limits 76 | type: resizable_limits_type 77 | 78 | global_type: 79 | seq: 80 | - id: content_type 81 | type: u1 82 | enum: value_type 83 | - id: mutability 84 | type: u1 85 | enum: mutability_flag 86 | 87 | global_variable_type: 88 | seq: 89 | - id: type 90 | type: global_type 91 | - id: init 92 | type: u1 93 | repeat: until 94 | repeat-until: _ == 0x0b 95 | 96 | export_entry_type: 97 | seq: 98 | - id: field_len 99 | type: vlq_base128_le 100 | - id: field_str 101 | type: str 102 | encoding: UTF-8 103 | size: field_len.value 104 | - id: kind 105 | type: u1 106 | enum: kind_type 107 | - id: index 108 | type: vlq_base128_le 109 | 110 | elem_segment_type: 111 | seq: 112 | - id: index 113 | type: vlq_base128_le 114 | - id: offset 115 | type: u1 116 | repeat: until 117 | repeat-until: _ == 0x0b 118 | - id: num_elem 119 | type: vlq_base128_le 120 | - id: elems 121 | type: vlq_base128_le 122 | repeat: expr 123 | repeat-expr: num_elem.value 124 | 125 | function_body_type: 126 | seq: 127 | - id: body_size 128 | type: vlq_base128_le 129 | - id: data 130 | type: function_body_data_type 131 | size: body_size.value 132 | 133 | function_body_data_type: 134 | seq: 135 | - id: local_count 136 | type: vlq_base128_le 137 | - id: locals 138 | type: local_entry_type 139 | repeat: expr 140 | repeat-expr: local_count.value 141 | - id: code 142 | size-eos: true 143 | 144 | local_entry_type: 145 | seq: 146 | - id: count 147 | type: vlq_base128_le 148 | - id: type 149 | type: u1 150 | enum: value_type 151 | 152 | data_segment_type: 153 | seq: 154 | - id: index 155 | type: vlq_base128_le 156 | - id: offset 157 | type: u1 158 | repeat: until 159 | repeat-until: _ == 0x0b 160 | - id: size 161 | type: vlq_base128_le 162 | - id: data 163 | type: u1 164 | repeat: expr 165 | repeat-expr: size.value 166 | 167 | section_header: 168 | seq: 169 | - id: id 170 | type: u1 171 | enum: payload_type 172 | - id: payload_len 173 | type: vlq_base128_le 174 | - id: name_len 175 | type: u4 176 | if: id == payload_type::custom_payload 177 | - id: name 178 | size: name_len 179 | if: id == payload_type::custom_payload 180 | 181 | section: 182 | seq: 183 | - id: header 184 | type: section_header 185 | 186 | - id: payload_data 187 | type: 188 | switch-on: header.id 189 | cases: 190 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#high-level-structure 191 | 'payload_type::custom_payload': unimplemented_section 192 | 'payload_type::type_payload': type_section 193 | 'payload_type::import_payload': import_section 194 | 'payload_type::function_payload': function_section 195 | 'payload_type::table_payload': table_section 196 | 'payload_type::memory_payload': memory_section 197 | 'payload_type::global_payload': global_section 198 | 'payload_type::export_payload': export_section 199 | 'payload_type::start_payload': start_section 200 | 'payload_type::element_payload': element_section 201 | 'payload_type::code_payload': code_section 202 | 'payload_type::data_payload': data_section 203 | 204 | 205 | sections: 206 | seq: 207 | - id: sections 208 | type: section 209 | repeat: eos 210 | 211 | type_section: 212 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#type-section 213 | seq: 214 | - id: count 215 | type: u1 216 | - id: entries 217 | type: func_type 218 | repeat: expr 219 | repeat-expr: count 220 | 221 | import_section: 222 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#import-section 223 | seq: 224 | - id: count 225 | type: u1 226 | - id: entries 227 | type: import_entry 228 | if: count > 0 229 | repeat: expr 230 | repeat-expr: count 231 | 232 | import_entry: 233 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#import-entry 234 | seq: 235 | - id: module_len 236 | type: vlq_base128_le 237 | - id: module_str 238 | type: str 239 | size: module_len.value 240 | encoding: UTF-8 241 | - id: field_len 242 | type: vlq_base128_le 243 | - id: field_str 244 | type: str 245 | size: field_len.value 246 | encoding: UTF-8 247 | - id: kind 248 | type: u1 249 | enum: kind_type 250 | - id: type 251 | type: 252 | switch-on: kind 253 | cases: 254 | 'kind_type::function_kind': vlq_base128_le 255 | 'kind_type::table_kind': table_type 256 | 'kind_type::memory_kind': memory_type 257 | 'kind_type::global_kind': global_type 258 | 259 | function_section: 260 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#function-section 261 | seq: 262 | - id: count 263 | type: vlq_base128_le 264 | - id: types 265 | type: vlq_base128_le 266 | repeat: expr 267 | repeat-expr: count.value 268 | 269 | table_section: 270 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#table-section 271 | seq: 272 | - id: count 273 | type: vlq_base128_le 274 | - id: entries 275 | type: table_type 276 | repeat: expr 277 | repeat-expr: count.value 278 | 279 | memory_section: 280 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#memory-section 281 | seq: 282 | - id: count 283 | type: vlq_base128_le 284 | - id: entries 285 | type: memory_type 286 | repeat: expr 287 | repeat-expr: count.value 288 | 289 | global_section: 290 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#global-section 291 | seq: 292 | - id: count 293 | type: vlq_base128_le 294 | - id: globals 295 | type: global_variable_type 296 | repeat: expr 297 | repeat-expr: count.value 298 | 299 | export_section: 300 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#export-section 301 | seq: 302 | - id: count 303 | type: vlq_base128_le 304 | - id: entries 305 | type: export_entry_type 306 | repeat: expr 307 | repeat-expr: count.value 308 | 309 | start_section: 310 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#start-section 311 | seq: 312 | - id: index 313 | type: vlq_base128_le 314 | 315 | element_section: 316 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#element-section 317 | seq: 318 | - id: count 319 | type: vlq_base128_le 320 | - id: entries 321 | type: elem_segment_type 322 | repeat: expr 323 | repeat-expr: count.value 324 | 325 | code_section: 326 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#code-section 327 | seq: 328 | - id: count 329 | type: vlq_base128_le 330 | - id: bodies 331 | type: function_body_type 332 | repeat: expr 333 | repeat-expr: count.value 334 | 335 | data_section: 336 | # https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#data-section 337 | seq: 338 | - id: count 339 | type: vlq_base128_le 340 | - id: entries 341 | type: data_segment_type 342 | repeat: expr 343 | repeat-expr: count.value 344 | 345 | unimplemented_section: 346 | seq: 347 | - id: raw 348 | type: u1 349 | repeat: expr 350 | repeat-expr: _parent.header.payload_len.value 351 | 352 | ##################################################################################################### 353 | 354 | enums: 355 | 356 | constructor_type: 357 | 0x7f: i32 358 | 0x7e: i64 359 | 0x7d: f32 360 | 0x7c: f64 361 | 0x70: anyfunc 362 | 0x60: func 363 | 0x40: empty_block 364 | 365 | value_type: 366 | 0x7f: i32 367 | 0x7e: i64 368 | 0x7d: f32 369 | 0x7c: f64 370 | 371 | kind_type: 372 | 0: function_kind 373 | 1: table_kind 374 | 2: memory_kind 375 | 3: global_kind 376 | 377 | payload_type: 378 | 0: custom_payload 379 | 1: type_payload 380 | 2: import_payload 381 | 3: function_payload 382 | 4: table_payload 383 | 5: memory_payload 384 | 6: global_payload 385 | 7: export_payload 386 | 8: start_payload 387 | 9: element_payload 388 | 10: code_payload 389 | 11: data_payload 390 | 391 | elem_type: 392 | 0x70: anyfunc 393 | 394 | mutability_flag: 395 | 0: immutable 396 | 1: mutable 397 | -------------------------------------------------------------------------------- /Tools/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly parser for Kaitai.io # 2 | 3 | 4 | ## Requirements ## 5 | 6 | * `emcc` from [EmScripten compiler suite](https://github.com/kripken/emscripten). Build instructions can be 7 | found [here](http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html) 8 | * [`kaitai-struct`](http://kaitai.io/) and its Python module 9 | 10 | ``` bash 11 | # for debian-based Linux systems 12 | $ sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv 379CE192D401AB61 13 | $ echo "deb https://dl.bintray.com/kaitai-io/debian jessie main" | sudo tee /etc/apt/sources.list.d/kaitai.list 14 | $ sudo apt update && sudo apt install kaitai-struct-compiler 15 | $ pip3 install --user -r ./requirements.txt 16 | ``` 17 | 18 | 19 | ## Tests ## 20 | 21 | `make test` will compile everything and disassemble a test WASM compiled "print 22 | (Hello World)" file. 23 | 24 | ``` bash 25 | $ make test 26 | kaitai-struct-compiler -t python webassembly.ksy 27 | emcc tests/hello.c -s WASM=1 -o tests/hello.html 28 | ./wasm-disassembler.py tests/hello.wasm 29 | [+] sub_0000 { 30 | 00000000 23 0c get_global 0xc 31 | 00000002 21 01 set_local 0x1 32 | 00000004 23 0c get_global 0xc 33 | 00000006 20 00 get_local 0x0 34 | 00000008 6a i32.add 35 | 00000009 24 0c set_global 0xc 36 | 0000000b 23 0c get_global 0xc 37 | 0000000d 41 0f i32.const 0xf 38 | 0000000f 6a i32.add 39 | } 40 | [...] 41 | ``` 42 | --------------------------------------------------------------------------------