From 4c92103ad3ffc07f5b09b9b4faf0ee0d2b4b6e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Ku=C4=8Dera?= Date: Fri, 13 Sep 2024 14:09:46 +0200 Subject: [PATCH] feat: disassembly --- README.md | 2 +- dist/index.js | 13 ++++++++++--- dist/worker.js | 36 ++++++++++++++++++++++++++++++------ package.json | 4 ++-- src/index.ts | 12 ++++++++++-- src/worker.ts | 44 +++++++++++++++++++++++++++++++++++++------- 6 files changed, 90 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 4575a72..3de8ded 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # script-krak -A slicer script binding for the Krakatau Java decompiler. +A slicer script binding for the Krakatau Java decompiler and disassembler. diff --git a/dist/index.js b/dist/index.js index ab2e127..ff468bb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -350,17 +350,24 @@ const krak = { id: "krak", label: "Krakatau", language: "java", - run: worker.run, + run: worker.decompile, +}; +const krakAsm = { + id: "krak-asm", + label: "Krakatau (ASM)", + run: worker.disassemble, }; var index = { name: "krak", - description: "A script binding for the Krakatau Java decompiler.", - version: "1.1.1", + description: "A script binding for the Krakatau Java decompiler and disassembler.", + version: "1.2.0", load(context) { context.disasm.add(krak); + context.disasm.add(krakAsm); }, unload(context) { context.disasm.remove(krak.id); + context.disasm.remove(krakAsm.id); }, }; diff --git a/dist/worker.js b/dist/worker.js index cbec628..5c81080 100644 --- a/dist/worker.js +++ b/dist/worker.js @@ -336,9 +336,11 @@ function generateUUID() { } const krakScript = `from pyodide.http import pyfetch -response = await pyfetch("https://cdn.jsdelivr.net/gh/run-slicer/script-krak@${"1.1.1"}/dist/krak.zip") +response = await pyfetch("https://cdn.jsdelivr.net/gh/run-slicer/script-krak@${"1.2.0"}/dist/krak.zip") await response.unpack_archive() +from io import StringIO + from Krakatau.java.visitor import DefaultVisitor from Krakatau.java.javaclass import generateAST from Krakatau.ssa import ssaFromVerified @@ -347,6 +349,8 @@ from Krakatau.java.stringescape import escapeString from Krakatau.environment import Environment from Krakatau.classfile import ClassFile from Krakatau.classfileformat.reader import Reader +from Krakatau.classfileformat.classdata import ClassData +from Krakatau.assembler.disassembly import Disassembler def makeGraph(m): v = verifyBytecode(m.code) @@ -389,15 +393,35 @@ def decompile(data): return source -decompile`; +def disassemble(data): + c = ClassData(Reader(data=bytes(data.to_py()))) + + output = StringIO() + Disassembler(c, output.write, roundtrip=False).disassemble() + + return output.getvalue()`; let decompileFunc = null; +let disassembleFunc = null; +const loadFuncs = async () => { + await import('https://cdn.jsdelivr.net/pyodide/v0.26.2/full/pyodide.mjs') + .then(({ loadPyodide }) => loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.26.2/full/" })) + .then(async ({ runPythonAsync, globals }) => { + await runPythonAsync(krakScript); + decompileFunc = globals.get("decompile"); + disassembleFunc = globals.get("disassemble"); + }); +}; expose({ - async run(data) { + async decompile(data) { if (!decompileFunc) { - decompileFunc = await import('https://cdn.jsdelivr.net/pyodide/v0.26.2/full/pyodide.mjs') - .then(({ loadPyodide }) => loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.26.2/full/" })) - .then(({ runPythonAsync }) => runPythonAsync(krakScript)); + await loadFuncs(); } return decompileFunc(data); }, + async disassemble(data) { + if (!disassembleFunc) { + await loadFuncs(); + } + return disassembleFunc(data); + }, }); diff --git a/package.json b/package.json index 000d3f4..14ad3c7 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "script-krak", - "version": "1.1.1", + "version": "1.2.0", "type": "module", "author": "run-slicer", "license": "GPL-3.0-only", - "description": "A slicer script binding for the Krakatau Java decompiler.", + "description": "A slicer script binding for the Krakatau Java decompiler and disassembler.", "scripts": { "prepare": "mkdir -p dist; cd Krakatau; find Krakatau LICENSE.TXT -name \"*.py\" -o -name \"LICENSE.TXT\" | zip -FS -@ ../dist/krak.zip", "build": "rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript", diff --git a/src/index.ts b/src/index.ts index 6c511d9..7282c4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,17 +21,25 @@ const krak: Disassembler = { id: "krak", label: "Krakatau", language: "java", - run: worker.run, + run: worker.decompile, +}; + +const krakAsm: Disassembler = { + id: "krak-asm", + label: "Krakatau (ASM)", + run: worker.disassemble, }; export default { name: "krak", - description: "A script binding for the Krakatau Java decompiler.", + description: "A script binding for the Krakatau Java decompiler and disassembler.", version: __SCRIPT_VERSION__, load(context: ScriptContext): void | Promise { context.disasm.add(krak); + context.disasm.add(krakAsm); }, unload(context: ScriptContext): void | Promise { context.disasm.remove(krak.id); + context.disasm.remove(krakAsm.id); }, } satisfies Script; diff --git a/src/worker.ts b/src/worker.ts index 80ff888..ad9c531 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -1,13 +1,16 @@ import { expose } from "comlink"; export interface Worker { - run(data: Uint8Array): Promise; + decompile(data: Uint8Array): Promise; + disassemble(data: Uint8Array): Promise; } const krakScript = `from pyodide.http import pyfetch response = await pyfetch("https://cdn.jsdelivr.net/gh/run-slicer/script-krak@${__SCRIPT_VERSION__}/dist/krak.zip") await response.unpack_archive() +from io import StringIO + from Krakatau.java.visitor import DefaultVisitor from Krakatau.java.javaclass import generateAST from Krakatau.ssa import ssaFromVerified @@ -16,6 +19,8 @@ from Krakatau.java.stringescape import escapeString from Krakatau.environment import Environment from Krakatau.classfile import ClassFile from Krakatau.classfileformat.reader import Reader +from Krakatau.classfileformat.classdata import ClassData +from Krakatau.assembler.disassembly import Disassembler def makeGraph(m): v = verifyBytecode(m.code) @@ -58,18 +63,43 @@ def decompile(data): return source -decompile`; +def disassemble(data): + c = ClassData(Reader(data=bytes(data.to_py()))) + + output = StringIO() + Disassembler(c, output.write, roundtrip=False).disassemble() + + return output.getvalue()`; + +type KrakFunc = (data: Uint8Array) => string; + +let decompileFunc: KrakFunc | null = null; +let disassembleFunc: KrakFunc | null = null; -let decompileFunc: ((data: Uint8Array) => string) | null = null; +const loadFuncs = async () => { + await import("https://cdn.jsdelivr.net/pyodide/v0.26.2/full/pyodide.mjs") + .then(({ loadPyodide }) => loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.26.2/full/" })) + .then(async ({ runPythonAsync, globals }) => { + await runPythonAsync(krakScript); + + decompileFunc = globals.get("decompile"); + disassembleFunc = globals.get("disassemble"); + }); +}; expose({ - async run(data: Uint8Array): Promise { + async decompile(data: Uint8Array): Promise { if (!decompileFunc) { - decompileFunc = await import("https://cdn.jsdelivr.net/pyodide/v0.26.2/full/pyodide.mjs") - .then(({ loadPyodide }) => loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.26.2/full/" })) - .then(({ runPythonAsync }) => runPythonAsync(krakScript)); + await loadFuncs(); } return decompileFunc(data); }, + async disassemble(data: Uint8Array): Promise { + if (!disassembleFunc) { + await loadFuncs(); + } + + return disassembleFunc(data); + }, } satisfies Worker);