Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ewasm support #13

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
60ddcf0
Initial ewasm parsing
fergarrui Jan 1, 2020
1514061
Disassemble bytecode
fergarrui Jan 2, 2020
06335e3
Parse import section
fergarrui Jan 2, 2020
dbe758f
bytecode post processing
fergarrui Jan 3, 2020
ff0aaf5
module callgraph
fergarrui Jan 4, 2020
7ecdb5a
Added call_indirect to call graph
fergarrui Jan 4, 2020
56f13aa
Fixed br_table bug - global section placeholder
fergarrui Jan 5, 2020
20185ce
Starting CFG
fergarrui Jan 5, 2020
09610c4
Fix FE
fergarrui Jan 5, 2020
71ddfc6
CFG with loop and bugfix
fergarrui Jan 5, 2020
18fb3fa
create analyzer component
Swolfeyes Jan 5, 2020
7e151d5
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
Swolfeyes Jan 5, 2020
9f6ee5d
Added if else to CFG
fergarrui Jan 6, 2020
9623cb9
Integrated CFG with controller
fergarrui Jan 6, 2020
98b043c
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
fergarrui Jan 6, 2020
bec4f82
graphs formatting
fergarrui Jan 6, 2020
2c20ee7
graph bug fix
Swolfeyes Jan 6, 2020
58b80e5
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
Swolfeyes Jan 6, 2020
67cfcba
add data to ewasm component
Swolfeyes Jan 12, 2020
1ac1388
added pre
fergarrui Jan 12, 2020
b5d4694
create ewasm graphs
Swolfeyes Jan 12, 2020
0660517
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
Swolfeyes Jan 12, 2020
d17bdf3
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
Swolfeyes Jan 12, 2020
41c1882
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
Swolfeyes Jan 12, 2020
486c50d
fix closing tabs bug
Swolfeyes Jan 12, 2020
8837310
fix graph
fergarrui Jan 12, 2020
02662a2
Merge branch 'features-ewasm' of https://github.com/fergarrui/ethereu…
fergarrui Jan 12, 2020
8e8ff4d
fix graph
fergarrui Jan 13, 2020
fac780c
Added analyze file
fergarrui Jan 13, 2020
7b491a6
wasm readme
fergarrui Jan 13, 2020
435e6ab
readme
fergarrui Jan 13, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ dist/*
coverage/*
.vscode/*
contracts/*
*.txt
*.json
*.cfg
*.viz
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,14 @@ Add contracts to `./contracts` (you will need to create the directory) and empty
* Scan the directory as described above
* You won't get source code mappings when clicking in operations of the CFG

### eWASM / WASM analysis

A `.wasm` file can be analyzed. Check [(e)Wasm Readme](./WASM.md) for more details

# Features

* **Now interactive** :star2:: it has a sepparate frontend and API instead of building a static HTML file like in earlier versions
* Initial **eWASM/WASM** support added
* **Control flow graph**: the CFG can be built without debugging a transaction.
* **Disassembler**: just disassembled opcodes can be seen, from runtime and constructor
* **Source mapping**: snippet of code related to the selected instruction is highlighted in the editor left panel
Expand All @@ -83,3 +88,4 @@ Add contracts to `./contracts` (you will need to create the directory) and empty
* ~~Only runtime debugging is supported for now (no constructor)~~
* You must run it against a node that supports `debug_traceTransaction`, like Geth or Ganache, therefore, Infura is not supported
* It was rewritten, so new bugs may appear
* eWASM/WASM cannot be debugged yet
35 changes: 35 additions & 0 deletions WASM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# (e)WASM

If there are `.wasm` files in the provided path they can be analyzed.
For now debugging is not possible.

The analysis will:
* Parse the WASM binary
* Identify WASM binary sections (for now they are not shown, but there will be a 'Summary' section)
* Functions call graph
* Functions are detected, bytecode is disassembled
* Functions control flow graph
* Some symbols are resolved with exported names if possible to make graphs/bytecode more readable

TODO:

* Analyze a (e)WASM contract address (API ready, FE in progress)
* Show more details about the binary (preloaded memory, elements, etc)

### Function call graph

Example of a function CFG:

![Function CFG](./images/function_cfg.png)

### Function disassembled bytecode

Example of a function bytecode:

![Function Bytecode](./images/function_bytecode.png)

### Wasm module callgraph

Example of a WASM module callgraph

![Module callgraph](./images/callgraph.png)
Binary file added images/callgraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/function_bytecode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/function_cfg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 63 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"bn.js": "^4.11.8",
"body-parser": "^1.18.3",
"brace": "^0.11.1",
"command-exists": "^1.2.8",
"copyfiles": "^2.1.0",
"d3": "^5.7.0",
"d3-graphviz": "^2.6.0",
Expand All @@ -101,7 +102,9 @@
"reflect-metadata": "^0.1.12",
"solc": "^0.5.8",
"terser": "3.14.1",
"tmp": "^0.1.0",
"tsoa": "2.3.81",
"wabt": "^1.0.12",
"web3": "1.0.0-beta.37",
"winston": "^2.2.0"
},
Expand Down Expand Up @@ -135,6 +138,7 @@
"sinon": "^8.0.2",
"style-loader": "^0.23.1",
"ts-jest": "^22.4.6",
"ts-node": "^8.5.4",
"tslint-config-prettier": "^1.14.0",
"typescript": "^3.1.3",
"webpack": "^4.25.1",
Expand Down
4 changes: 2 additions & 2 deletions src/api/bytecode/EVMDisassembler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Disassembler } from './Disassembler'
import { Operation } from './Operation'
import { Opcodes } from './Opcodes'
import { EVMOpcodes } from './EVMOpcodes'
import { injectable, inject } from 'inversify'
import { Opcode } from './Opcode'
import { DisassembledContract } from './DisassembledContract'
Expand Down Expand Up @@ -106,7 +106,7 @@ export class EVMDisassembler implements Disassembler {

for (let i = 0; i < operations.length; i++) {
const code = operations[i]
const opcode: Opcode = Opcodes.opcodes[parseInt(code, 16)] || Opcodes.opcodes[-1]
const opcode: Opcode = EVMOpcodes.opcodes[parseInt(code, 16)] || EVMOpcodes.opcodes[-1]
if (this.isPush(opcode)) {
const parameters = opcode.parameters
const argument = `${operations.slice(i + 1, i + parameters + 1).join('')}`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Opcode } from './Opcode'

export class Opcodes {
export class EVMOpcodes {
static opcodes = {}

static populate() {
Expand Down Expand Up @@ -161,4 +161,4 @@ export class Opcodes {
}
}

Opcodes.populate()
EVMOpcodes.populate()
99 changes: 99 additions & 0 deletions src/api/bytecode/ewasm/BytesReader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Int64 } from "./Int64";

export class BytesReader {

private pointer: number
private buffer: Buffer

constructor(buffer: Buffer) {
this.buffer = buffer
this.pointer = 0
}

readBytes(bytesNumber: number): Buffer {
const result = this.buffer.slice(this.pointer, bytesNumber + this.pointer)
this.pointer += bytesNumber
return result
}

readBytesToHex(bytesNumber: number): string {
const result = this.readBytes(bytesNumber)
return result.toString('hex')
}

readBytesToNumber(bytesNumber: number): number {
const result = this.readBytesToHex(bytesNumber)
return parseInt(result, 16)
}

readBytesToUtf8String(bytesNumber: number): string {
const result = this.readBytes(bytesNumber)
return result.toString('utf8')
}

readVarUint32(): number {
var result = 0
var shift = 0
while (true) {
var byte = parseInt(this.readBytesToHex(1), 16)
result |= (byte & 0x7F) << shift
shift += 7
if ((byte & 0x80) === 0){
break
}
}
return result
}

readVarInt32(): number {
var result = 0
var shift = 0
while (true) {
var byte = parseInt(this.readBytesToHex(1), 16)
result |= (byte & 0x7F) << shift
shift += 7
if ((byte & 0x80) === 0) {
break;
}
}
if (shift >= 32) {
return result
}
var ashift = (32 - shift)
return (result << ashift) >> ashift
}

readVarInt64(): number {
var result = new Uint8Array(8);
var i = 0;
var c = 0;
var shift = 0;
while (true) {
var byte = parseInt(this.readBytesToHex(1), 16)
c |= (byte & 0x7F) << shift;
shift += 7;
if (shift > 8) {
result[i++] = c & 0xFF;
c >>= 8;
shift -= 8;
}
if ((byte & 0x80) === 0)
break;
}
var ashift = (32 - shift);
c = (c << ashift) >> ashift;
while (i < 8) {
result[i++] = c & 0xFF;
c >>= 8;
}
return new Int64(result).toDouble();
}

getPointer(): number {
return this.pointer
}

finished(): boolean {
return this.pointer >= this.buffer.length
}
}
7 changes: 7 additions & 0 deletions src/api/bytecode/ewasm/EWasmModuleResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { WasmBinary } from "./WasmBinary";

export interface EWasmModuleResponse {
binary: WasmBinary
dotCallGraph: string
functionsCfg: string[]
}
7 changes: 7 additions & 0 deletions src/api/bytecode/ewasm/ExportEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { WasmExternalKind } from "./wasmTypes";

export interface ExportEntry {
name: string
kind: WasmExternalKind
index: number
}
26 changes: 26 additions & 0 deletions src/api/bytecode/ewasm/FuncType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { WasmValueType } from "./wasmTypes";

export interface FuncType {
params: WasmValueType[]
results: WasmValueType[]
}

export const printSignature = (index: number, funcType: FuncType): string => {
let signature = `func_${index}(`
signature += funcType.params.map(p => p.toString()).join(',')
signature += ')'
signature += ':'
const results = funcType.results.length > 0 ? funcType.results.map(r => r.toString()).join(',') : 'void'
signature += results
return signature
}

export const printSignatureForGraph = (index: number, funcType: FuncType): string => {
let signature = `type_${index}_params_`
signature += funcType.params.map(p => p.toString()).join('_')
signature += '_'
signature += 'results_'
const results = funcType.results.length > 0 ? funcType.results.map(r => r.toString()).join('_') : 'void'
signature += results
return signature
}
Loading