wasm-tob


Namewasm-tob JSON
Version 1.0.1 PyPI version JSON
download
home_page
SummaryWebAssembly decoder & disassembler
upload_time2023-04-05 22:33:25
maintainer
docs_urlNone
author
requires_python>=3.7
license
keywords wasm disassembler decoder
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # wasm-tob

Python module capable of decoding and disassembling WebAssembly modules
and bytecode, according to the MVP specification of the WASM binary
format.

As there is no official text format defined yet, the text format
implemented doesn't correspond to any existing definition and is a
simple `mnemonic op1, op2, ...` format. Functions are formatted in a
way similar to how Google Chrome does in the debug console.

## ❗ Important

This is a fork of the original project that the author was no longer able to
spend time on: https://github.com/athre0z/wasm. The changes made here are
primarily to support the
[Manticore](https://github.com/trailofbits/manticore) project.

New issues and pull requests will be reviewed on a best-effort basis. Please
open an issue first if you think fixing the problem will be complex; this is so
we can evaluate whether a fix or feature is in scope before comitting time to
review. When opening an issue, please include information on how to reproduce
what you are seeing. If you feel comfortable, please submit a well-crafted,
minimal pull request that we can review.

## Installation

```sh
# From PyPi
pip install wasm-tob

# From GitHub
pip install git+https://github.com/trail-of-forks/wasm-tob.git
```

## Examples

Parsing a WASM module, printing the types of sections found.

```python
from wasm_tob import decode_module

with open('input-samples/hello/hello.wasm', 'rb') as raw:
    raw = raw.read()

mod_iter = iter(decode_module(raw))
header, header_data = next(mod_iter)

for cur_sec, cur_sec_data in mod_iter:
    print(cur_sec_data.get_decoder_meta()['types']['payload'])
```

Possible output:

```text
<wasm_tob.modtypes.TypeSection object at 0x108249b90>
<wasm_tob.modtypes.ImportSection object at 0x108249bd0>
<wasm_tob.modtypes.FunctionSection object at 0x108249c10>
<wasm_tob.modtypes.GlobalSection object at 0x108249cd0>
<wasm_tob.modtypes.ExportSection object at 0x108249d10>
<wasm_tob.modtypes.ElementSection object at 0x108249d90>
<wasm_tob.modtypes.CodeSection object at 0x108249dd0>
<wasm_tob.modtypes.DataSection object at 0x108249e10>
<wasm_tob.types.BytesField object at 0x108249b10>
```

Parsing specific sections (eg. GlobalSection, ElementSection, DataSection) in WASM module, printing each section's content:

```python
from wasm_tob import (
    decode_module,
    format_instruction,
    format_lang_type,
    format_mutability,
    SEC_DATA,
    SEC_ELEMENT,
    SEC_GLOBAL,
)

with open('input-samples/hello/hello.wasm', 'rb') as raw:
    raw = raw.read()

mod_iter = iter(decode_module(raw))
header, header_data = next(mod_iter)

for cur_sec, cur_sec_data in mod_iter:
    if cur_sec_data.id == SEC_GLOBAL:
        print("GlobalSection:")
        for idx, entry in enumerate(cur_sec_data.payload.globals):
            print(
                format_mutability(entry.type.mutability),
                format_lang_type(entry.type.content_type),
            )

            for cur_insn in entry.init:
                print(format_instruction(cur_insn))

    if cur_sec_data.id == SEC_ELEMENT:
        print("ElementSection:")
        for idx, entry in enumerate(cur_sec_data.payload.entries):
            print(entry.index, entry.num_elem, entry.elems)
            for cur_insn in entry.offset:
                print(format_instruction(cur_insn))

    if cur_sec_data.id == SEC_DATA:
        print("DataSection:")
        for idx, entry in enumerate(cur_sec_data.payload.entries):
            print(entry.index, entry.size, entry.data.tobytes())
            for cur_insn in entry.offset:
                print(format_instruction(cur_insn))
```

Output:

```text
GlobalSection:
mut i32
get_global 0
end
mut i32
get_global 1
end
[...]
mut f32
f32.const 0x0
end
mut f32
f32.const 0x0
end
ElementSection:
0 12576 [856, 856, 856, [...], 888]
i32.const 0
end
DataSection:
0 16256 b'\x98&\x00\x00\xfe4\x00\x00\x10\x04\x00\x00\x00...\x00N10__cxxabiv121__vmi_class_type_infoE'
get_global 8
end

```

Manually disassemble WASM bytecode, printing each instruction.

```python
from wasm_tob import (
    decode_bytecode,
    format_instruction,
    INSN_ENTER_BLOCK,
    INSN_LEAVE_BLOCK,
)

raw = bytearray([2, 127, 65, 24, 16, 28, 65, 0, 15, 11])
indent = 0
for cur_insn in decode_bytecode(raw):
    if cur_insn.op.flags & INSN_LEAVE_BLOCK:
        indent -= 1
    print('  ' * indent + format_instruction(cur_insn))
    if cur_insn.op.flags & INSN_ENTER_BLOCK:
        indent += 1
```

Output:

```text
block -1
  i32.const 24
  call 28
  i32.const 0
  return
end
```

## `wasmdump` command-line tool

The module also comes with a simple command-line tool called `wasmdump`,
dumping all module struct in tree format. Optionally, it also
disassembles all functions found when invoked with `--disas` (slow).

## Version support

This project aims to support all Python releases that are still actively
supported and maintained. If you encounter issues with a particular Python
version, please open an issue.


            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "wasm-tob",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "wasm,disassembler,decoder",
    "author": "",
    "author_email": "Trail of Bits <opensource@trailofbits.com>",
    "download_url": "https://files.pythonhosted.org/packages/7b/73/fe4593d7193fbe93cacfe8be17a7d87accd794f3d1c8e79e5a4b1b2117a2/wasm-tob-1.0.1.tar.gz",
    "platform": null,
    "description": "# wasm-tob\n\nPython module capable of decoding and disassembling WebAssembly modules\nand bytecode, according to the MVP specification of the WASM binary\nformat.\n\nAs there is no official text format defined yet, the text format\nimplemented doesn't correspond to any existing definition and is a\nsimple `mnemonic op1, op2, ...` format. Functions are formatted in a\nway similar to how Google Chrome does in the debug console.\n\n## \u2757 Important\n\nThis is a fork of the original project that the author was no longer able to\nspend time on: https://github.com/athre0z/wasm. The changes made here are\nprimarily to support the\n[Manticore](https://github.com/trailofbits/manticore) project.\n\nNew issues and pull requests will be reviewed on a best-effort basis. Please\nopen an issue first if you think fixing the problem will be complex; this is so\nwe can evaluate whether a fix or feature is in scope before comitting time to\nreview. When opening an issue, please include information on how to reproduce\nwhat you are seeing. If you feel comfortable, please submit a well-crafted,\nminimal pull request that we can review.\n\n## Installation\n\n```sh\n# From PyPi\npip install wasm-tob\n\n# From GitHub\npip install git+https://github.com/trail-of-forks/wasm-tob.git\n```\n\n## Examples\n\nParsing a WASM module, printing the types of sections found.\n\n```python\nfrom wasm_tob import decode_module\n\nwith open('input-samples/hello/hello.wasm', 'rb') as raw:\n    raw = raw.read()\n\nmod_iter = iter(decode_module(raw))\nheader, header_data = next(mod_iter)\n\nfor cur_sec, cur_sec_data in mod_iter:\n    print(cur_sec_data.get_decoder_meta()['types']['payload'])\n```\n\nPossible output:\n\n```text\n<wasm_tob.modtypes.TypeSection object at 0x108249b90>\n<wasm_tob.modtypes.ImportSection object at 0x108249bd0>\n<wasm_tob.modtypes.FunctionSection object at 0x108249c10>\n<wasm_tob.modtypes.GlobalSection object at 0x108249cd0>\n<wasm_tob.modtypes.ExportSection object at 0x108249d10>\n<wasm_tob.modtypes.ElementSection object at 0x108249d90>\n<wasm_tob.modtypes.CodeSection object at 0x108249dd0>\n<wasm_tob.modtypes.DataSection object at 0x108249e10>\n<wasm_tob.types.BytesField object at 0x108249b10>\n```\n\nParsing specific sections (eg. GlobalSection, ElementSection, DataSection) in WASM module, printing each section's content:\n\n```python\nfrom wasm_tob import (\n    decode_module,\n    format_instruction,\n    format_lang_type,\n    format_mutability,\n    SEC_DATA,\n    SEC_ELEMENT,\n    SEC_GLOBAL,\n)\n\nwith open('input-samples/hello/hello.wasm', 'rb') as raw:\n    raw = raw.read()\n\nmod_iter = iter(decode_module(raw))\nheader, header_data = next(mod_iter)\n\nfor cur_sec, cur_sec_data in mod_iter:\n    if cur_sec_data.id == SEC_GLOBAL:\n        print(\"GlobalSection:\")\n        for idx, entry in enumerate(cur_sec_data.payload.globals):\n            print(\n                format_mutability(entry.type.mutability),\n                format_lang_type(entry.type.content_type),\n            )\n\n            for cur_insn in entry.init:\n                print(format_instruction(cur_insn))\n\n    if cur_sec_data.id == SEC_ELEMENT:\n        print(\"ElementSection:\")\n        for idx, entry in enumerate(cur_sec_data.payload.entries):\n            print(entry.index, entry.num_elem, entry.elems)\n            for cur_insn in entry.offset:\n                print(format_instruction(cur_insn))\n\n    if cur_sec_data.id == SEC_DATA:\n        print(\"DataSection:\")\n        for idx, entry in enumerate(cur_sec_data.payload.entries):\n            print(entry.index, entry.size, entry.data.tobytes())\n            for cur_insn in entry.offset:\n                print(format_instruction(cur_insn))\n```\n\nOutput:\n\n```text\nGlobalSection:\nmut i32\nget_global 0\nend\nmut i32\nget_global 1\nend\n[...]\nmut f32\nf32.const 0x0\nend\nmut f32\nf32.const 0x0\nend\nElementSection:\n0 12576 [856, 856, 856, [...], 888]\ni32.const 0\nend\nDataSection:\n0 16256 b'\\x98&\\x00\\x00\\xfe4\\x00\\x00\\x10\\x04\\x00\\x00\\x00...\\x00N10__cxxabiv121__vmi_class_type_infoE'\nget_global 8\nend\n\n```\n\nManually disassemble WASM bytecode, printing each instruction.\n\n```python\nfrom wasm_tob import (\n    decode_bytecode,\n    format_instruction,\n    INSN_ENTER_BLOCK,\n    INSN_LEAVE_BLOCK,\n)\n\nraw = bytearray([2, 127, 65, 24, 16, 28, 65, 0, 15, 11])\nindent = 0\nfor cur_insn in decode_bytecode(raw):\n    if cur_insn.op.flags & INSN_LEAVE_BLOCK:\n        indent -= 1\n    print('  ' * indent + format_instruction(cur_insn))\n    if cur_insn.op.flags & INSN_ENTER_BLOCK:\n        indent += 1\n```\n\nOutput:\n\n```text\nblock -1\n  i32.const 24\n  call 28\n  i32.const 0\n  return\nend\n```\n\n## `wasmdump` command-line tool\n\nThe module also comes with a simple command-line tool called `wasmdump`,\ndumping all module struct in tree format. Optionally, it also\ndisassembles all functions found when invoked with `--disas` (slow).\n\n## Version support\n\nThis project aims to support all Python releases that are still actively\nsupported and maintained. If you encounter issues with a particular Python\nversion, please open an issue.\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "WebAssembly decoder & disassembler",
    "version": "1.0.1",
    "project_urls": {
        "Homepage": "https://pypi.org/project/wasm-tob/",
        "Issues": "https://github.com/trail-of-forks/wasm-tob/issues",
        "Source": "https://github.com/trail-of-forks/wasm-tob"
    },
    "split_keywords": [
        "wasm",
        "disassembler",
        "decoder"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "742cf8f5bcc5939063e15061dfaa59491ee480b1c4a1aac30c75e6235428528d",
                "md5": "b10e4b3fc5d1a3fad5d65af7a396470b",
                "sha256": "43964558326a943f7291615650b54da2a964a80029c8c952e49011901c89405a"
            },
            "downloads": -1,
            "filename": "wasm_tob-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b10e4b3fc5d1a3fad5d65af7a396470b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 17315,
            "upload_time": "2023-04-05T22:33:23",
            "upload_time_iso_8601": "2023-04-05T22:33:23.683518Z",
            "url": "https://files.pythonhosted.org/packages/74/2c/f8f5bcc5939063e15061dfaa59491ee480b1c4a1aac30c75e6235428528d/wasm_tob-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7b73fe4593d7193fbe93cacfe8be17a7d87accd794f3d1c8e79e5a4b1b2117a2",
                "md5": "5baac6661c02973087230e59e66235e7",
                "sha256": "0f78c55c619ab9e459b3dcf00f8aa267053be7b957e1a3ea89747f2dd97c2b16"
            },
            "downloads": -1,
            "filename": "wasm-tob-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "5baac6661c02973087230e59e66235e7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 15677,
            "upload_time": "2023-04-05T22:33:25",
            "upload_time_iso_8601": "2023-04-05T22:33:25.420037Z",
            "url": "https://files.pythonhosted.org/packages/7b/73/fe4593d7193fbe93cacfe8be17a7d87accd794f3d1c8e79e5a4b1b2117a2/wasm-tob-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-04-05 22:33:25",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "trail-of-forks",
    "github_project": "wasm-tob",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "wasm-tob"
}
        
Elapsed time: 0.06901s