├── go ├── Makefile └── radare2.yml ├── ruby ├── build.mk ├── Makefile ├── chkruby.rb ├── mkruby.rb ├── ruby.c └── radare.rb ├── csharp ├── Makefile ├── repl │ ├── r2pipe.dll.gz │ ├── Newtonsoft.Json.dll.gz │ ├── r2api │ │ └── README.md │ ├── Makefile │ └── main.cs ├── build.mk └── csharp.c ├── duktape ├── Makefile ├── duk │ ├── duk_console.h │ └── duk_console.c ├── build.mk └── examples │ └── dukasm.js ├── lua ├── Makefile ├── README.md ├── lib │ ├── Makefile │ ├── r2api.lua │ ├── r2api.lua.c │ └── inspect.lua ├── examples │ ├── typescript │ │ ├── index.ts │ │ ├── Makefile │ │ └── package.json │ └── test.lua ├── hello.lua ├── build.mk └── lua.c ├── mujs ├── Makefile ├── example.mujs ├── build.mk ├── plugin.c └── jsapi.c ├── perl ├── Makefile ├── build.mk └── perl.c ├── python ├── Makefile ├── python │ ├── io.h │ ├── arch.h │ ├── asm.h │ ├── bin.h │ ├── core.h │ ├── anal.h │ ├── common.h │ ├── common.c │ ├── core.c │ ├── asm.c │ ├── anal.c │ └── io.c ├── stubs │ ├── pyproject.toml │ └── radare_stubs.py ├── examples │ ├── test-pyfile-io.py │ ├── test-py-core.py │ ├── test-py-asm.py │ ├── test-py-io.py │ ├── test-py-io2.py │ ├── test-py-anal.py │ └── test-py-arch.py ├── python-config-wrapper ├── build.mk └── radare.py ├── tcc ├── Makefile ├── build.mk └── tcc.c ├── wasm3 └── zig │ ├── src │ ├── r2.zig │ └── main.zig │ ├── examples │ ├── r2pipe.zig │ ├── r2pipe.c │ └── Makefile │ ├── Makefile │ ├── libs │ └── zig-wasm3.patch │ └── build.zig ├── guile ├── hello.scm ├── Makefile └── plugin.c ├── tcl ├── README.md ├── hello.tcl ├── json.tcl ├── Makefile ├── test-tcl-core.tcl ├── tktest.tcl ├── tkhello.tcl └── plugin.c ├── typescript ├── README.md ├── mujs │ ├── Makefile │ ├── tsconfig.json │ ├── index.ts │ ├── types │ │ └── r2pipe.d.ts │ └── r2pipe.ts └── tolua │ ├── tsconfig.json │ ├── Makefile │ ├── index.ts │ ├── types │ └── r2pipe.d.ts │ └── r2pipe.ts ├── zforth ├── test.zf ├── README.md ├── Makefile ├── core.zf └── zforth.c ├── vlang ├── tests │ ├── hello.v │ ├── test-core-vlang.v │ ├── out_core.txt │ └── out.txt ├── build.mk ├── Makefile ├── README.md └── example.v ├── .gitignore ├── configure.acr ├── tiny ├── Makefile ├── hello.tiny └── lang_tiny.c ├── wren ├── Makefile ├── test-example.wren ├── wren.mk └── p │ └── wren.c ├── autogen.sh ├── install.mk ├── .github └── workflows │ ├── c-cpp.yml │ └── release.yml ├── Makefile ├── config.mk.acr └── README.md /go/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /ruby/build.mk: -------------------------------------------------------------------------------- 1 | lang_ruby.${EXT_SO}: 2 | -env CFLAGS="${CFLAGS}" ruby mkruby.rb 3 | -------------------------------------------------------------------------------- /csharp/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /duktape/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /lua/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /mujs/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /perl/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /ruby/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /tcc/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | -------------------------------------------------------------------------------- /wasm3/zig/src/r2.zig: -------------------------------------------------------------------------------- 1 | pub fn r2_cmd(_: *void) *void { 2 | return "jeje"; 3 | } 4 | -------------------------------------------------------------------------------- /guile/hello.scm: -------------------------------------------------------------------------------- 1 | (display "Hello World") 2 | (newline) 3 | (display (r2cmd "e scr.utf8=false;?E hello")) 4 | -------------------------------------------------------------------------------- /csharp/repl/r2pipe.dll.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-rlang/master/csharp/repl/r2pipe.dll.gz -------------------------------------------------------------------------------- /tcl/README.md: -------------------------------------------------------------------------------- 1 | # TCL/TK scripting for radare2 2 | 3 | On Debian/Ubuntu: 4 | 5 | ``` 6 | apt install tk-dev 7 | make 8 | ``` 9 | -------------------------------------------------------------------------------- /typescript/README.md: -------------------------------------------------------------------------------- 1 | # Scripting r2 in TypeScript 2 | 3 | * tstl : uses typescript-to-lua transpiler to run with rlang-lua 4 | -------------------------------------------------------------------------------- /zforth/test.zf: -------------------------------------------------------------------------------- 1 | ." Testing r2 from Forth .. " nl 2 | 3 | ." [*] running a command " nl 4 | s" ?E Hello world " r2cmd tell 5 | -------------------------------------------------------------------------------- /csharp/repl/Newtonsoft.Json.dll.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-rlang/master/csharp/repl/Newtonsoft.Json.dll.gz -------------------------------------------------------------------------------- /typescript/mujs/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | tsc index.ts 3 | echo "main(r2);" >> index.js 4 | mv index.js index.mujs 5 | r2 -qi index.mujs /bin/ls 6 | -------------------------------------------------------------------------------- /csharp/repl/r2api/README.md: -------------------------------------------------------------------------------- 1 | R2Api 2 | ===== 3 | 4 | Superset of the r2pipe api implementing higher level interfaces for 5 | accessing the radare2 functionalities. 6 | -------------------------------------------------------------------------------- /vlang/tests/hello.v: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | pub fn entry(core &R2) { 4 | println('simple hello') 5 | println(core.cmd('?E hello')) 6 | os.system('echo world') 7 | } 8 | 9 | -------------------------------------------------------------------------------- /typescript/mujs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "amd", 4 | "target": "es6", 5 | "rootDir": "./", 6 | "outFile": "./out.js" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typescript/tolua/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "amd", 4 | "target": "es6", 5 | "rootDir": "./", 6 | "outFile": "./out.js" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tcl/hello.tcl: -------------------------------------------------------------------------------- 1 | set ocolor [r2cmd "e scr.color"] 2 | r2cmd "e scr.color=0" 3 | r2cmd "e scr.utf8=0" 4 | set msg [r2cmd "?E Hello World"] 5 | puts $msg 6 | r2cmd "e scr.color=$ocolor" 7 | -------------------------------------------------------------------------------- /lua/README.md: -------------------------------------------------------------------------------- 1 | # LUA scripting for radare2 2 | 3 | * `r2cmd` is available as a global 4 | * `r2api.lua` implements a high level interface on top of r2cmd 5 | * `json.lua` is required for `r2.cmdj` 6 | -------------------------------------------------------------------------------- /tcl/json.tcl: -------------------------------------------------------------------------------- 1 | package require json 2 | 3 | set data [r2cmd "ij"] 4 | # puts $data 5 | 6 | set obj [json::json2dict $data] 7 | set fileName [dict get $obj "core" "file"] 8 | puts "FileName: $fileName" 9 | -------------------------------------------------------------------------------- /lua/lib/Makefile: -------------------------------------------------------------------------------- 1 | FILES=inspect.lua json.lua r2api.lua 2 | 3 | all: 4 | for a in $(FILES) ; do n=$$(echo $$a|sed -e 's,\.,_,g'); printf "const char *$$n = " > $$a.c ; r2 -qfcpcs "$$a" >> $$a.c ; echo ';' >> $$a.c ; done 5 | -------------------------------------------------------------------------------- /lua/examples/typescript/index.ts: -------------------------------------------------------------------------------- 1 | import { R2Pipe } from "../../../quickjs/examples/ts/types/r2pipe"; 2 | 3 | function main(r2: R2Pipe) { 4 | console.log("Hello World"); 5 | console.log("Hello World"); 6 | // console.log(r2.cmd("?E Hello")) 7 | } 8 | -------------------------------------------------------------------------------- /wasm3/zig/examples/r2pipe.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | extern "r2" fn add(a: i32, b: i32, mul: *i32) i32; 4 | 5 | fn main() void { 6 | const add_res = add(a1, a2, &mul_res); 7 | std.info.log("Hello World", .{add_res}); 8 | } 9 | -------------------------------------------------------------------------------- /tcc/build.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(HAVE_LIB_TCC),1) 2 | lang_tcc.${EXT_SO}: tcc.o 3 | -${CC} ${CFLAGS} -fPIC ${LDFLAGS_LIB} -o lang_tcc.${EXT_SO} tcc.c -ldl -ltcc 4 | else 5 | lang_tcc.${EXT_SO}: ; 6 | @echo INFO: Missing libtcc. not building lang_tcc.$(EXT_SO) 7 | endif 8 | -------------------------------------------------------------------------------- /wasm3/zig/examples/r2pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //__attribute__((export_name("r2.add"))) 4 | extern int add (int a, int b); 5 | 6 | __attribute__((export_name("main"))) 7 | int main() { 8 | // printf ("Hello World %d\n", add (1, 2)); 9 | printf ("Hello World %d\n", 123); 10 | } 11 | -------------------------------------------------------------------------------- /lua/hello.lua: -------------------------------------------------------------------------------- 1 | --# require "r2api" 2 | --# require "json" 3 | 4 | print("Hello World") 5 | print(r2cmd("?E Hello World")) 6 | 7 | function foo() 8 | print(r2.cmdj("x")) 9 | end 10 | xpcall(foo,print) 11 | 12 | print("DONE") 13 | -- hello world 14 | local res = r2cmd("afl") 15 | print(res) 16 | -------------------------------------------------------------------------------- /guile/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | GUILE_FLAGS=$(shell pkg-config guile-3.0 --cflags --libs guile-3.0 r_core) 3 | EXT_SO=$(shell r2 -H R2_LIBEXT) 4 | 5 | all: 6 | $(CC) $(GUILE_FLAGS) -fPIC -shared plugin.c -o lang_guile.$(EXT_SO) 7 | $(MAKE) user-install 8 | r2 -qi hello.scm - 9 | 10 | include ../install.mk 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | clang-log/ 2 | .clang_complete 3 | .tmp-format 4 | .#* 5 | *._d 6 | *._o 7 | *.[ado] 8 | *.so 9 | *.pc 10 | *.sdb 11 | *.dylib 12 | *.dll 13 | *.lib 14 | *.obj 15 | *.ilk 16 | *.dSYM 17 | supported.* 18 | config.mk 19 | plugins.cfg 20 | langs.cfg 21 | .*.swp 22 | .*.swo 23 | *.un~ 24 | *.pdb 25 | *.lib 26 | *.ilk 27 | 28 | -------------------------------------------------------------------------------- /perl/build.mk: -------------------------------------------------------------------------------- 1 | PERLINC=$(shell perl -MConfig -e 'print $$Config{archlib}')/CORE/ 2 | lang_perl.${EXT_SO}: 3 | -${CC} ${CFLAGS} -I$(PERLINC) \ 4 | -fPIC ${LDFLAGS_LIB} -o lang_perl.${EXT_SO} perl.c \ 5 | `perl -MExtUtils::Embed -e ccopts | sed -e 's/-arch [^\s]* //g'` \ 6 | `perl -MExtUtils::Embed -e ldopts | sed -e 's/-arch [^\s]* //g'` 7 | -------------------------------------------------------------------------------- /python/python/io.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2019 - pancake, xvilka, aronsky */ 2 | 3 | #ifndef _PY_IO_H 4 | #define _PY_IO_H 5 | 6 | #include 7 | #include "common.h" 8 | 9 | void Radare_plugin_io_free(RIOPlugin *ap); 10 | 11 | PyObject *Radare_plugin_io(Radare* self, PyObject *args); 12 | 13 | #endif /* _PY_IO_H */ -------------------------------------------------------------------------------- /configure.acr: -------------------------------------------------------------------------------- 1 | PKGNAME radare2-rlang 2 | VERSION 6.0.0 3 | CONTACT pancake ; pancake@nopcode.org 4 | 5 | REPORT PREFIX ; 6 | 7 | LANG_C! 8 | USE_PKGCONFIG! 9 | 10 | (( mandatory )) 11 | PKGCFG! R2_CFLAGS R2_LDFLAGS r_core 12 | 13 | ARG_WITH USEROSTYPE=auto ostype Choose OS type ( gnulinux windows darwin haiku ) ; 14 | 15 | SUBDIRS ./config.mk ; 16 | -------------------------------------------------------------------------------- /wasm3/zig/examples/Makefile: -------------------------------------------------------------------------------- 1 | WASI_CC=${HOME}/Downloads/wasi/wasi-sdk-16.0/bin/clang 2 | WASI_SYSROOT=${HOME}/Downloads/wasi/wasi-sysroot-16.0/ 3 | WASI_CFLAGS+=--sysroot=${WASI_SYSROOT} 4 | WASI_CFLAGS+=-Wl,--allow-undefined 5 | WASI_CFLAGS+=-shared 6 | 7 | all: 8 | $(WASI_CC) $(WASI_CFLAGS) r2pipe.c -o r2pipe.wasm 9 | cp -f r2pipe.wasm ../hello.wasm 10 | -------------------------------------------------------------------------------- /python/python/arch.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2024 - astuder */ 2 | 3 | #ifndef _PY_ARCH_H 4 | #define _PY_ARCH_H 5 | 6 | #include 7 | #include "common.h" 8 | 9 | void py_export_arch_enum(PyObject *tp_dict); 10 | 11 | void Radare_plugin_arch_free(RArchPlugin *ap); 12 | 13 | PyObject *Radare_plugin_arch(Radare* self, PyObject *args); 14 | 15 | #endif /* _PY_ARCH_H */ -------------------------------------------------------------------------------- /python/python/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef _PY_ASM_H 2 | #define _PY_ASM_H 3 | 4 | #include 5 | 6 | #if R2_VERSION_NUMBER < 50800 7 | 8 | #include "common.h" 9 | 10 | void py_export_asm_enum(PyObject *tp_dict); 11 | 12 | void Radare_plugin_asm_free(RAsmPlugin *ap); 13 | 14 | PyObject *Radare_plugin_asm(Radare* self, PyObject *args); 15 | #endif 16 | 17 | #endif /* _PY_ASM_H */ 18 | -------------------------------------------------------------------------------- /python/python/bin.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2019 - pancake, xvilka, aronsky */ 2 | 3 | #ifndef _PY_BIN_H 4 | #define _PY_BIN_H 5 | 6 | #include 7 | #include "common.h" 8 | 9 | PyObject *init_pybinfile_module(void); 10 | 11 | void Radare_plugin_bin_free(RBinPlugin *bp); 12 | 13 | PyObject *Radare_plugin_bin(Radare* self, PyObject *args); 14 | 15 | #endif /* _PY_BIN_H */ -------------------------------------------------------------------------------- /python/python/core.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2025 - pancake, xvilka, aronsky */ 2 | 3 | #ifndef _PY_CORE_H 4 | #define _PY_CORE_H 5 | 6 | #include 7 | #include "common.h" 8 | 9 | extern R_TH_LOCAL RCore *Gcore; 10 | 11 | void Radare_plugin_core_free(RCorePlugin *ap); 12 | 13 | PyObject *Radare_plugin_core(Radare* self, PyObject *args); 14 | 15 | #endif /* _PY_CORE_H */ 16 | -------------------------------------------------------------------------------- /python/python/anal.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2019 - pancake, xvilka, aronsky */ 2 | 3 | #ifndef _PY_ANAL_H 4 | #define _PY_ANAL_H 5 | 6 | #include 7 | #include "common.h" 8 | 9 | void py_export_anal_enum(PyObject *tp_dict); 10 | 11 | void Radare_plugin_anal_free(RAnalPlugin *ap); 12 | 13 | PyObject *Radare_plugin_anal(Radare* self, PyObject *args); 14 | 15 | #endif /* _PY_ANAL_H */ -------------------------------------------------------------------------------- /typescript/tolua/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | rm -f index.lua lualib_bundle.lua 3 | tstl -lt 5.4 --luaBundle index.lua --luaBundleEntry index.ts index.ts 4 | sed -i -e 's/return require("index", ...)/return require("index", ...)["main"](nil, r2)/' index.lua 5 | sed -i -e 's/JSON:/json./g' index.lua 6 | sed -i -e 's/self.r2:cmd/r2cmd/g' index.lua 7 | sed -i -e 's/r2:cmd/r2cmd/g' index.lua 8 | r2 -qi index.lua /bin/ls 9 | -------------------------------------------------------------------------------- /typescript/mujs/index.ts: -------------------------------------------------------------------------------- 1 | import { R2Pipe, R2Api } from "./r2pipe"; 2 | 3 | declare function inspect(o: any): string; 4 | 5 | export function main(r2: R2Pipe) { 6 | console.log(r2) 7 | const a = new R2Api(r2) 8 | // console.log(inspect(a)) 9 | r2.cmd("aeim"); 10 | // console.log(r2.cmd("i")) 11 | const regs = a.getRegisters(); 12 | console.log(inspect(regs)); // 13 | console.log("Hello World"); 14 | } 15 | -------------------------------------------------------------------------------- /typescript/tolua/index.ts: -------------------------------------------------------------------------------- 1 | import { R2Pipe, R2Api } from "./r2pipe"; 2 | 3 | declare function inspect(o: any): string; 4 | 5 | export function main(r2: R2Pipe) { 6 | console.log(r2) 7 | const a = new R2Api(r2) 8 | // console.log(inspect(a)) 9 | r2.cmd("aeim"); 10 | // console.log(r2.cmd("i")) 11 | const regs = a.getRegisters(); 12 | console.log(inspect(regs)); // 13 | console.log("Hello World"); 14 | } 15 | -------------------------------------------------------------------------------- /vlang/build.mk: -------------------------------------------------------------------------------- 1 | v vlang: 2 | rm -f lang_v.$(EXT_SO) 3 | $(MAKE) lang_v.$(EXT_SO) 4 | 5 | lang_v.$(EXT_SO): 6 | ${CC} v.c ${CFLAGS} \ 7 | $(shell pkg-config --cflags --libs r_core r_lang) \ 8 | ${LDFLAGS} ${LDFLAGS_LIB} -fPIC -o lang_v.$(EXT_SO) 9 | 10 | vlang-clean v-clean: 11 | rm -f v.o lang_v.$(EXT_SO) 12 | 13 | vlang-install v-install: 14 | mkdir -p ${R2PM_PLUGDIR} 15 | cp -f lang_v.$(EXT_SO) ${R2PM_PLUGDIR} 16 | -------------------------------------------------------------------------------- /python/stubs/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "radare-stubs" 3 | version = "0.1.0" 4 | description = "Stubs for radare core api" 5 | authors = ["radareorg "] 6 | readme = "../../README.md" 7 | packages = [{include = "radare_stubs.py"}] 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.6" 11 | 12 | 13 | [build-system] 14 | requires = ["poetry-core"] 15 | build-backend = "poetry.core.masonry.api" 16 | -------------------------------------------------------------------------------- /tcl/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | TCL_FLAGS=$(shell pkg-config --cflags --libs tcl) 3 | R2_FLAGS=$(shell pkg-config --cflags --libs r_core) 4 | EXT_SO=$(shell r2 -H R2_LIBEXT) 5 | 6 | all: 7 | $(CC) plugin.c $(TCL_FLAGS) $(R2_FLAGS) -fPIC -shared -o lang_tcl.$(EXT_SO) 8 | $(MAKE) user-install 9 | r2 -qi hello.tcl - | grep Hello 10 | r2 -qi test-tcl-core.tcl -c tclhello - | grep "Hello from TCL" 11 | 12 | include ../install.mk 13 | -------------------------------------------------------------------------------- /tiny/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | FILES+=lang_tiny.c 3 | FILES+=Tiny/tiny/src/*.c 4 | CFLAGS+=-I Tiny/tiny/include 5 | CFLAGS+=$(shell pkg-config --cflags --libs r_core) 6 | EXT_SO=$(shell r2 -H R2_LIBEXT) 7 | CFLAGS+=-flto -Oz 8 | 9 | include ../config.mk 10 | 11 | all: Tiny 12 | $(CC) -shared -o lang_tiny.$(EXT_SO) $(CFLAGS) $(FILES) 13 | 14 | Tiny: 15 | git clone https://github.com/goodpaul6/Tiny 16 | 17 | 18 | include ../install.mk 19 | -------------------------------------------------------------------------------- /wasm3/zig/Makefile: -------------------------------------------------------------------------------- 1 | all: libs/zig-wasm3 libs/wasm3 2 | zig build 3 | 4 | run: 5 | $(MAKE) -C examples 6 | zig-out/bin/hello 7 | 8 | libs/zig-wasm3: 9 | git clone 'https://github.com/alichay/zig-wasm3' 'libs/zig-wasm3' 10 | cd libs && patch -p1 < zig-wasm3.patch 11 | 12 | libs/wasm3: 13 | git clone 'https://github.com/wasm3/wasm3' 'libs/wasm3' 14 | 15 | clean: 16 | rm -rf libs/wasm3 libs/zig-wasm3 17 | 18 | fmt: 19 | zig fmt **/*.zig 20 | -------------------------------------------------------------------------------- /lua/examples/typescript/Makefile: -------------------------------------------------------------------------------- 1 | all: node_modules 2 | tsc index.ts 3 | node_modules/.bin/castl --babel --strict -o index.tmp index.js 4 | echo "console={log=print,error=print}" > index.lua 5 | cat index.tmp | grep -v _ENV | grep -v exports >> index.lua 6 | echo 'r2 = {cmd=r2cmd,cmdj=r2cmdj}' >> index.lua 7 | echo 'main(r2)' >> index.lua 8 | rm -f index.tmp 9 | r2 -qi index.lua /bin/ls 10 | 11 | node_modules: 12 | mkdir node_modules 13 | npm i 14 | -------------------------------------------------------------------------------- /csharp/build.mk: -------------------------------------------------------------------------------- 1 | PCP=/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig/ 2 | 3 | all: 4 | @echo TODO: csharp 5 | 6 | mono csharp lang_csharp.$(EXT_SO): 7 | $(CC) -fPIC $(LDFLAGS_LIB) -o lang_csharp.$(EXT_SO) \ 8 | $(shell pkg-config --cflags --libs r_util) csharp.c 9 | 10 | csharp-install mono-install: 11 | mkdir -p ${R2PM_PLUGDIR} 12 | cp -f lang_csharp.$(EXT_SO) ${R2PM_PLUGDIR} 13 | 14 | csharp-uninstall mono-uninstall: 15 | rm -f ${R2PM_PLUGDIR}/lang_csharp.$(EXT_SO) 16 | -------------------------------------------------------------------------------- /wren/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | WREN_PLUGIN=lang_wren.$(EXT_SO) 4 | 5 | all: $(WREN_PLUGIN) 6 | 7 | $(WREN_PLUGIN): wren/libwren.a p/wren.o 8 | $(CC) $(CFLAGS) $(LDFLAGS) -shared -fPIC p/wren.c -o lang_wren.$(EXT_SO) 9 | 10 | clean: 11 | rm -f p/*.o *.$(EXT_SO) 12 | 13 | mrproper: clean 14 | rm -rf wren 15 | 16 | user-install: 17 | cp -f lang_wren.$(EXT_SO) $(R2PM_PLUGDIR)/lang_wren.$(EXT_SO) 18 | 19 | user-uninstall: 20 | rm -f $(R2PM_PLUGDIR)/lang_wren.$(EXT_SO) 21 | 22 | include wren.mk 23 | -------------------------------------------------------------------------------- /zforth/README.md: -------------------------------------------------------------------------------- 1 | # zForth for radare2 2 | 3 | zforth is a minimalistic implementation of Forth that aims to be easy 4 | to embed, simple and portable. 5 | 6 | This plugin exposes the forth interpreter to be used with radare2. 7 | 8 | Enter the zforth repl. 9 | 10 | ``` 11 | $ r2 -c '#!zforth' - 12 | ``` 13 | 14 | ## Simple programs 15 | 16 | ``` 17 | 1 3 + . 10 0 sys ( 10 0 sys is the same as printing \n char to stdout ) 18 | ``` 19 | 20 | ## Using the r2cmd syscall 21 | 22 | ``` 23 | s" ?E Hello World " r2cmd tell nl 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /wasm3/zig/libs/zig-wasm3.patch: -------------------------------------------------------------------------------- 1 | diff --git a/zig-wasm3/submod_build_plugin.zig b/zig-wasm3/submod_build_plugin.zig 2 | index 8acdb6f..7e3e7a3 100644 3 | --- a/zig-wasm3/submod_build_plugin.zig 4 | +++ b/zig-wasm3/submod_build_plugin.zig 5 | @@ -79,7 +79,7 @@ pub fn compile(b: *std.build.Builder, mode: std.builtin.Mode, target: std.zig.Cr 6 | 7 | } 8 | 9 | - lib.addIncludeDir(src_dir); 10 | + lib.addIncludePath(src_dir); 11 | 12 | lib.addCSourceFile(std.fs.path.join(b.allocator, &[_][]const u8{ 13 | std.fs.path.dirname(@src().file).?, 14 | -------------------------------------------------------------------------------- /mujs/example.mujs: -------------------------------------------------------------------------------- 1 | // example r2script 2 | 3 | function main() { 4 | var res = r2.cmd("x 64"); 5 | console.log(res); 6 | 7 | var res = r2.call("pd 3"); 8 | console.log(res); 9 | 10 | // stuff not supported 11 | // var p = new Promise(); 12 | // setTimeout(function a() { console.log("pop"); }, 1000); 13 | 14 | // filesystem test 15 | fs.writeFileSync("test.txt", "patata"); 16 | var data = fs.readFileSync("test.txt"); 17 | console.log(data); 18 | r2.call("rm test.txt"); 19 | 20 | var msg = b64("hello world"); 21 | console.log(msg); 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /wren/test-example.wren: -------------------------------------------------------------------------------- 1 | 2 | 3 | System.print("Hello World") 4 | var a = R2.cmd("?E hello world;aaa") 5 | 6 | var json_length = R2.cmd("aflj").count 7 | System.print("input json length = " + json_length.toString) 8 | var obj = R2.cmdj("aflj") 9 | System.print("contains = " + obj.count.toString + " entries") 10 | 11 | class R2Api { 12 | foo=(v) { 13 | //this.foo = v 14 | } 15 | construct new() { 16 | this.foo = 123 17 | } 18 | fileInfo() { 19 | return R2.cmdj("ij") 20 | } 21 | } 22 | 23 | 24 | var ra = R2Api.new() 25 | /* 26 | 27 | var fi = ra.fileInfo() 28 | System.print(fi["core"]) 29 | */ 30 | -------------------------------------------------------------------------------- /wasm3/zig/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | pub const wasm3_build = @import("libs/zig-wasm3/submod_build_plugin.zig"); 3 | 4 | pub fn build(b: *std.build.Builder) void { 5 | const target = b.standardTargetOptions(.{}); 6 | // const target = std.zig.CrossTarget { .cpu_arch = .wasm32, .os_tag = .wasi, }; 7 | const mode = b.standardReleaseOptions(); 8 | const exe = b.addExecutable("hello", "src/main.zig"); 9 | exe.setTarget(target); 10 | wasm3_build.addTo(exe, "libs/wasm3"); 11 | exe.addPackage(wasm3_build.pkg(null)); 12 | exe.setBuildMode(mode); 13 | exe.install(); 14 | } 15 | -------------------------------------------------------------------------------- /zforth/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | CFLAGS += -I zForth/src/linux 4 | CFLAGS += -I zForth/src/zforth 5 | CFLAGS += -fPIC -shared 6 | LDFLAGS +=-lr_util -lr_core -lr_config 7 | R2_LIBEXT:=$(shell r2 -H R2_LIBEXT) 8 | R2_USER_PLUGINS=$(shell r2 -H R2_USER_PLUGINS) 9 | 10 | all: zForth 11 | #rax2 -i < zForth/forth/core.zf > core_zf.h 12 | rax2 -i < core.zf > core_zf.h 13 | $(CC) -o lang_zforth.$(R2_LIBEXT) $(CFLAGS) $(LDFLAGS) zforth.c zForth/src/zforth/zforth.c 14 | mkdir -p $(R2_USER_PLUGINS) 15 | cp -f lang_zforth.$(R2_LIBEXT) $(R2_USER_PLUGINS) 16 | 17 | zForth: 18 | git clone https://github.com/zevv/zForth 19 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Look for the 'acr' tool here: https://github.com/radare/acr 4 | # Clone last version of ACR from here: 5 | # git clone https://github.com/radare/acr 6 | # 7 | # -- pancake 8 | 9 | r2pm -h >/dev/null 2>&1 10 | if [ $? = 0 ]; then 11 | echo "Installing the last version of 'acr'..." 12 | r2pm -i acr > /dev/null 13 | r2pm -r acr -h > /dev/null 2>&1 14 | if [ $? = 0 ]; then 15 | echo "Running 'acr -p'..." 16 | r2pm -r acr -p 17 | else 18 | echo "Cannot find 'acr' in PATH" 19 | fi 20 | else 21 | echo "Running acr..." 22 | acr -p 23 | fi 24 | if [ -n "$1" ]; then 25 | echo "./configure $*" 26 | ./configure $* 27 | fi 28 | -------------------------------------------------------------------------------- /install.mk: -------------------------------------------------------------------------------- 1 | clean mrproper: 2 | -rm -f *.${EXT_SO} *.${EXT_AR} *.o 3 | -rm -rf *.dSYM 4 | 5 | install: 6 | mkdir -p $(DESTDIR)/$(R2_PLUGIN_PATH) 7 | rm -f $(DESTDIR)/$(R2_PLUGIN_PATH)/`ls *.$(EXT_SO)` 8 | [ -n "`ls *.$(EXT_SO)`" ] && cp -f *.$(EXT_SO) $(DESTDIR)/$(R2_PLUGIN_PATH) || true 9 | 10 | user-install install-home: 11 | mkdir -p ${R2PM_PLUGDIR} 12 | rm -f $(DESTDIR)/$(R2_PLUGIN_PATH)/`ls *.$(EXT_SO)` 13 | [ -n "`ls *.$(EXT_SO)`" ] && cp -f *.$(EXT_SO) ${R2PM_PLUGDIR} || true 14 | 15 | uninstall: 16 | rm -f $(DESTDIR)/$(R2_PLUGIN_PATH)/"`ls *.$(EXT_SO)`" 17 | 18 | user-uninstall uninstall-home: 19 | rm -f $(R2PM_PLUGDIR)/"`ls *.$(EXT_SO)`" 20 | -------------------------------------------------------------------------------- /lua/examples/test.lua: -------------------------------------------------------------------------------- 1 | -- require"r2api" 2 | -- local inspect = require"inspect" 3 | 4 | -- function r2cmd() end 5 | 6 | local size = 4 7 | local res = r2cmd("px " .. size) 8 | local entry0 = r2:ptr("entry0") 9 | 10 | local pc = entry0 11 | 12 | -- disasm until invalid instruction 13 | while true do 14 | local op = pc:instruction() 15 | 16 | if op.opcode == "invalid" then break end 17 | print(hex(op.addr).." "..op.size.." "..op.opcode) 18 | pc:add(op.size) 19 | end 20 | 21 | r2.analyzeProgram() 22 | local bytes = r2:ptr("entry0"):readBytes(4) 23 | print(inspect(bytes)) 24 | local arch = r2.getConfig("asm.arch") 25 | print(arch) 26 | print(res) 27 | print("Hello World") 28 | -------------------------------------------------------------------------------- /vlang/tests/test-core-vlang.v: -------------------------------------------------------------------------------- 1 | // Example V core plugin registration 2 | // Usage: 3 | // r2 -qi vlang/tests/test-core-vlang.v - 4 | // Then type 'vhello' in the r2 prompt to test. 5 | 6 | pub fn vcore_call(core &R2, input byteptr) bool { 7 | unsafe { 8 | s := input.vstring() 9 | if s == 'vhello' { 10 | println('Hello from V core plugin!') 11 | println(core.cmd('?E Hello V')) 12 | return true 13 | } 14 | } 15 | return false 16 | } 17 | 18 | pub fn entry(core &R2) { 19 | // name, callback, desc, license 20 | _ = core.register_core('vcoretest', vcore_call, 'Example core plugin written in V', 'MIT') 21 | } 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: R2L 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: radare2 15 | run: | 16 | git clone --depth=1 https://github.com/radareorg/radare2 17 | cd radare2 18 | ./configure --prefix=/usr 19 | make 20 | sudo make install 21 | cd .. 22 | - name: configure 23 | run: ./configure --prefix=/usr 24 | - name: make 25 | run: make 26 | - name: install 27 | run: make install 28 | - name: make tests 29 | run: make tests 30 | -------------------------------------------------------------------------------- /python/examples/test-pyfile-io.py: -------------------------------------------------------------------------------- 1 | import r2lang 2 | 3 | 4 | def pyfile(a): 5 | def _open(path, rw, perm): 6 | return open(path[9:], 'rb') 7 | 8 | def _check(path, many): 9 | return path[0:9] == "pyfile://" 10 | 11 | def _read(data, size): 12 | return data.read(size) 13 | 14 | def _seek(data, offset, whence): 15 | data.seek(offset, whence) 16 | return data.tell() 17 | 18 | def _close(data): 19 | data.close() 20 | return 0 21 | 22 | return { 23 | "name": "pyfile", 24 | "license": "LGPL", 25 | "desc": "IO plugin in python (pyfile://)", 26 | "check": _check, 27 | "open": _open, 28 | "read": _read, 29 | "seek": _seek, 30 | "close": _close, 31 | } 32 | 33 | r2lang.plugin("io", pyfile) 34 | -------------------------------------------------------------------------------- /wren/wren.mk: -------------------------------------------------------------------------------- 1 | WREN_LIB=wren/libwren.a 2 | # OBJS+=$(WREN_LIB) 3 | #OBJS+=p/wren.o 4 | CFLAGS+=$(shell pkg-config --cflags r_lang r_cons r_util) -Oz 5 | LDFLAGS+=$(shell pkg-config --libs r_lang r_cons r_util) 6 | 7 | wren: 8 | git clone --depth=1 https://github.com/wren-lang/wren 9 | $(MAKE) $(WREN_LIB) 10 | 11 | p/wren.o: p/wren-vm.c p/wren.c 12 | 13 | $(WREN_LIB): wren 14 | cd wren/src/vm/ && $(CC) $(CFLAGS) $(LDFLAGS) -Oz -c *.c -DWREN_OPT_RANDOM=0 -DWREN_OPT_META=0 -I ../include -I .. 15 | $(AR) rvs $(WREN_LIB) wren/src/vm/*.o 16 | $(RANLIB) $(WREN_LIB) 17 | 18 | PYTHON?=python 19 | 20 | p/wren-vm.c: wren 21 | cd wren && $(PYTHON) util/generate_amalgamation.py > ../p/wren-vm.c 22 | cp -f wren/src/include/wren.h p/wren-vm.h 23 | -------------------------------------------------------------------------------- /tcl/test-tcl-core.tcl: -------------------------------------------------------------------------------- 1 | # Example TCL Core plugin written in TCL 2 | # Usage: 3 | # r2 -qi tcl/test-tcl-core.tcl - 4 | # Then type 'tclhello' in the r2 prompt to test. 5 | 6 | proc tclcore_provider {} { 7 | return [dict create \ 8 | name "tclcoretest" \ 9 | license "MIT" \ 10 | desc "Example core plugin written in TCL" \ 11 | call tclcore_call] 12 | } 13 | 14 | proc tclcore_call {input} { 15 | if {$input eq "tclhello"} { 16 | # run an r2 command from TCL and print output 17 | puts [r2cmd "x 16 @ $$"] 18 | puts "Hello from TCL core plugin!" 19 | return 1 20 | } 21 | return 0 22 | } 23 | 24 | puts "Registering TCL core plugin..." 25 | puts [r2plugin core tclcore_provider] 26 | -------------------------------------------------------------------------------- /python/examples/test-py-core.py: -------------------------------------------------------------------------------- 1 | # Example Python Core plugin written in Python 2 | # =========================================== 3 | # -- pancake 2016-2023 4 | # 5 | # $ r2 -i test-py-core.py - 6 | # > q 7 | # .. hexdump .. 8 | # Dont be rude. Use q! 9 | # > ^D 10 | # $ 11 | 12 | import r2lang 13 | 14 | def pycore(a): 15 | def _call(s): 16 | if s == "q": 17 | try: 18 | print(r2lang.cmd("x")) 19 | except: 20 | print("ERR") 21 | print("Dont be rude. Use q!") 22 | return True; 23 | return False 24 | 25 | return { 26 | "name": "pycoretest", 27 | "license": "MIT", 28 | "desc": "example core plugin written in python", 29 | "call": _call, 30 | } 31 | 32 | print("Registering Python core plugin...") 33 | print(r2lang.plugin("core", pycore)) 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include config.mk 2 | 3 | LANGS?=python duktape lua perl vlang 4 | 5 | # WIP language support 6 | # LANGS+=csharp 7 | # LANGS+=ruby 8 | # LANGS+=tcc 9 | 10 | all: $(LANGS) 11 | for LANG in $(LANGS); do $(MAKE) -C $${LANG} ; done 12 | 13 | install: 14 | for LANG in $(LANGS); do $(MAKE) -C $${LANG} install ; done 15 | 16 | install-home: 17 | for LANG in $(LANGS); do $(MAKE) -C $${LANG} install-home ; done 18 | 19 | uninstall: 20 | for LANG in $(LANGS); do $(MAKE) -C $${LANG} install-home ; done 21 | 22 | uninstall-home: 23 | for LANG in $(LANGS); do $(MAKE) -C $${LANG} uninstall-home ; done 24 | 25 | mrproper clean: 26 | for LANG in $(LANGS); do $(MAKE) -C $${LANG} clean ; done 27 | 28 | tests test: 29 | @echo Nothing to test for now 30 | # for LANG in $(LANGS); do $(MAKE) -C $${LANG} test ; done 31 | 32 | -------------------------------------------------------------------------------- /python/python-config-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # python-config wrapper trying to fix the python versioning hell 3 | # -- pancake 4 | 5 | PCS="${PYTHON_CONFIG} 6 | python3-config 7 | python38-config 8 | python3.8-config 9 | python37-config 10 | python3.7-config 11 | python36-config 12 | python3.6-config 13 | python-config" 14 | 15 | PYCFG="" 16 | 17 | for a in ${PCS} ; do 18 | $a --help >/dev/null 2>&1 19 | if [ $? = 0 ]; then 20 | PYCFG=$a 21 | break 22 | fi 23 | done 24 | 25 | [ -z "${PYCFG}" ] && exit 1 26 | if [ "$1" = "-n" ]; then 27 | echo "${PYCFG}" 28 | exit 0 29 | fi 30 | 31 | output=`"${PYCFG}" "$@"` \ 32 | && echo $output || echo $output 1>&2 | sed \ 33 | -e 's/-arch [^\ ]*//g' \ 34 | -e 's, s ,,g' \ 35 | -e 's,-mn[^\ ]*,,g' \ 36 | -e 's,-fn[^\ ]*,,g' \ 37 | -e 's,-Wstrict-prototypes,,g' 2>/dev/null 38 | -------------------------------------------------------------------------------- /vlang/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | include build.mk 3 | include ../install.mk 4 | 5 | test: 6 | @command -v r2 >/dev/null || { echo "SKIP: r2 not found"; exit 0; } 7 | @command -v v >/dev/null || { echo "SKIP: V compiler not found"; exit 0; } 8 | $(MAKE) vlang 9 | $(MAKE) vlang-install 10 | @mkdir -p tests 11 | @echo "Running V plugin smoke test..." 12 | @r2 -N -q -e scr.color=false -i tests/hello.v - > tests/out.txt 2>&1 || true 13 | @grep -q "simple hello" tests/out.txt && echo "OK: vlang plugin works" || { echo "FAIL: vlang plugin test failed"; exit 1; } 14 | @echo "Running V core plugin test..." 15 | @r2 -N -q -e scr.color=false -qi tests/test-core-vlang.v -c vhello - > tests/out_core.txt 2>&1 || true 16 | @grep -q "Hello from V core plugin" tests/out_core.txt && echo "OK: vlang core plugin works" || { echo "FAIL: vlang core plugin test failed"; exit 1; } 17 | -------------------------------------------------------------------------------- /tcc/tcc.c: -------------------------------------------------------------------------------- 1 | /* tcc extension for libr (radare2) - copyright pancake 2011-2024 */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /* TODO: store the state globally or so.. */ 8 | static bool r_lang_tcc_run(RLangSession *ls, const char *code, int len) { 9 | TCCState *ts = tcc_new (); 10 | /* TODO: set defined vars as global */ 11 | // list_for_each(lang->defs) { 12 | tcc_compile_string (ts, code); 13 | tcc_run (ts, 0, 0); //argc, argv); 14 | tcc_delete (ts); 15 | return R_TRUE; 16 | } 17 | 18 | static RLangPlugin r_lang_plugin_tcc = { 19 | .meta = { 20 | .name = "tcc", 21 | .desc = "C99 rlang extension using libtcc", 22 | }, 23 | .ext = "c", 24 | .run = &r_lang_tcc_run 25 | }; 26 | 27 | #ifndef CORELIB 28 | RLibStruct radare_plugin = { 29 | .type = R_LIB_TYPE_LANG, 30 | .version = R2_VERSION, 31 | .data = &r_lang_plugin_tcc, 32 | }; 33 | #endif 34 | -------------------------------------------------------------------------------- /config.mk.acr: -------------------------------------------------------------------------------- 1 | PREFIX=@PREFIX@ 2 | 3 | R2_PLUGIN_PATH=$(shell r2 -H R2_USER_PLUGINS) 4 | R2_LIBDIR_PATH=$(shell r2 -H R2_LIBDIR) 5 | PKG_CONFIG_PATH+=:${R2_LIBDIR_PATH}/pkgconfig 6 | R2_PREFIX=$(shell r2 -H R2_PREFIX) 7 | 8 | ifeq ($(PREFIX),) 9 | PREFIX=$(R2_PREFIX) 10 | endif 11 | 12 | CFLAGS+=$(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --cflags r_core) 13 | CFLAGS+=-DPREFIX=\"${PREFIX}\" 14 | 15 | DUK_CFLAGS+=-Wall -DPREFIX=\"${PREFIX}\" -I. -Iduk 16 | 17 | R2PM_PLUGDIR?=${R2_PLUGIN_PATH} 18 | EXT_SO?=$(shell r2 -H LIBEXT) 19 | 20 | ifeq ($(EXT_SO),) 21 | ifeq ($(OSTYPE),darwin) 22 | CFLAGS+=-undefined dynamic_lookup 23 | EXT_SO=dylib 24 | else 25 | ifeq ($(OSTYPE),windows) 26 | EXT_SO=dll 27 | else 28 | EXT_SO=so 29 | endif 30 | endif 31 | endif 32 | 33 | LDFLAGS_LIB=$(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs-only-L r_core) -lr_core -lr_io -lr_util -shared -lr_asm 34 | -------------------------------------------------------------------------------- /duktape/duk/duk_console.h: -------------------------------------------------------------------------------- 1 | #if !defined(DUK_CONSOLE_H_INCLUDED) 2 | #define DUK_CONSOLE_H_INCLUDED 3 | 4 | #include "duktape.h" 5 | 6 | #if defined(__cplusplus) 7 | extern "C" { 8 | #endif 9 | 10 | /* Use a proxy wrapper to make undefined methods (console.foo()) no-ops. */ 11 | #define DUK_CONSOLE_PROXY_WRAPPER (1U << 0) 12 | 13 | /* Flush output after every call. */ 14 | #define DUK_CONSOLE_FLUSH (1U << 1) 15 | 16 | /* Send output to stdout only (default is mixed stdout/stderr). */ 17 | #define DUK_CONSOLE_STDOUT_ONLY (1U << 2) 18 | 19 | /* Send output to stderr only (default is mixed stdout/stderr). */ 20 | #define DUK_CONSOLE_STDERR_ONLY (1U << 3) 21 | 22 | /* Initialize the console system */ 23 | extern void duk_console_init(duk_context *ctx, duk_uint_t flags); 24 | 25 | #if defined(__cplusplus) 26 | } 27 | #endif /* end 'extern "C"' wrapper */ 28 | 29 | #endif /* DUK_CONSOLE_H_INCLUDED */ 30 | -------------------------------------------------------------------------------- /tiny/hello.tiny: -------------------------------------------------------------------------------- 1 | global := 213 2 | 3 | struct ptr { 4 | num: int 5 | text: str 6 | } 7 | func get_pointer() : ptr { 8 | return new ptr {0, ""} 9 | } 10 | 11 | func find_entrypoint() : str { 12 | return trim(r2("ieq")) 13 | } 14 | 15 | // parse file, expose new functions and globals and check 16 | // if all of them start with the filename as prefix 17 | // include("test.tiny") 18 | 19 | func countmovs(addr: str) : int { 20 | return atoi(r2("af;pdr~mov?")) 21 | } 22 | 23 | func getbbs(addr: str) : array { 24 | return array() // split(r2(format("afbq@%s", addr)), "\n") 25 | } 26 | 27 | func main() { 28 | printf("Hello radare2!\n") 29 | r2("o /bin/ls") 30 | ep := find_entrypoint() 31 | printf ("entry0 = %s\n", ep) 32 | n := countmovs(ep) 33 | printf ("movs = %i\n", n) 34 | bbs := getbbs(ep) 35 | for i := 0; i < n; i += 1 { 36 | printf ("op %i\n", i) 37 | } 38 | // a := test.new() 39 | // test(a, "") 40 | } 41 | main() 42 | -------------------------------------------------------------------------------- /ruby/chkruby.rb: -------------------------------------------------------------------------------- 1 | # setup with ruby! 2 | 3 | require 'mkmf' 4 | INCDIR = Config::CONFIG['rubylibdir'] + "/"+Config::CONFIG['arch'] 5 | LIBDIR = Config::CONFIG['LIBRUBY_ARG_SHARED'] 6 | #LIBS = Config::CONFIG['LIBS'] -lpthread... 7 | LIBNAM = Config::CONFIG['RUBY_INSTALL_NAME'] 8 | #LDSHARED=compilername -shared..." 9 | 10 | rb_so = '_test.so' 11 | rb_c = '_test.c' 12 | inc = '../..' 13 | 14 | $cc=ENV["CC"] 15 | if $cc == nil then 16 | $cc="cc" 17 | end 18 | 19 | tobeup=false 20 | begin 21 | d0 = File.stat(rb_so).mtime.to_i 22 | d1 = File.stat(rb_c).mtime.to_i 23 | if d1 > d0 then 24 | tobeup=true 25 | end 26 | rescue 27 | tobeup=true 28 | end 29 | 30 | ret = false 31 | if tobeup then 32 | system("echo 'main(){}' > #{rb_c}"); 33 | $line="#{$cc} -I #{inc} -I#{INCDIR} #{rb_c} -shared #{LIBDIR}" \ 34 | " -l#{LIBNAM} #{ENV['CFLAGS']} #{ENV['LDFLAGS']} -o #{rb_so}" 35 | ret = system($line) 36 | system("rm -f #{rb_so} #{rb_c}"); 37 | end 38 | exit ret 39 | -------------------------------------------------------------------------------- /csharp/repl/Makefile: -------------------------------------------------------------------------------- 1 | R2PIPE=../../../r2pipe/dotnet/r2pipe/R2Pipe.cs 2 | R2PIPE+=../../../r2pipe/dotnet/r2pipe/IR2Pipe.cs 3 | R2PIPE+=../../../r2pipe/dotnet/r2pipe/RlangPipe.cs 4 | R2PIPE+=../../../r2pipe/dotnet/r2pipe/CmdQueue.cs 5 | R2PIPE+=../../../r2pipe/dotnet/r2pipe/HttpR2Pipe.cs 6 | R2PIPE+=../../../r2pipe/dotnet/r2pipe/QueuedR2Pipe.cs 7 | 8 | BIN=main.exe 9 | SCR=csharp-r2 10 | 11 | all: NewtonSoft.Json.dll r2pipe.dll 12 | mcs -out:$(BIN) main.cs shell.cs getline.cs \ 13 | -r:Mono.CSharp -r:System.Net.Http \ 14 | -r:Mono.Posix -r:r2pipe -r:NewtonSoft.Json 15 | echo '#!/bin/sh' > $(SCR) 16 | echo 'mono $(shell pwd)/main.exe $$@' >> $(SCR) 17 | chmod +x $(SCR) 18 | 19 | NewtonSoft.Json.dll: 20 | gunzip -k NewtonSoft.Json.dll.gz 21 | 22 | r2pipe.dll: 23 | gunzip -k r2pipe.dll.gz 24 | 25 | install: 26 | cp -f $(SCR) ~/.config/radare2/bin 27 | 28 | uninstall: 29 | rm -f ~/.config/radare2/bin/$(SCR) 30 | 31 | clean: 32 | rm -f $(BIN) 33 | rm -f r2repl 34 | -------------------------------------------------------------------------------- /duktape/build.mk: -------------------------------------------------------------------------------- 1 | DUKTAPE_VER=2.7.0 2 | DUKTAPE_FILE=duktape-$(DUKTAPE_VER).tar.xz 3 | DUKTAPE_URL=https://duktape.org/$(DUKTAPE_FILE) 4 | DV=duktape-${DUKTAPE_VER} 5 | 6 | 7 | duktape: 8 | $(MAKE) lang_duktape.$(EXT_SO) 9 | 10 | lang_duktape.$(EXT_SO): duktape.o duk 11 | -$(CC) -std=c99 -flto -Oz $(DUK_CFLAGS) $(CFLAGS) -fPIC $(LDFLAGS_LIB) \ 12 | -o lang_duktape.$(EXT_SO) duktape.c 13 | 14 | p: 15 | rm -f lang_python.${EXT_SO} 16 | $(MAKE) lang_python.${EXT_SO} PYVER=3 17 | cp -f lang_python.${EXT_SO} ~/.local/share/radare2/plugins 18 | 19 | 20 | duk duktape-sync duk-sync sync-dunk sync-duktape: 21 | rm -f $(DUKTAPE_FILE) 22 | wget -O $(DUKTAPE_FILE) $(DUKTAPE_URL) 23 | tar xJvf $(DUKTAPE_FILE) 24 | mkdir -p duk 25 | cp -f $(DV)/src/duktape.* duk/ 26 | cp -f $(DV)/src/duk_config.h duk/ 27 | cp -f $(DV)/extras/console/duk* duk/ 28 | rm -rf $(DUKTAPE_FILE) ${DV} 29 | 30 | duk-install install-duk: 31 | cp -f lang_duktape.${EXT_SO} ${R2PM_PLUGDIR} 32 | 33 | -------------------------------------------------------------------------------- /tcl/tktest.tcl: -------------------------------------------------------------------------------- 1 | package require Tk 2 | 3 | r2cmd "-e scr.color=0" 4 | 5 | label .l -text "Command:" 6 | entry .e -width 40 -relief sunken -bd 2 -textvariable name 7 | focus .e 8 | button .b -text Clear -command { 9 | set output "" 10 | set name "" 11 | } 12 | button .r -text Run -command { 13 | set output [r2cmd $name] 14 | set name "" 15 | } 16 | label .o -text "Output:" -textvariable output -font {-family Courier -size 18} -justify left -wraplength 800 17 | bind .e { 18 | set output [r2cmd $name] 19 | set name "" 20 | } 21 | 22 | 23 | grid .l -row 0 -column 0 -sticky e 24 | grid .e -row 0 -column 1 -sticky w 25 | grid .r -row 0 -column 2 26 | grid .b -row 0 -column 3 27 | grid .o -row 1 -column 0 -columnspan 3 28 | 29 | # stop script when window is closed. thats what wish do 30 | proc onWindowClose {} { 31 | set ::done 1 32 | destroy . 33 | # exit 34 | } 35 | wm protocol . WM_DELETE_WINDOW onWindowClose 36 | set done 0 37 | # mainloop 38 | vwait ::done 39 | -------------------------------------------------------------------------------- /mujs/build.mk: -------------------------------------------------------------------------------- 1 | MUJS_GIT=1 2 | MUJS_VER=1.3.2 3 | MUJS_FILE=mujs-$(MUJS_VER).tar.xz 4 | MUJS_URL=https://mujs.com/downloads/$(MUJS_FILE) 5 | DV=mujs-${MUJS_VER} 6 | 7 | ifeq ($(shell type wget 2> /dev/null && echo 1),1) 8 | WGET?=wget -c --no-check-certificate -O 9 | else 10 | WGET?=curl -o 11 | endif 12 | 13 | lang_mujs.$(EXT_SO): plugin.o mujs 14 | -$(CC) -std=c99 -flto -Oz $(DUK_CFLAGS) $(CFLAGS) -fPIC $(LDFLAGS_LIB) \ 15 | -o lang_mujs.$(EXT_SO) plugin.c 16 | 17 | all: mujs 18 | $(MAKE) lang_mujs.$(EXT_SO) 19 | 20 | mujs mujs-sync: 21 | ifeq ($(MUJS_GIT),1) 22 | [ ! -d mujs ] && git clone https://github.com/ccxvii/mujs mujs 23 | [ -d mujs ] && cd mujs && git pull 24 | else 25 | rm -rf $(MUJS_FILE) 26 | $(WGET) -O $(MUJS_FILE) $(MUJS_URL) 27 | tar xJvf $(MUJS_FILE) 28 | ln -fs mujs-$(MUJS_VER) mujs 29 | endif 30 | 31 | mujs-install install-mujs: 32 | cp -f lang_mujs.${EXT_SO} ${R2PM_PLUGDIR} 33 | 34 | mujs-clean: 35 | rm -f mujs 36 | rm -rf mujs-$(MUJS_VER) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | radare2-rlang 2 | ============= 3 | 4 | [![Tests Status](https://github.com/radareorg/radare2-rlang/workflows/R2L/badge.svg)](https://github.com/radareorg/radare2-rlang/actions?query=workflow%3A%22R2L%22) 5 | 6 | RLang plugins are used to instantiate a VM inside radare2 to run scripts by keeping the 7 | internal state alive along multiple executions. This is like interpretting scripts using 8 | r2pipe, but with extra features: 9 | 10 | * No need to instantiate and load the libraries on every call 11 | * Keep global state between runs 12 | * Write asm/anal/bin plugins in dynamic languages 13 | * Support Python, Javascript and others! 14 | 15 | Building 16 | ======== 17 | 18 | Check for dependencies and build 19 | 20 | ``` 21 | ./configure --prefix=/usr 22 | make 23 | make install 24 | ``` 25 | 26 | If you want to build a specific plugin, just cd into the right directory. 27 | 28 | ``` 29 | ./configure --prefix=/usr 30 | cd python 31 | make 32 | make install 33 | ``` 34 | -------------------------------------------------------------------------------- /python/python/common.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2019 - pancake, xvilka, aronsky */ 2 | 3 | #ifndef _PY_COMMON_H 4 | #define _PY_COMMON_H 5 | #include 6 | #include 7 | 8 | #undef HAVE_SIGACTION 9 | 10 | #undef _GNU_SOURCE 11 | #undef _XOPEN_SOURCE 12 | #undef _POSIX_C_SOURCE 13 | #undef PREFIX 14 | 15 | #include 16 | #include 17 | 18 | #if PY_MAJOR_VERSION<3 19 | #error Python 2 support is deprecated, use Python 3 instead 20 | #endif 21 | 22 | typedef struct { 23 | PyObject_HEAD 24 | PyObject *first; /* first name */ 25 | PyObject *last; /* last name */ 26 | int number; 27 | } Radare; 28 | 29 | bool contains(PyObject *o, const char *name); 30 | 31 | PyObject *getO(PyObject *o, const char *name); 32 | 33 | char *getS(PyObject *o, const char *name); 34 | 35 | st64 getI(PyObject *o, const char *name); 36 | 37 | void *getF(PyObject *o, const char *name); 38 | 39 | bool getB(PyObject *o, const char *name); 40 | #endif /* _PY_COMMON_H */ 41 | -------------------------------------------------------------------------------- /lua/build.mk: -------------------------------------------------------------------------------- 1 | LUAPKG=$(shell pkg-config --list-all|awk '/lua5|lua5-/{print $$1;}') 2 | ifneq (${LUAPKG},) 3 | CFLAGS+=$(shell pkg-config --cflags r_core ${LUAPKG}) 4 | LUA_LDFLAGS+=$(shell pkg-config --libs r_lang ${LUAPKG}) 5 | else 6 | LUA_VERSION=5.4.4 7 | LUA_CFLAGS+=-Ilua-$(LUA_VERSION)/src -g 8 | LUA_LDFLAGS+=`ls lua-$(LUA_VERSION)/src/*.c | grep -v lua.c | grep -v luac.c` 9 | endif 10 | # CFLAGS+=-Os 11 | # LUA_LDFLAGS+=-Os -flto 12 | 13 | lua lang_lua.${EXT_SO}: lua-sync 14 | -${CC} $(LUA_CFLAGS) ${CFLAGS} -fPIC ${LDFLAGS_LIB} -o lang_lua.${EXT_SO} lua.c ${LUA_LDFLAGS} 15 | 16 | lua-install: 17 | mkdir -p ${R2PM_PLUGDIR}/lua 18 | cp -f lang_lua.${EXT_SO} ${R2PM_PLUGDIR} 19 | cp -f lua/*.lua ${R2PM_PLUGDIR}/lua 20 | # TODO: move this radare.lua into lua/ 21 | cp -f radare.lua ${R2PM_PLUGDIR}/lua 22 | 23 | ifeq (${LUAPKG},) 24 | lua-sync: lua-${LUA_VERSION} 25 | else 26 | lua-sync: 27 | endif 28 | 29 | lua-${LUA_VERSION}: 30 | wget -c https://www.lua.org/ftp/lua-$(LUA_VERSION).tar.gz 31 | tar xzvf lua-$(LUA_VERSION).tar.gz 32 | -------------------------------------------------------------------------------- /python/examples/test-py-asm.py: -------------------------------------------------------------------------------- 1 | # Example Python Asm plugin written in Python 2 | # =========================================== 3 | # 4 | # -- pancake @ nopcode.org 5 | # 6 | # The r2lang.plugin function exposes a way to register new plugins 7 | # into the RCore instance. This API is only available from RLang. 8 | # You must call with with '#!python test.py' or 'r2 -i test.py ..' 9 | 10 | import r2lang 11 | 12 | def pyasm(a): 13 | def assemble(s): 14 | print("Assembling %s"%(s)) 15 | return [ 1, 2, 3, 4 ] 16 | 17 | def disassemble(buf, buflen, pc): 18 | try: 19 | return [ 2, f"opcode {buf[0]}" ] 20 | except: 21 | print("err") 22 | print(sys.exc_info()) 23 | return [ 2, "opcode" ] 24 | return { 25 | "name": "MyPyDisasm", 26 | "arch": "pyarch", 27 | "bits": 32, 28 | "license": "GPL", 29 | "desc": "disassembler plugin in python", 30 | "assemble": assemble, 31 | "disassemble": disassemble, 32 | } 33 | 34 | if not r2lang.plugin("asm", pyasm): 35 | print("Failed to register the python asm plugin.") 36 | 37 | -------------------------------------------------------------------------------- /csharp/csharp.c: -------------------------------------------------------------------------------- 1 | /* radare - MIT - Copyright 2016 pancake */ 2 | 3 | #define _XOPEN_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static int lang_csharp_run(RLang *lang, const char *code, int len) { 13 | lang->cmdf (lang->user, "#!pipe csharp-r2 -e '%s'", code); 14 | return 1; 15 | } 16 | 17 | static int lang_csharp_prompt(RLang *lang) { 18 | lang->cmdf (lang->user, "#!pipe csharp-r2"); 19 | return 1; 20 | } 21 | 22 | static bool lang_csharp_file(RLang *lang, const char *file) { 23 | int ret = false; 24 | if (lang && lang->cmdf && file) { 25 | lang->cmdf (lang->user, "#!pipe csharp-r2 -i '%s'", file); 26 | return true; 27 | } 28 | return true; 29 | } 30 | 31 | static RLangPlugin r_lang_plugin_csharp = { 32 | .name = "csharp", 33 | .ext = "cs", 34 | .desc = "C# extension language using Mono", 35 | .license = "MIT", 36 | .prompt = lang_csharp_prompt, 37 | .run = lang_csharp_run, 38 | .run_file = (void*)lang_csharp_file, 39 | }; 40 | 41 | #if !CORELIB 42 | struct r_lib_struct_t radare_plugin = { 43 | .type = R_LIB_TYPE_LANG, 44 | .data = &r_lang_plugin_csharp, 45 | }; 46 | #endif 47 | -------------------------------------------------------------------------------- /duktape/examples/dukasm.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Example disassembler plugin in Javascript for r2 3 | * This script depends on "duktape" 4 | * $ r2 -nqc '. dukasm.js' - 5 | */ 6 | // xxx this plugin is not going to work in r2>=5.8 because asm plugins cant disasm 7 | 8 | var res = r2plugin ("asm", function (a) { 9 | function disassemble (buf) { 10 | switch (buf[0]) { 11 | case 0x90: return [1, "nop"]; 12 | case 0xcc: return [1, "int3"]; 13 | case 0xcd: return [2, "int "+buf[1]]; 14 | } 15 | return [ 1, "invalid "+buf[0], -1 ]; 16 | } 17 | function assemble(str) { 18 | var op = str.split (/ /g); 19 | switch (op[0]) { 20 | case "nop": return [0x90]; 21 | case "int3": return [0xcc]; 22 | case "int": return [0xcd, +op[1]]; 23 | } 24 | return null; 25 | } 26 | return { 27 | name: "MyJS", 28 | arch: "myarch", 29 | license: "LGPL3", 30 | bits: 32, 31 | description: "My Javascript Disassembler", 32 | disassemble: disassemble, 33 | assemble: assemble 34 | } 35 | }); 36 | 37 | var msg = res? "New":"Error registering"; 38 | console.log (msg+" disasm plugin from Javascript"); 39 | 40 | if (res) { 41 | r2cmd ("e asm.arch=MyJS"); 42 | r2cmd ("wx 0090cccd33"); 43 | console.log (r2cmd ("pd 4")); 44 | console.log (r2cmd ("\"pa nop;int3\"")); 45 | } 46 | -------------------------------------------------------------------------------- /python/python/common.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2019 - pancake, xvilka, aronsky */ 2 | 3 | #include "common.h" 4 | 5 | bool contains(PyObject *o, const char *name) { 6 | if (!o || !name) return false; 7 | PyObject *str = PyUnicode_FromString (name); 8 | return (PyDict_Contains (o, str) == 1); 9 | } 10 | 11 | PyObject *getO(PyObject *o, const char *name) { 12 | if (!o) return NULL; 13 | PyObject *res = PyDict_GetItemString (o, name); 14 | if (!res || res == Py_None) return NULL; 15 | return res; 16 | } 17 | 18 | char *getS(PyObject *o, const char *name) { 19 | if (!o) return NULL; 20 | PyObject *res = PyDict_GetItemString (o, name); 21 | if (!res || res == Py_None) return NULL; 22 | return strdup (PyUnicode_AsUTF8 (res)); 23 | } 24 | 25 | st64 getI(PyObject *o, const char *name) { 26 | if (!o) return 0; 27 | PyObject *res = PyDict_GetItemString (o, name); 28 | if (!res || res == Py_None) return 0; 29 | return (st64) PyNumber_AsSsize_t (res, NULL); 30 | } 31 | 32 | void *getF(PyObject *o, const char *name) { 33 | if (!o || o == Py_None) return NULL; 34 | return PyDict_GetItemString (o, name); 35 | } 36 | 37 | bool getB(PyObject *o, const char *name) { 38 | if (!o || o == Py_None) return NULL; 39 | if (PyObject_IsTrue (o)) return true; 40 | return false; 41 | } -------------------------------------------------------------------------------- /tcl/tkhello.tcl: -------------------------------------------------------------------------------- 1 | package require Tk 2 | 3 | # source "/tmp/colorutils.tcl" 4 | # source "/tmp/awthemes.tcl" 5 | # source "/tmp/awclearlooks.tcl" 6 | # source "/tmp/awblack.tcl" 7 | 8 | # proc r2cmd {} { return "" } 9 | 10 | set ver [r2cmd "?V"] 11 | 12 | ########### label 13 | set msg [r2cmd "?e Hello From radare2"] 14 | label .hello -text "$msg\n$ver" -anchor w 15 | pack .hello -fill x -expand true 16 | 17 | ########### textarea 18 | text .txt -width 40 -height 10 19 | pack .txt -side top -fill both -expand true 20 | 21 | ########### button 22 | proc hello_world {} { 23 | .txt insert end "console.log('Hello World');\n" 24 | } 25 | button .hello_btn -text "Say Hello" -command hello_world 26 | pack .hello_btn -side left -padx 10 -pady 10 27 | 28 | ########### runscript button 29 | 30 | proc run_script {} { 31 | set contents [.txt get 1.0 end] 32 | set script [r2cmd "'?b64 $contents"] 33 | puts "Running $script" 34 | r2cmd "'js base64:$script" 35 | } 36 | 37 | button .run_btn -text "Run" -command run_script 38 | pack .run_btn -side right -padx 9 -pady 10 39 | 40 | # stop script when window is closed. thats what wish do 41 | proc onWindowClose {} { 42 | set ::done 1 43 | destroy . 44 | # exit 45 | } 46 | 47 | wm protocol . WM_DELETE_WINDOW onWindowClose 48 | set done 0 49 | # mainloop 50 | vwait ::done 51 | -------------------------------------------------------------------------------- /ruby/mkruby.rb: -------------------------------------------------------------------------------- 1 | # setup with ruby! 2 | 3 | rb_so = 'lang_ruby.so' 4 | rb_c = 'ruby.c' 5 | rb_o = 'ruby.o' 6 | inc = '../../include' 7 | 8 | require 'mkmf' 9 | # TODO. those Config::CONFIG things doesnt seems to work with latest ruby 10 | INCDIR = "" # Config::CONFIG['rubylibdir'] + "/"+Config::CONFIG['arch'] 11 | LIBDIR = "" # Config::CONFIG['LIBRUBY_ARG_SHARED'] 12 | #LIBS = Config::CONFIG['LIBS'] -lpthread... 13 | LIBNAM = "ruby" # Config::CONFIG['RUBY_INSTALL_NAME'] 14 | #LDSHARED=compilername -shared..." 15 | 16 | if ARGV[0] != nil; rb_c = ARGV[0] end 17 | if ARGV[1] != nil; rb_so = ARGV[1] end 18 | if ARGV[2] != nil; inc = ARGV[2] end 19 | 20 | $cc=ENV["CC"] 21 | if $cc == nil then 22 | $cc="cc" 23 | end 24 | 25 | tobeup=false 26 | begin 27 | d0 = File.stat(rb_so).mtime.to_i 28 | d1 = File.stat(rb_c).mtime.to_i 29 | if d1 > d0 then 30 | tobeup=true 31 | end 32 | rescue 33 | tobeup=true 34 | end 35 | 36 | def runline(line) 37 | puts line 38 | system(line) 39 | end 40 | 41 | if tobeup then 42 | # runline("#{$cc} -I #{inc} -I#{INCDIR} #{rb_c} -fPIC -c #{LIBDIR}" \ 43 | # " -l#{LIBNAM} #{ENV['CFLAGS']} #{ENV['LDFLAGS']} -o #{rb_o}") 44 | runline("#{$cc} -I #{inc} -I#{INCDIR} #{rb_c} -fPIC -shared #{LIBDIR}" \ 45 | " -l#{LIBNAM} #{ENV['CFLAGS']} #{ENV['LDFLAGS']} -o #{rb_so}") 46 | end 47 | exit 0 48 | -------------------------------------------------------------------------------- /vlang/README.md: -------------------------------------------------------------------------------- 1 | Vlang support for Rlang 2 | ======================= 3 | 4 | This plugin allows you to run V scripts inside r2: 5 | 6 | ```go 7 | $ cat example.v 8 | import os 9 | 10 | pub fn entry(core &R2) { 11 | println("simple hello") 12 | println(core.cmd('?E hello')) 13 | os.system('echo world') 14 | } 15 | ``` 16 | 17 | Then you can run it like this: 18 | 19 | ``` 20 | $ r2 -i example.v - 21 | hello 22 | .--. .-------. 23 | | _| | | 24 | | O O < hello | 25 | | | | | | 26 | || | / `-------' 27 | |`-'| 28 | `---' 29 | 30 | world 31 | [0x00000000]> q 32 | ``` 33 | 34 | Pending stuff: 35 | -------------- 36 | 37 | * [ ] Support cmdj() with x.json2 or so 38 | * [ ] Basic r2pipe-api on top of it 39 | * [x] Support writing core plugins in V-rlang 40 | 41 | Core plugins in V 42 | ----------------- 43 | 44 | Register a core plugin from V so that it can handle commands entered in r2: 45 | 46 | ``` 47 | // vlang/tests/test-core-vlang.v 48 | pub fn vcore_call(core &R2, input byteptr) bool { 49 | unsafe { 50 | if input.vstring() == 'vhello' { 51 | println(core.cmd('x 16 @ $$')) 52 | println('Hello from V core plugin!') 53 | return true 54 | } 55 | } 56 | return false 57 | } 58 | 59 | pub fn entry(core &R2) { 60 | _ = core.register_core('vcoretest', vcore_call, 'Example core plugin written in V', 'MIT') 61 | } 62 | 63 | // Run: r2 -qi vlang/tests/test-core-vlang.v -c vhello - 64 | ``` 65 | -------------------------------------------------------------------------------- /go/radare2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | GENERATOR: 3 | PackageName: radare2 4 | PackageDescription: "Package radare2 provides Go bindings for radare2." 5 | PackageLicense: "LGPLv2" 6 | FlagGroups: 7 | - {name: LDFLAGS, flags: [-lr_core]} 8 | SysIncludes: 9 | - r_core.h 10 | 11 | PARSER: 12 | Arch: arm 13 | SourcesPaths: 14 | - r_core.h 15 | IncludePaths: 16 | # NOTE: Replace these paths if you want to re-generate. 17 | - ../../radare2/libr/include 18 | - /usr/local/include/libr 19 | - /usr/include/libr 20 | Defines: 21 | R2_GO: {} 22 | 23 | TRANSLATOR: 24 | ConstRules: 25 | defines: expand 26 | enum: expand 27 | PtrTips: 28 | function: 29 | - {target: ^r_*$, tips: [0,arr,size,ref]} 30 | TypeTips: 31 | type: 32 | - {target: R*$, self: plain} 33 | function: 34 | - {target: ^r_$, self: plain} 35 | Rules: 36 | global: 37 | - {action: accept, from: "^R_API"} 38 | - {action: replace, from: "^EGL"} 39 | function: 40 | - {action: accept, from: ^r_} 41 | - {action: replace, from: ^r_} 42 | - {action: ignore, from: ^_} 43 | type: 44 | - {action: replace, from: "_t$"} 45 | const: 46 | - {action: ignore, from: R2_DEFAULT_DISPLAY} 47 | - {transform: lower} 48 | private: 49 | - {transform: unexport} 50 | post-global: 51 | - {action: doc, from: "^egl", to: "https://www.radare.org"} 52 | - {transform: export} 53 | - {load: snakecase} 54 | -------------------------------------------------------------------------------- /guile/plugin.c: -------------------------------------------------------------------------------- 1 | /* lang.guile plugin for r2 - 2022-2023 - pancake */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static R_TH_LOCAL RCore *Gcore = NULL; 9 | 10 | static SCM r2cmd_wrapper(SCM x) { 11 | size_t len = 0; 12 | char *cmd = scm_to_utf8_stringn (x, &len); 13 | char *res = r_core_cmd_str (Gcore, cmd); 14 | free (cmd); 15 | return scm_from_utf8_stringn (res, strlen (res)); 16 | } 17 | 18 | static bool runstr(RLangSession *s, const char *code, int len) { 19 | scm_c_eval_string (code); 20 | return false; 21 | } 22 | 23 | static int runfile(RLangSession *s, const char *file) { 24 | char *data = r_file_slurp (file, NULL); 25 | if (data) { 26 | scm_c_eval_string (data); 27 | free (data); 28 | } 29 | return 0; 30 | } 31 | 32 | static bool init(RLangSession *s) { 33 | if (s == NULL) { 34 | return true; 35 | } 36 | int argc = 0; 37 | Gcore = s->lang->user; 38 | char **argv = NULL; 39 | scm_init_guile (); 40 | scm_c_define_gsubr ("r2cmd", 1, 0, 0, r2cmd_wrapper); 41 | return true;; 42 | } 43 | 44 | static RLangPlugin r_lang_plugin_guile = { 45 | .meta = { 46 | .name = "guile", 47 | .license = "LGPL", 48 | .desc = "GUILE", 49 | .author = "pancake" 50 | }, 51 | .ext = "scm", 52 | .init = (void*)init, 53 | .run = runstr, 54 | .run_file = (void*)runfile, 55 | }; 56 | 57 | #ifndef CORELIB 58 | RLibStruct radare_plugin = { 59 | .type = R_LIB_TYPE_LANG, 60 | .data = &r_lang_plugin_guile, 61 | }; 62 | #endif 63 | -------------------------------------------------------------------------------- /python/examples/test-py-io.py: -------------------------------------------------------------------------------- 1 | # Example Python IO plugin written in Python 2 | # =========================================== 3 | # 4 | # -- pancake @ nopcode.org 5 | # 6 | # Usage: 7 | # r2 -I test-py-io.py pyio://33 8 | # 9 | # The r2lang.plugin function exposes a way to register new plugins 10 | # into the RCore instance. This API is only available from RLang. 11 | 12 | import r2lang 13 | 14 | FAKESIZE = 512 15 | 16 | def pyio(a): 17 | def _open(path, rw, perm): 18 | print("MyPyIO Opening %s"%(path)) 19 | return "pyio-data" 20 | def _check(path, many): 21 | print("python-check %s"%(path)) 22 | return path[0:7] == "pyio://" 23 | def _read(data, size): 24 | print("python-read") 25 | return "A" * size 26 | def _seek(data, offset, whence): 27 | print("python-seek") 28 | if whence == 0: # SET 29 | return offset 30 | if whence == 1: # CUR 31 | return offset 32 | if whence == 2: # END 33 | return 512 34 | return 512 35 | def _write(data, buf, size): 36 | print("python-write") 37 | return True 38 | def _system(data, cmd): 39 | print("python-SYSTEM %s"%(cmd)) 40 | return True 41 | def _close(data): 42 | print(data) 43 | print("python-close") 44 | return 0 45 | return { 46 | "name": "pyio", 47 | "license": "GPL", 48 | "desc": "IO plugin in python (pyio://3)", 49 | "check": _check, 50 | "open": _open, 51 | "read": _read, 52 | "seek": _seek, 53 | "write": _write, 54 | "system": _system, 55 | "close": _close, 56 | } 57 | 58 | print("Registering Python IO plugin...") 59 | print(r2lang.plugin("io", pyio)) 60 | -------------------------------------------------------------------------------- /python/examples/test-py-io2.py: -------------------------------------------------------------------------------- 1 | # Example Python IO plugin written in Python 2 | # =========================================== 3 | # 4 | # -- pancake @ nopcode.org 5 | # 6 | # Usage: 7 | # r2 -I test-py-io.py pyio://33 8 | # 9 | # The r2lang.plugin function exposes a way to register new plugins 10 | # into the RCore instance. This API is only available from RLang. 11 | 12 | import r2lang 13 | 14 | FAKESIZE = 100 15 | 16 | def pyio(a): 17 | def _open(path, rw, perm): 18 | print("MyPyIO2 Opening %s"%(path)) 19 | return "pyio-data" 20 | def _check(path, many): 21 | print("python-check %s"%(path)) 22 | return path[0:8] == "pyio2://" 23 | def _read(data, size): 24 | print("python-read") 25 | return "B" * size 26 | def _seek(data, offset, whence): 27 | print("python-seek") 28 | if whence == 0: # SET 29 | return offset 30 | if whence == 1: # CUR 31 | return offset 32 | if whence == 2: # END 33 | return FAKESIZE 34 | return FAKESIZE 35 | def _write(data, buf, size): 36 | print("python-write") 37 | return True 38 | def _system(data, cmd): 39 | print("python-SYSTEM %s"%(cmd)) 40 | return True 41 | def _close(data): 42 | print(data) 43 | print("python-close") 44 | return 0 45 | return { 46 | "name": "pyio2", 47 | "license": "GPL", 48 | "desc": "IO plugin in python (pyio2://3)", 49 | "check": _check, 50 | "open": _open, 51 | "read": _read, 52 | "seek": _seek, 53 | "write": _write, 54 | "system": _system, 55 | "close": _close, 56 | } 57 | 58 | print("Registering Python IO plugin...") 59 | print(r2lang.plugin("io", pyio)) 60 | -------------------------------------------------------------------------------- /lua/examples/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Sergi Alvarez" 4 | }, 5 | "engines": { 6 | "node": ">=16", 7 | "npm": ">=8.6.0" 8 | }, 9 | "scripts": { 10 | "semi": "semistandard", 11 | "indent": "semistandard --fix bin/*.js lib/*.js *.js", 12 | "unzip-lzfse": "git clone https://github.com/sskaje/unzip-lzfse ; cd unzip-lzfse ; chmod +x unix/configure ; LZFSE_PATH=/usr/local make -f unix/Makefile CF='-DUSE_LZFSE=1 -c -O3 -Wall -DBSD -I. -Ibzip2 -DUNIX' LF2=-llzfse all", 13 | "test": "mocha", 14 | "dist": "./dist.sh", 15 | "dist-all": "./dist.sh macos linux freebsd alpine win" 16 | }, 17 | "devDependencies": { 18 | "castl": "*", 19 | "npm": "^8.6.0", 20 | "pkg": "5.6.0", 21 | "semistandard": "^16.0.1" 22 | }, 23 | "dependencies": { 24 | "colors": "1.4.0", 25 | "tstl": "^2.5.13", 26 | "typescript-to-lua": "^1.11.1" 27 | }, 28 | "overrides": { 29 | "plist": "github:TooTallNate/plist.js#e17373ef96510a606b62553bd28845842133ba12" 30 | }, 31 | "files": [ 32 | "index.ts", 33 | "README.md", 34 | "dist.sh" 35 | ], 36 | "description": "API to resign IPA files", 37 | "homepage": "https://www.radare.org", 38 | "license": "MIT", 39 | "main": "index.js", 40 | "maintainers": [ 41 | { 42 | "name": "Sergi Alvarez", 43 | "email": "pancake@nopcode.org" 44 | } 45 | ], 46 | "semistandard": { 47 | "globals": [ 48 | "describe", 49 | "context", 50 | "before", 51 | "beforeEach", 52 | "after", 53 | "afterEach", 54 | "it", 55 | "expect" 56 | ] 57 | }, 58 | "name": "r2lua", 59 | "version": "4.1.0" 60 | } 61 | -------------------------------------------------------------------------------- /vlang/tests/out_core.txt: -------------------------------------------------------------------------------- 1 | .tmp.v:54:14: error: unknown method or field: `r2v.R2.register_core`. 2 | 3 possibilities: `cmd`, `free`, `str`. 3 | 52 | pub fn entry(core &R2) { 4 | 53 | // name, callback, desc, license 5 | 54 | _ = core.register_core('vcoretest', vcore_call, 'Example core plugin written in V', 'MIT') 6 | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 55 | } 8 | 56 | 9 | .tmp.v:54:7: error: assignment mismatch: 1 variable but `register_core()` returns 0 values 10 | 52 | pub fn entry(core &R2) { 11 | 53 | // name, callback, desc, license 12 | 54 | _ = core.register_core('vcoretest', vcore_call, 'Example core plugin written in V', 'MIT') 13 | | ^ 14 | 55 | } 15 | 56 | 16 | If the code of your project is in multiple files, try with `v .` instead of `v .tmp.v` 17 | .tmp.v:54:14: error: unknown method or field: `r2v.R2.register_core`. 18 | 3 possibilities: `cmd`, `free`, `str`. 19 | 52 | pub fn entry(core &R2) { 20 | 53 | // name, callback, desc, license 21 | 54 | _ = core.register_core('vcoretest', vcore_call, 'Example core plugin written in V', 'MIT') 22 | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | 55 | } 24 | 56 | 25 | .tmp.v:54:7: error: assignment mismatch: 1 variable but `register_core()` returns 0 values 26 | 52 | pub fn entry(core &R2) { 27 | 53 | // name, callback, desc, license 28 | 54 | _ = core.register_core('vcoretest', vcore_call, 'Example core plugin written in V', 'MIT') 29 | | ^ 30 | 55 | } 31 | 56 | 32 | If the code of your project is in multiple files, try with `v .` instead of `v .tmp.v` 33 | ERROR: Panel mode requires scr.interactive=true 34 | -------------------------------------------------------------------------------- /lua/lib/r2api.lua: -------------------------------------------------------------------------------- 1 | -- require"json" 2 | -- local inspect = require"inspect" 3 | 4 | -- generic utilities 5 | function split(text, sep) 6 | sep = sep or "\n" 7 | text = chomp(text) 8 | local lines = {} 9 | local pos = 1 10 | while true do 11 | local b,e = text:find(sep, pos) 12 | if not b then table.insert(lines, text:sub(pos)) break end 13 | table.insert(lines, text:sub(pos,b-1)) 14 | pos = e + 1 15 | end 16 | return lines 17 | end 18 | function trim(text) 19 | if text == nil then return "" end 20 | text = string.gsub(text, " *$", "") 21 | text = string.gsub(text, "\n$", "") 22 | return string.gsub(text, "^ *", "") 23 | end 24 | 25 | -- r2api starts here 26 | 27 | r2 = {} 28 | function r2.cmd(x) 29 | return r2cmd(x) 30 | end 31 | 32 | function r2.cmdj(x) 33 | local res = trim(r2cmd(x)) 34 | if res[0] == "[" then assert("UFCK") end 35 | return json.decode(res) 36 | end 37 | function r2.getConfig(x) 38 | return r2cmd("e "..x) 39 | end 40 | function r2.setConfig(x, y) 41 | return r2cmd("e "..x.."="..y) 42 | end 43 | function r2.analyzeProgram() 44 | return r2cmd("aa") 45 | end 46 | function r2.functionBasicBlocks() 47 | return split(r2cmd("ablq"),"\n") 48 | end 49 | 50 | -- local inspect = require"inspect" 51 | function r2:ptr (at) 52 | o = {addr = trim(at)} -- create object if user does not provide one 53 | setmetatable(o, self) 54 | self.__index = self 55 | o.readBytes = function(self, n) 56 | return json.decode(r2cmd("p8j "..n.."@"..o.addr)) 57 | end 58 | o.instruction = function(self) 59 | return json.decode(r2cmd("aoj@"..o.addr.."~{[0]}")) 60 | end 61 | o.add = function(self, x) 62 | o.addr = trim(r2cmd("?v "..o.addr.."+"..x)) 63 | return self 64 | end 65 | return o 66 | end 67 | 68 | function hex(x) 69 | return string.format("0x%08x", x) 70 | end 71 | -------------------------------------------------------------------------------- /python/examples/test-py-anal.py: -------------------------------------------------------------------------------- 1 | # Example Python Anal plugin written in Python 2 | # ============================================ 3 | # 4 | # -- pancake @ nopcode.org 5 | # 6 | # The r2lang.plugin function exposes a way to register new plugins 7 | # into the RCore instance. This API is only available from RLang. 8 | # You must call with with '#!python test.py' or 'r2 -i test.py ..' 9 | 10 | import r2lang 11 | from r2lang import R 12 | 13 | def pyanal(a): 14 | def set_reg_profile(): 15 | return "=PC pc\n" + \ 16 | "=SP sp\n" + \ 17 | "gpr r0 .32 0 0\n" + \ 18 | "gpr r1 .32 4 0\n" + \ 19 | "gpr r2 .32 8 0\n" + \ 20 | "gpr r3 .32 12 0\n" + \ 21 | "gpr r4 .32 16 0\n" + \ 22 | "gpr r5 .32 20 0\n" + \ 23 | "gpr sp .32 24 0\n" + \ 24 | "gpr pc .32 28 0\n" 25 | 26 | def archinfo(query): 27 | if query == R.R_ANAL_ARCHINFO_MIN_OP_SIZE: 28 | return 2 29 | if query == R.R_ANAL_ARCHINFO_MAX_OP_SIZE: 30 | return 2 31 | if query == R.R_ANAL_ARCHINFO_INV_OP_SIZE: # invalid op size 32 | return 2 33 | if query == R.R_ANAL_ARCHINFO_ALIGN: 34 | return 2 35 | if query == R.R_ANAL_ARCHINFO_DATA_ALIGN: 36 | return 2 37 | return 0 38 | 39 | def analop(buf, pc): 40 | op = { 41 | "type" : R.R_ANAL_OP_TYPE_NULL, 42 | "cycles" : 0, 43 | "stackop" : 0, 44 | "stackptr" : 0, 45 | "ptr" : -1, 46 | "jump" : -1, 47 | "addr" : 0, 48 | "eob" : False, 49 | "esil" : "", 50 | } 51 | return [ 2, op ] 52 | 53 | return { 54 | "name": "MyPyAnal", 55 | "arch": "pyarch", 56 | "bits": 32, 57 | "license": "GPL", 58 | "desc": "anal plugin in python", 59 | "set_reg_profile": set_reg_profile, 60 | "archinfo": archinfo, 61 | "op": analop, 62 | } 63 | 64 | if not r2lang.plugin("anal", pyanal): 65 | print("Failed to register the python anal plugin.") 66 | 67 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create release from numeric tag on master 2 | 3 | on: 4 | push: 5 | # Trigger for tags that start with a number (e.g. 1.0.0, 2025-01) 6 | tags: 7 | - '[0-9]*' 8 | 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repository (full history) 14 | uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Resolve tag and commit 19 | run: | 20 | echo "GITHUB_REF=$GITHUB_REF" 21 | TAG=${GITHUB_REF#refs/tags/} 22 | echo "TAG=$TAG" >> $GITHUB_ENV 23 | COMMIT=$(git rev-list -n 1 "$TAG") 24 | echo "COMMIT=$COMMIT" >> $GITHUB_ENV 25 | 26 | - name: Fetch remote master 27 | run: git fetch origin master:refs/remotes/origin/master 28 | 29 | - name: Verify tag commit is on master 30 | id: verify_on_master 31 | run: | 32 | if git merge-base --is-ancestor "$COMMIT" origin/master; then 33 | echo "on_master=true" >> $GITHUB_OUTPUT 34 | else 35 | echo "on_master=false" >> $GITHUB_OUTPUT 36 | fi 37 | 38 | - name: Exit if tag is not on master 39 | if: steps.verify_on_master.outputs.on_master != 'true' 40 | run: | 41 | echo "Tag commit $COMMIT is not contained in origin/master. Skipping release." 42 | exit 0 43 | 44 | - name: Create GitHub release 45 | uses: actions/create-release@v1 46 | with: 47 | tag_name: ${{ env.TAG }} 48 | release_name: ${{ env.TAG }} 49 | body: "Automatic release for tag ${{ env.TAG }}" 50 | draft: false 51 | prerelease: false 52 | env: 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | 55 | -------------------------------------------------------------------------------- /vlang/tests/out.txt: -------------------------------------------------------------------------------- 1 | ================== C compilation error (from cc): ============== 2 | cc: | ^ 3 | cc: /tmp/v_501/.tmp.01K4AJCKY92DPN9GD9QV518A3H.tmp.so.c:18264:9: error: call to undeclared function 'r2v_register_core'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 4 | cc: 18264 | return r2v_register_core(name.str, (voidptr)call, desc.str, license.str); 5 | cc: | ^ 6 | cc: /tmp/v_501/.tmp.01K4AJCKY92DPN9GD9QV518A3H.tmp.so.c:18264:9: note: did you mean 'r2v__R2_register_core'? 7 | cc: /tmp/v_501/.tmp.01K4AJCKY92DPN9GD9QV518A3H.tmp.so.c:18263:6: note: 'r2v__R2_register_core' declared here 8 | cc: 18263 | bool r2v__R2_register_core(r2v__R2* core, string name, bool (*call)(r2v__R2* , byteptr ), string desc, string license) { 9 | cc: | ^ 10 | cc: 18264 | return r2v_register_core(name.str, (voidptr)call, desc.str, license.str); 11 | cc: | ~~~~~~~~~~~~~~~~~ 12 | cc: | r2v__R2_register_core 13 | cc: /tmp/v_501/.tmp.01K4AJCKY92DPN9GD9QV518A3H.tmp.so.c:18268:30: warning: incompatible pointer types passing 'r2v__R2 *' (aka 'struct r2v__R2 *') to parameter of type 'RCore *' (aka 'struct r_core_t *') [-Wincompatible-pointer-types] 14 | ... 15 | cc: 8 warnings and 1 error generated. 16 | (note: the original output was 64 lines long; it was truncated to its first 12 lines + the last line) 17 | ================================================================ 18 | (You can pass `-cg`, or `-show-c-output` as well, to print all the C error messages). 19 | builder error: 20 | ================== 21 | C error found. It should never happen, when compiling pure V code. 22 | This is a V compiler bug, please report it using `v bug file.v`, 23 | or goto https://github.com/vlang/v/issues/new/choose . 24 | You can also use #help on Discord: https://discord.gg/vlang . 25 | -------------------------------------------------------------------------------- /python/build.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(OSTYPE),windows) 2 | lang_python.${EXT_SO}: 3 | ${CC} ${CFLAGS} -I${HOME}/.wine/drive_c/Python37/include \ 4 | -L${HOME}/.wine/drive_c/Python37/libs \ 5 | $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --cflags --libs r_reg r_core r_cons) \ 6 | ${LDFLAGS_LIB} -o lang_python.${EXT_SO} python.c -lpython37 7 | else 8 | # Prefer local radare2 headers and pkg-config if available 9 | R2SRC?=./radare2 10 | R2_LOCAL_INC:=$(R2SRC)/libr/include 11 | R2_LOCAL_PKG1:=$(R2SRC)/libr/pkgconfig 12 | R2_LOCAL_PKG2:=$(R2SRC)/pkgcfg 13 | 14 | PYCFLAGS=$(shell PYVER=3 ./python-config-wrapper --includes) -DPYVER=3 15 | # Python3.8+ requires new `--embed` flag to include `-lpython`. 16 | PYLDFLAGS=$(shell PYVER=3 ./python-config-wrapper --libs --embed || \ 17 | PYVER=3 ./python-config-wrapper --libs) 18 | PYLDFLAGS+=$(shell PYVER=3 ./python-config-wrapper --ldflags) 19 | PYLDFLAGS+=${LDFLAGS_LIB} 20 | 21 | # Add local radare2 headers if present 22 | CFLAGS+=-g 23 | ifneq (,$(wildcard $(R2_LOCAL_INC)/r_core.h)) 24 | CFLAGS+=-I$(R2_LOCAL_INC) 25 | endif 26 | CFLAGS+=$(PYCFLAGS) 27 | CFILES=python.c 28 | ifeq ($(shell pkg-config --max-version 5.8.8 r_core && echo 1),1) 29 | CFILES+=anal.c asm.c bin.c 30 | endif 31 | CFILES+=python/common.c python/core.c python/io.c python/arch.c 32 | OFILES=$(subst .c,.o,${CFILES}) 33 | 34 | lang_python.$(EXT_SO): $(OFILES) 35 | ${CC} $(CFILES) ${CFLAGS} ${PYLDFLAGS} \ 36 | $(shell PKG_CONFIG_PATH="$(R2_LOCAL_PKG1):$(R2_LOCAL_PKG2):$(PKG_CONFIG_PATH)" pkg-config --cflags --libs r_reg r_core r_cons) \ 37 | ${LDFLAGS} ${LDFLAGS_LIB} -fPIC -o lang_python.$(EXT_SO) 38 | endif 39 | 40 | py python: 41 | rm -f lang_python.$(EXT_SO) 42 | $(MAKE) lang_python.$(EXT_SO) 43 | 44 | py-clean: 45 | rm -f python.o lang_python.$(EXT_SO) 46 | 47 | py-install python-install: 48 | mkdir -p ${R2PM_PLUGDIR} 49 | cp -f lang_python.$(EXT_SO) ${R2PM_PLUGDIR} 50 | 51 | py-uninstall python-uninstall: 52 | rm -f ${R2PM_PLUGDIR}/lang_python.$(EXT_SO) 53 | -------------------------------------------------------------------------------- /wasm3/zig/src/main.zig: -------------------------------------------------------------------------------- 1 | const wasm3 = @import("wasm3"); 2 | const std = @import("std"); 3 | // const r2 = @import("r2.zig"); 4 | 5 | const kib = 1024; 6 | const mib = 1024 * kib; 7 | const gib = 1024 * mib; 8 | 9 | fn r2pipe(core: *u8, cmd: *u8) void { 10 | _ = core; 11 | _ = cmd; 12 | } 13 | 14 | pub fn main() !void { 15 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 16 | defer _ = gpa.deinit(); 17 | 18 | var a = gpa.allocator(); 19 | 20 | // var args = try std.process.argsAlloc(a); 21 | // defer std.process.argsFree(a, args); 22 | // 23 | // if (args.len < 2) { 24 | // std.log.err("Please provide a wasm file on the command line!\n", .{}); 25 | // std.os.exit(1); 26 | // } 27 | // std.log.info("Loading wasm file {s}!\n", .{args[1]}); 28 | 29 | var env = wasm3.Environment.init(); 30 | defer env.deinit(); 31 | 32 | var rt = env.createRuntime(16 * kib, null); 33 | 34 | defer rt.deinit(); 35 | errdefer rt.printError(); 36 | var file = "hello.wasm"; 37 | 38 | var mod_bytes = try std.fs.cwd().readFileAlloc(a, file, 512 * kib); 39 | defer a.free(mod_bytes); 40 | var mod = try env.parseModule(mod_bytes); 41 | try rt.loadModule(mod); 42 | // try mod.linkRawFunction("r2", "cmd", "v(ss)", @ptrCast(*const anyopaque, &r2pipe)); 43 | try mod.linkWasi(); 44 | // if (true) { 45 | // try mod.linkLibrary("r2", struct { 46 | // pub inline fn add(_: *std.mem.Allocator, lh: i32, rh: i32) i32 { 47 | // return lh + rh; 48 | // } 49 | // pub inline fn sub(_: *std.mem.Allocator, lh: i32, rh: i32) i32 { 50 | // return lh - rh; 51 | // } 52 | // }, &a); 53 | // } 54 | 55 | var start_fn = try rt.findFunction("main"); 56 | std.log.info("finding {s}", .{"main"}); 57 | start_fn.call(void, .{}) catch |e| switch (e) { 58 | error.TrapExit => {}, 59 | else => return e, 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /vlang/example.v: -------------------------------------------------------------------------------- 1 | import json 2 | import x.json2 3 | 4 | fn (r2 &R2)once(k string) bool { 5 | if r2.cmd('fd once.$k') != '' { 6 | return true 7 | } 8 | r2.cmd('f once.$k=-123') 9 | return false 10 | } 11 | 12 | fn (r2 &R2)main() ? { 13 | arg := file_type(r2) 14 | println('File: ' + arg) 15 | arq := file_typ(r2) 16 | println('File2: '+arq) 17 | println(r2.cmd('?E hello')) 18 | r2.cmd('aaa') 19 | addrs := r2.function_addrs()? 20 | for at in addrs { 21 | fcn := r2.function_info(at)? 22 | println('--- ${fcn.name}') 23 | } 24 | 25 | fcns := r2.functions()? 26 | for fcn in fcns { 27 | fcnmap := fcn.as_map() 28 | name := fcnmap['name'] 29 | addr := fcnmap['offset'] 30 | println('$addr $name') 31 | } 32 | } 33 | 34 | pub fn entry(r2 &R2) { 35 | if r2.once('') { 36 | eprintln('dont run this script twice') 37 | return 38 | } 39 | r2.main() or { 40 | panic(err) 41 | } 42 | } 43 | 44 | // helper functions 45 | 46 | struct Core { 47 | t_pe string @[json: @type] 48 | file string 49 | } 50 | 51 | struct Function { 52 | addr u64 53 | name string 54 | } 55 | 56 | struct Info { 57 | core Core 58 | foo string 59 | } 60 | 61 | fn (f Function)str() string { 62 | return '$f.addr $f.name' 63 | } 64 | 65 | fn file_type(r2 &R2) string { 66 | mut s := r2.cmd('ij') 67 | y := json.decode(Info, s) or { 68 | return 'xx' 69 | } 70 | return y.core.file 71 | } 72 | 73 | fn (r2 &R2)function_addrs() ?[]u64 { 74 | mut s := r2.cmd('aflqj') 75 | y := json2.raw_decode(s)? 76 | return y.arr().map(u64(it.i64())) 77 | } 78 | 79 | fn (r2 &R2)function_info(addr u64) ?Function { 80 | eprintln('afij @ ${addr}') 81 | mut s := r2.cmd('afij @ ${addr}') 82 | y := json2.raw_decode(s)? 83 | a := y.arr() 84 | for item in a { 85 | f := item.as_map() 86 | return Function { 87 | name: f['name'].str() 88 | addr: addr 89 | } 90 | } 91 | return error('Cannot find function') 92 | } 93 | 94 | fn (r2 &R2)functions() ?[]json2.Any { 95 | mut s := r2.cmd('aflj') 96 | y := json2.raw_decode(s)? 97 | return y.arr() // map()['core'].as_map()['t_pe'].str() 98 | } 99 | 100 | fn file_typ(r2 &R2)string{ 101 | mut s := r2.cmd('ij') 102 | y := json2.raw_decode(s) or { 103 | return 'xx' 104 | } 105 | return y.as_map()['core'].as_map()['t_pe'].str() 106 | } 107 | 108 | -------------------------------------------------------------------------------- /ruby/ruby.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2009-2024 pancake */ 2 | /* ruby extension for libr (radare2) */ 3 | 4 | #include "r_lib.h" 5 | #include "r_lang.h" 6 | #include "ruby.h" 7 | 8 | // XXX 9 | //#define RUBYAPI LIBDIR"/ruby1.8/radare.rb" 10 | #define RUBYAPI "/usr/lib/radare2/"R2_VERSION"/radare.rb" 11 | 12 | #include "r_core.h" 13 | static struct r_core_t *core = NULL; 14 | 15 | static VALUE radare_ruby_cmd(VALUE self, VALUE string) { 16 | const char *retstr; 17 | Check_Type (string, T_STRING); 18 | retstr = r_core_cmd_str (core, RSTRING(string)->ptr); 19 | if (retstr == NULL || retstr[0]=='\0') 20 | return rb_str_new2 (""); 21 | return rb_str_new2 (retstr); 22 | } 23 | 24 | static bool run(RLangSession *user, const char *code, int len) { 25 | int err, ret = true; 26 | rb_eval_string_protect (code, &err); 27 | if (err != 0) { 28 | fprintf (stderr, "error %d handled\n", err); 29 | ret = false; 30 | } 31 | return ret; 32 | } 33 | 34 | static int slurp_ruby(const char *file) { 35 | if (r_file_exists (file)) { 36 | rb_load_file (file); 37 | ruby_exec (); 38 | return true; 39 | } 40 | eprintf ("lang_ruby: Cannot open '%s'\n", file); 41 | return false; 42 | } 43 | 44 | static int run_file(RLangSession *user, const char *file) { 45 | return slurp_ruby (file); 46 | } 47 | 48 | static bool init(RLangSession *user) { 49 | VALUE rb_RadareCmd; 50 | 51 | ruby_init (); 52 | ruby_init_loadpath (); 53 | 54 | rb_eval_string_protect ("require 'irb'", NULL); 55 | core = user; 56 | rb_RadareCmd = rb_define_class ("RadareInternal", rb_cObject); 57 | rb_define_method (rb_RadareCmd, "cmd", radare_ruby_cmd, 1); 58 | rb_eval_string_protect ("$r = RadareInternal.new()", NULL); 59 | 60 | if (!slurp_ruby (RUBYAPI)) { 61 | fprintf (stderr, "[ruby] error loading ruby api\n"); 62 | //return false; 63 | } 64 | return true; 65 | } 66 | 67 | static bool prompt(RLangSession *user) { 68 | int err; 69 | rb_eval_string_protect ("IRB.start();", &err); 70 | if (err != 0) 71 | return false; 72 | return true; 73 | } 74 | 75 | static bool fini(RLangSession *user) { 76 | ruby_finalize (); 77 | return true; 78 | } 79 | 80 | static const char *help = 81 | "Ruby plugin usage:\n" 82 | " $r = RadareInternal.new()\n" 83 | " bytes = $r.cmd(\"p8 10\");\n"; 84 | 85 | static struct r_lang_plugin_t r_lang_plugin_ruby = { 86 | .meta = { 87 | .name = "ruby", 88 | .desc = "Ruby language extension", 89 | }, 90 | .ext = "rb", 91 | .init = &init, 92 | .fini = &fini, 93 | .help = &help, 94 | .prompt = &prompt, 95 | .run = &run, 96 | .run_file = &run_file, 97 | .set_argv = NULL, 98 | }; 99 | 100 | #ifndef CORELIB 101 | struct r_lib_struct_t radare_plugin = { 102 | .type = R_LIB_TYPE_LANG, 103 | .data = &r_lang_plugin_ruby, 104 | }; 105 | #endif 106 | -------------------------------------------------------------------------------- /perl/perl.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2009-2024 - pancake, nibble */ 2 | /* perl extension for libr (radare2) */ 3 | 4 | #include "r_lib.h" 5 | #include "r_lang.h" 6 | 7 | #include 8 | #include 9 | #undef PL_madskills 10 | #undef PL_xmlfp 11 | #include 12 | 13 | #undef U32_MAX 14 | #undef U32_MIN 15 | 16 | #undef LIST_HEAD 17 | #include "r_core.h" 18 | 19 | static R_TH_LOCAL RCore *core = NULL; 20 | 21 | static R_TH_LOCAL PerlInterpreter *my_perl = NULL; 22 | 23 | static void perl_radare_cmd(pTHX_ CV* cv) { 24 | char *cmd; 25 | char *str; 26 | dXSARGS; 27 | cmd = sv_pv (ST (0)); 28 | str = r_core_cmd_str (core, cmd); 29 | ST(0) = newSVpvn (str, strlen(str)); 30 | free (str); 31 | XSRETURN (1); 32 | str = (char *)(size_t)items; /* dummy unreachable code */ 33 | } 34 | 35 | static void xs_init(pTHX) { 36 | newXS ("r", perl_radare_cmd, __FILE__); 37 | } 38 | 39 | static bool init(RLangSession *ls) { 40 | char *perl_embed[] = { "", "-e", "0" }; 41 | core = ls->lang->user; 42 | my_perl = perl_alloc (); 43 | if (!my_perl) { 44 | fprintf (stderr, "Cannot init perl module\n"); 45 | return false; 46 | } 47 | perl_construct (my_perl); 48 | perl_parse (my_perl, xs_init, 3, perl_embed, (char **)NULL); 49 | return true; 50 | } 51 | 52 | static int fini(void *user) { 53 | perl_destruct (my_perl); 54 | perl_free (my_perl); 55 | my_perl = NULL; 56 | return true; 57 | } 58 | 59 | static int run(void *user, const char *code, int len) { 60 | /* TODO: catcth errors */ 61 | eval_pv (code, TRUE); 62 | return true; 63 | } 64 | 65 | static int setargv(void *user, int argc, char **argv) { 66 | perl_parse (my_perl, xs_init, argc, argv, (char **)NULL); 67 | return true; 68 | } 69 | 70 | static bool setup(RLangSession *ls) { 71 | RListIter *iter; 72 | RLangDef *def; 73 | char cmd[128]; 74 | // Segfault if already initialized ? 75 | //PyRun_SimpleString ("require r2/r_core.pl"); 76 | #warning TODO: implement setup in lang/perl 77 | core = ls->lang->user; 78 | r_list_foreach (ls->lang->defs, iter, def) { 79 | if (!def->type || !def->name) { 80 | continue; 81 | } 82 | if (!strcmp (def->type, "int")) { 83 | snprintf (cmd, sizeof (cmd), "%s=%d", def->name, (int)(size_t)def->value); 84 | } else if (!strcmp (def->type, "string")) { 85 | snprintf (cmd, sizeof (cmd), "%s=\"%s\"", def->name, (char *)def->value); 86 | } else { 87 | snprintf (cmd, sizeof (cmd), "%s=%s.cast(%p)", 88 | def->name, def->type, def->value); 89 | } 90 | // PyRun_SimpleString (cmd); 91 | } 92 | return true; 93 | } 94 | 95 | static const char *help = 96 | "Perl plugin usage:\n" 97 | " print \"r(\"pd 10\")\\n\";\n"; 98 | 99 | static RLangPlugin r_lang_plugin_perl = { 100 | .meta = { 101 | .name = "perl", 102 | .desc = "Perl language extension", 103 | }, 104 | .ext = "pl", 105 | .init = init, 106 | .setup = setup, 107 | .fini = (void *)fini, 108 | .help = (void *)&help, 109 | .prompt = NULL, 110 | .run = (void *)&run, 111 | .run_file = NULL, 112 | .set_argv = (void *)setargv, 113 | }; 114 | 115 | #ifndef CORELIB 116 | RLibStruct radare_plugin = { 117 | .type = R_LIB_TYPE_LANG, 118 | .data = &r_lang_plugin_perl, 119 | }; 120 | #endif 121 | -------------------------------------------------------------------------------- /mujs/plugin.c: -------------------------------------------------------------------------------- 1 | /* lang.mujs plugin for r2 - 2022 - pancake */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "mujs/one.c" 7 | #include "jsapi.c" 8 | 9 | typedef struct { 10 | js_State *J; 11 | RLangSession *s; 12 | RCore *core; 13 | // in case we need to store more data 14 | } MujsContext; 15 | 16 | static bool mujs_run(RLangSession *s, const char *code, int len) { 17 | MujsContext *ctx = s->plugin_data; 18 | js_State *J = ctx->J; 19 | // char *nc = r_str_newf ("try { var res = (function(){%s;})(); if (res != undefined) { console.log(res); } } catch(e) { console.error(e); }", code); 20 | const char *echo = strstr (code, "=")? "": "if(res!=undefined){console.log(res);}"; 21 | char *nc = r_str_newf ("try { var res = (%s); %s } catch(e) { console.error(e); }", code, echo); 22 | js_dostring (J, nc); 23 | free (nc); 24 | return true; 25 | } 26 | 27 | static bool mujs_file(RLangSession *s, const char *file) { 28 | MujsContext *ctx = s->plugin_data; 29 | js_dofile (ctx->J, file); 30 | return true; 31 | } 32 | 33 | static void r2cmd(js_State *J) { 34 | MujsContext *ctx = J->uctx; 35 | const char *s = js_tostring (J, 1); 36 | if (s) { 37 | char *str = r_core_cmd_str (ctx->core, s); 38 | js_pushstring (J, str); 39 | free (str); 40 | } else { 41 | js_pushstring (J, ""); 42 | } 43 | } 44 | 45 | static void r2call(js_State *J) { 46 | MujsContext *ctx = J->uctx; 47 | const char *s = js_tostring (J, 1); 48 | if (s) { 49 | r_core_cmd_call (ctx->core, s); 50 | js_pushundefined (J); 51 | } else { 52 | js_error(J, "string expected %s: %s", s, strerror (errno)); 53 | } 54 | } 55 | 56 | static bool fini(RLangSession *s) { 57 | MujsContext *ctx = s->plugin_data; 58 | js_freestate (ctx->J); 59 | s->plugin_data = NULL; 60 | return true; 61 | } 62 | 63 | static void *init(RLangSession *s) { 64 | js_State *J = js_newstate (NULL, NULL, JS_STRICT); 65 | if (!J) { 66 | return NULL; 67 | } 68 | js_newcfunction (J, jsB_b64, "b64", 1); 69 | js_setglobal (J, "b64"); 70 | js_newcfunction (J, r2cmd, "r2cmd", 1); 71 | js_setglobal (J, "r2cmd"); 72 | js_newcfunction (J, r2call, "r2call", 1); 73 | js_setglobal (J, "r2call"); 74 | 75 | js_newcfunction (J, jsB_read, "readFileSync", 1); 76 | js_setglobal (J, "readFileSync"); 77 | js_newcfunction (J, jsB_write, "writeFileSync", 1); 78 | js_setglobal (J, "writeFileSync"); 79 | js_dostring (J, fs_js); 80 | 81 | js_dostring (J, r2_js); 82 | js_dostring (J, require_js); 83 | js_dostring (J, stacktrace_js); 84 | js_dostring (J, "var global = {}; var G = global;"); 85 | 86 | js_newcfunction (J, jsB_print, "print", 0); 87 | js_setglobal (J, "print"); 88 | js_dostring (J, console_js); 89 | 90 | js_newcfunction(J, jsB_gc, "gc", 0); 91 | js_setglobal(J, "gc"); 92 | 93 | MujsContext *ctx = R_NEW0 (MujsContext); 94 | if (ctx) { 95 | ctx->s = s; 96 | ctx->J = J; 97 | ctx->core = s->lang->user; 98 | J->uctx = ctx; 99 | } 100 | return ctx; 101 | } 102 | 103 | static RLangPlugin r_lang_plugin_mujs = { 104 | .name = "mujs", 105 | .ext = "mujs", 106 | .license = "MIT", 107 | .desc = "Ghostscripts mujs interpreter (ES5)", 108 | .run = mujs_run, 109 | .init = init, 110 | .fini = fini, 111 | .run_file = mujs_file, 112 | }; 113 | 114 | #ifndef CORELIB 115 | RLibStruct radare_plugin = { 116 | .type = R_LIB_TYPE_LANG, 117 | .data = &r_lang_plugin_mujs, 118 | }; 119 | #endif 120 | -------------------------------------------------------------------------------- /ruby/radare.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | Ruby API for radare scripting plugin 4 | 5 | author: pancake 6 | 7 | =end 8 | 9 | # This class is instantiated as $r = Radare.new() 10 | class Radare 11 | # helpers 12 | def str2hash(str) 13 | t = {} 14 | list = str.split("\n") 15 | list.each do |item| 16 | w = item.split("=") 17 | if w.size > 1 then 18 | t[w[0]]=w[1] 19 | end 20 | end 21 | return t 22 | end 23 | 24 | def hex2bin(str) 25 | return str.to_i(16).to_s(2) 26 | end 27 | 28 | def bin2hex(binstr) 29 | return binstr.to_i(2).to_s(16).upcase 30 | end 31 | 32 | def slurp_hexpair(file) 33 | # XXX readlines loads whole file on memory, bad karma 34 | return File.readlines(file).map { |l| l.rstrip } 35 | end 36 | 37 | def slurp(file) 38 | # XXX outputs scaped shit 39 | f = File.open(file) 40 | str = "" 41 | 42 | str = bin2hex(f.read) 43 | # f.each_line do |l| 44 | # l.strip! 45 | # str.concat(bin2hex(l)) 46 | # end 47 | 48 | return str 49 | end 50 | 51 | # core 52 | 53 | def seek(addr) 54 | $r.cmd("s %s"%addr) 55 | end 56 | 57 | # code 58 | def comment_add(addr, str) 59 | $r.cmd("CC #{str} @ 0x%08"PFMT64x""%addr) 60 | end 61 | 62 | def comment_del(str) 63 | $r.cmd("CC -#{str}"); 64 | end 65 | 66 | def analyze_opcode(addr) 67 | begin 68 | return str2hash($r.cmd("ao @ 0x%08x"%addr)) 69 | rescue 70 | return str2hash($r.cmd("ao @ #{addr}")) 71 | end 72 | end 73 | 74 | def analyze_block(addr) 75 | begin 76 | return str2hash($r.cmd("ab")) 77 | rescue 78 | return str2hash($r.cmd("ab @ 0x%x"%addr)) 79 | end 80 | end 81 | 82 | def endian_set(big) 83 | $r.cmd("eval cfg.bigendian=%d"%big) 84 | end 85 | 86 | def write(hexpair) 87 | $r.cmd("wx %s"%hexpair) 88 | end 89 | 90 | def write_asm(opcode) 91 | $r.cmd("wa %s"%opcode) 92 | end 93 | 94 | def write_string(str) 95 | $r.cmd("w %s"%str) 96 | end 97 | 98 | def write_wide_string(str) 99 | $r.cmd("ww %s"%str) 100 | end 101 | 102 | 103 | def write_from_file(file) 104 | $r.cmd("wf %s"%file) 105 | end 106 | 107 | def write_from_hexpair_file(file) 108 | $r.cmd("wF %s"%file) 109 | end 110 | 111 | def seek_undo() 112 | r.cmd("undo") 113 | end 114 | 115 | def seek_redo() 116 | r.cmd("uu") 117 | end 118 | 119 | =begin 120 | XXX 121 | def seek_history() 122 | ret = [] 123 | list = r.cmd("u*").split("\n") 124 | for i in range(1, len(list)): 125 | w = list[i].split(" ") 126 | if len(w) > 3: 127 | t = {} 128 | t["addr"] = w[0].strip() 129 | ret.append(t) 130 | return ret 131 | end 132 | =end 133 | 134 | def seek_history_reset() 135 | r.cmd("u!") 136 | end 137 | 138 | def write_undo(num) 139 | return r.cmd("uw %d"%num) 140 | end 141 | 142 | def write_redo(num) 143 | return r.cmd("uw -%d"%num) 144 | end 145 | 146 | =begin 147 | XXX 148 | def write_history() 149 | ret = [] 150 | list = r.cmd("wu").split("\n") 151 | for i in range(1, len(list)): 152 | w = list[i].split(" ") 153 | if len(w) > 3: 154 | t = {} 155 | t["size"] = long(w[2].strip(),10) 156 | t["addr"] = long(w[3].strip(),16) 157 | # TODO moar nfo here 158 | ret.append(t) 159 | return ret 160 | # debugger 161 | end 162 | =end 163 | 164 | def step(addr) 165 | $r.cmd("!step") 166 | end 167 | 168 | def continue() 169 | $r.cmd("!cont") 170 | end 171 | 172 | def until(addr) 173 | $r.cmd("!cont #{addr}") 174 | end 175 | 176 | def quit() 177 | $r.cmd("q!") 178 | end 179 | 180 | end 181 | -------------------------------------------------------------------------------- /python/stubs/radare_stubs.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, List, Dict, Union 2 | 3 | def hex2bin(s: str) -> bytes: ... 4 | def bin2hex(binstr: bytes) -> bytes: ... 5 | def slurp_hexpair(file: str) -> str: ... 6 | def slurp(file: str) -> bytes: ... 7 | def analyze_opcode(addr: Optional[int] = None) -> Dict[str, Union[int, str]]: ... 8 | def analyze_block(addr: Optional[int] = None) -> Dict[str, Union[int, str]]: ... 9 | def endian_set(big: bool) -> None: ... 10 | def write(hexpair: str) -> None: ... 11 | def write_asm(opcode: str) -> None: ... 12 | def write_string(s: str) -> None: ... 13 | def write_wide_string(s: str) -> None: ... 14 | def write_from_file(file: str) -> None: ... 15 | def write_from_hexpair_file(file: str) -> None: ... 16 | def seek_undo() -> None: ... 17 | def seek_redo() -> None: ... 18 | def seek_history() -> List[Dict[str, str]]: ... 19 | def seek_history_reset() -> None: ... 20 | def write_undo(num: int) -> str: ... 21 | def write_redo(num: int) -> str: ... 22 | def write_history() -> List[Dict[str, Union[int, str]]]: ... 23 | def flag_space_set(name: str) -> None: ... 24 | def flag_list(mask: str) -> List[Dict[str, Union[int, str]]]: ... 25 | def flag_set(name: str, addr: Optional[int] = None) -> None: ... 26 | def flag_rename(old_name: str, new_name: str) -> None: ... 27 | def flag_unset(name: str) -> None: ... 28 | def flag_get(name: str) -> str: ... 29 | def meta_comment_add(msg: str) -> None: ... 30 | def type_code(length: int) -> None: ... 31 | def type_data(length: int) -> None: ... 32 | def type_string(length: int) -> None: ... 33 | def copy(num: int, addr: Optional[int] = None) -> None: ... 34 | def paste(num: int, addr: Optional[int] = None) -> None: ... 35 | def asm(opcode: str) -> str: ... 36 | def dis(num: int, addr: Optional[int] = None) -> str: ... 37 | def str(addr: Optional[int] = None) -> str: ... 38 | def dword(num: int, addr: Optional[int] = None) -> str: ... 39 | def word(num: int, addr: Optional[int] = None) -> str: ... 40 | def half(num: int, addr: Optional[int] = None) -> str: ... 41 | def hex(num: int, addr: Optional[int] = None) -> str: ... 42 | def eval_get(key: str) -> str: ... 43 | def eval_set(key: str, value: str) -> None: ... 44 | def eval_hash_get() -> Dict[str, str]: ... 45 | def eval_hash_set(hash: Dict[str, str]) -> None: ... 46 | def get_byte(addr: int) -> str: ... 47 | def write_to_files(file: str, size: int) -> None: ... 48 | def seek(addr: Union[int, str]) -> None: ... 49 | def cmp(hexpairs: str, addr: int) -> None: ... 50 | def cmp_file(file: str, addr: int) -> None: ... 51 | def dbg_attach(pid: int) -> None: ... 52 | def dbg_detach(pid: int) -> None: ... 53 | def dbg_continue() -> None: ... 54 | def dbg_step(num: int) -> None: ... 55 | def dbg_step_over(num: int) -> None: ... 56 | def dbg_jmp(addr: str) -> None: ... 57 | def dbg_call(addr: str) -> None: ... 58 | def dbg_bp_set(addr: str, type: str) -> None: ... 59 | def dbg_bp_unset(addr: str, type: str) -> None: ... 60 | def dbg_alloc(size: str) -> str: ... 61 | def dbg_free(addr: str) -> None: ... 62 | def dbg_backtrace() -> List[Dict[str, int]]: ... 63 | def dbg_dump(name: str) -> None: ... 64 | def dbg_restore(name: str) -> None: ... 65 | def dbg_register_get(name: str) -> None: ... 66 | def dbg_register_set(name: str, value: str) -> None: ... 67 | def trace_at(addr: str) -> Dict[str, str]: ... 68 | def trace_list() -> List[str]: ... 69 | def trace_reset() -> None: ... 70 | def trace_ranges() -> List[str]: ... 71 | def hash(algo: str, size: int) -> str: ... 72 | def graph(addr: Optional[str] = None) -> None: ... 73 | def cmd(s: str) -> str: ... 74 | def quit() -> None: ... 75 | -------------------------------------------------------------------------------- /tiny/lang_tiny.c: -------------------------------------------------------------------------------- 1 | #include "tiny.h" 2 | #include 3 | 4 | // TODO move into Tiny_StateThread 5 | static RCore *Gcore = NULL; 6 | 7 | const Tiny_NativeProp r2prop = { 8 | "r2core", 9 | NULL, 10 | NULL, 11 | }; 12 | 13 | static Tiny_Value Lib_r2trim(Tiny_StateThread *thread, const Tiny_Value *args, int count) { 14 | // thread->userdata = NULL; 15 | const char *cmd = Tiny_ToString (args[0]); 16 | char *res = strdup (cmd); 17 | r_str_trim (res); 18 | return Tiny_NewString(thread, res); 19 | } 20 | 21 | static Tiny_Value Lib_r2atoi(Tiny_StateThread *thread, const Tiny_Value *args, int count) { 22 | const char *cmd = Tiny_ToString (args[0]); 23 | ut64 n = r_num_math (NULL, cmd); 24 | return Tiny_NewInt(n); 25 | } 26 | 27 | static Tiny_Value Lib_r2cmd(Tiny_StateThread *thread, const Tiny_Value *args, int count) { 28 | const char *cmd = Tiny_ToString (args[0]); 29 | #if 0 30 | Tiny_Value v = Tiny_GetGlobal(thread, 0); 31 | void *core = Tiny_ToAddr (v); 32 | #else 33 | void *core = thread->userdata; // Gcore; 34 | #endif 35 | if (!core) { 36 | printf ("No core pointer\n"); 37 | return Tiny_Null; 38 | } 39 | char *res = r_core_cmd_str (core, cmd); 40 | if (!res || !*res) { 41 | free (res); 42 | return Tiny_Null; 43 | } 44 | return Tiny_NewString(thread, res); 45 | } 46 | 47 | #if 0 48 | int main(int argc, char **argv) { 49 | if (argc > 1) { 50 | tinyrun (NULL, argv[1], NULL); 51 | return 0; 52 | } 53 | return 1; 54 | } 55 | #endif 56 | 57 | static int tinyrun(RCore *core, const char *filename, const char *eval) { 58 | Tiny_State *ts = Tiny_CreateState(); 59 | 60 | // Tiny_BindStandardRadare2 (ts); 61 | Tiny_BindStandardArray (ts); 62 | Tiny_BindStandardDict (ts); 63 | Tiny_BindStandardIO (ts); 64 | Tiny_BindStandardLib (ts); 65 | Tiny_BindFunction(ts, "r2(str): str", Lib_r2cmd); 66 | Tiny_BindFunction(ts, "trim(str): str", Lib_r2trim); 67 | Tiny_BindFunction(ts, "atoi(str): int", Lib_r2atoi); 68 | if (filename) { 69 | Tiny_CompileFile (ts, filename); 70 | } else if (eval) { 71 | Tiny_CompileString (ts, "main", eval); 72 | } 73 | Gcore = core; 74 | #if 0 75 | RCore *core = r_core_new (); 76 | char *s = r_str_newf ("r2core := %lld", (unsigned long long)(size_t)core); 77 | Tiny_CompileString (ts, "r2core", s); 78 | #endif 79 | Tiny_StateThread thread; 80 | Tiny_InitThread(&thread, ts); 81 | Tiny_StartThread(&thread); 82 | thread.userdata = core; 83 | 84 | #if 0 85 | Tiny_Value v = Tiny_NewNative (&thread, core, &r2prop); 86 | Tiny_Value tiny_core = Tiny_NewLightNative (core); 87 | Tiny_CallFunction (&thread, 0, NULL, 0); 88 | // Tiny_SetGlobal (&thread, 0, v); 89 | #endif 90 | 91 | while (Tiny_ExecuteCycle(&thread)) 92 | ; 93 | // GenerateCode (ts, TINY_OP_HALT); 94 | // CheckInitialized(ts); // Done after compilation because it might have registered 95 | // Tiny_ExecuteCycle 96 | // CompileFile() 97 | return 0; 98 | } 99 | 100 | static bool lang_tiny_run(RLang *lang, const char *code, int len) { 101 | RCore *core = lang->user; 102 | return tinyrun (core, NULL, code); 103 | } 104 | 105 | static int lang_tiny_file(RLang *lang, const char *file) { 106 | RCore *core = lang->user; 107 | return tinyrun (core, file, NULL); 108 | } 109 | 110 | static RLangPlugin r_lang_plugin_tiny = { 111 | .name = "tiny", 112 | .ext = "tiny", 113 | .desc = "Tiny programming language", 114 | .license = "MIT", 115 | .run = lang_tiny_run, 116 | .run_file = (void*)lang_tiny_file, 117 | }; 118 | 119 | #if !CORELIB 120 | RLibStruct radare_plugin = { 121 | .type = R_LIB_TYPE_LANG, 122 | .data = &r_lang_plugin_tiny, 123 | .version = R2_VERSION 124 | }; 125 | #endif 126 | -------------------------------------------------------------------------------- /wren/p/wren.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2018-2022 pancake */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "wren-vm.h" 7 | #include "wren-vm.c" 8 | #include "json-wren.h" 9 | 10 | static const char *r2_wren = 11 | "class R2 {\n" 12 | " foreign static cmd(str)\n" 13 | " static cmdj(str) {\n" 14 | " var res = R2.cmd(str)\n" 15 | " return Json.parse(res)\n" 16 | " }\n" 17 | "}\n"; 18 | 19 | static WrenVM* vm = NULL; 20 | 21 | static bool lang_wren_file(RLang *lang, const char *file) { 22 | char * code = r_file_slurp (file, NULL); 23 | if (code) { 24 | WrenInterpretResult result = wrenInterpret (vm, "main", code); 25 | if (result != WREN_RESULT_SUCCESS) { 26 | eprintf ("wren: Error loading script\n"); 27 | } 28 | free (code); 29 | } else { 30 | eprintf ("file not found (%s)\n", file); 31 | return false; 32 | } 33 | return true; 34 | } 35 | 36 | static void writeFn(WrenVM* vm, const char* text) { 37 | // r_cons_printf ("%s", text); 38 | printf("%s", text); 39 | } 40 | 41 | void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) { 42 | switch (errorType) { 43 | case WREN_ERROR_COMPILE: 44 | eprintf("[%s line %d] [Error] %s\n", module, line, msg); 45 | break; 46 | case WREN_ERROR_STACK_TRACE: 47 | eprintf("[%s line %d] in %s\n", module, line, msg); 48 | break; 49 | case WREN_ERROR_RUNTIME: 50 | eprintf("[Runtime Error] %s\n", msg); 51 | break; 52 | } 53 | } 54 | 55 | static RLang *lang = NULL; 56 | 57 | void r2cmd(WrenVM* vm) { 58 | const char *a = wrenGetSlotString (vm, 1); 59 | if (a && lang->cmd_str) { 60 | char *res = lang->cmd_str (lang->user, a); 61 | wrenSetSlotString(vm, 0, res); 62 | free (res); 63 | } 64 | } 65 | 66 | WrenForeignMethodFn foreign_methods (struct WrenVM* vm, 67 | const char* module, 68 | const char* className, 69 | bool isStatic, 70 | const char* signature 71 | ) { 72 | if (!strcmp (module, "main") && !strcmp (className, "R2") && isStatic) { 73 | if (!strcmp (signature, "cmd(_)")) { 74 | return r2cmd; 75 | } 76 | } 77 | return NULL; 78 | } 79 | 80 | static WrenLoadModuleResult load_module(WrenVM* vm, const char* name) { 81 | // TODO: add include paths 82 | #if 0 83 | char *res = r_file_slurp (name, NULL); 84 | #endif 85 | WrenLoadModuleResult wmr = {0}; 86 | return wmr; 87 | } 88 | 89 | static bool lang_wren_init(void *user) { 90 | // wrenFreeVM(vm); 91 | lang = user; 92 | WrenConfiguration config; 93 | wrenInitConfiguration (&config); 94 | config.writeFn = &writeFn; 95 | config.errorFn = &errorFn; 96 | config.bindForeignMethodFn = foreign_methods; 97 | config.loadModuleFn = load_module; 98 | vm = wrenNewVM (&config); 99 | WrenInterpretResult result = wrenInterpret (vm, "main", json_wren); 100 | if (result != WREN_RESULT_SUCCESS) { 101 | eprintf ("wren cannot load json%c", 10); 102 | } 103 | result = wrenInterpret (vm, "main", r2_wren); 104 | if (result != WREN_RESULT_SUCCESS) { 105 | eprintf ("wren cannot load json%c", 10); 106 | } 107 | return true; 108 | } 109 | 110 | static bool lang_wren_run(RLang *lang, const char *code, int len) { 111 | WrenInterpretResult result = wrenInterpret(vm, "main", code); 112 | return (result == WREN_RESULT_SUCCESS); 113 | } 114 | 115 | static RLangPlugin r_lang_plugin_wren = { 116 | .name = "wren", 117 | .ext = "wren", 118 | .license = "MIT", 119 | .desc = "wren.io scripting language", 120 | .run = lang_wren_run, 121 | .init = (void*)lang_wren_init, 122 | .run_file = (void*)lang_wren_file, 123 | }; 124 | 125 | #ifndef CORELIB 126 | RLibStruct radare_plugin = { 127 | .type = R_LIB_TYPE_LANG, 128 | .data = &r_lang_plugin_wren, 129 | }; 130 | #endif 131 | -------------------------------------------------------------------------------- /typescript/mujs/types/r2pipe.d.ts: -------------------------------------------------------------------------------- 1 | export type InstructionType = "mov" | "jmp" | "cmp" | "nop" | "call"; 2 | export type InstructionFamily = "cpu" | "fpu" | "priv"; 3 | export interface SearchResult { 4 | offset: number; 5 | type: string; 6 | data: string; 7 | } 8 | export interface Flag { 9 | name: string; 10 | size: number; 11 | offset: number; 12 | } 13 | export interface CallRef { 14 | addr: number; 15 | type: string; 16 | at: number; 17 | } 18 | export interface Function { 19 | offset: number; 20 | name: string; 21 | size: number; 22 | noreturn: boolean; 23 | stackframe: number; 24 | ebbs: number; 25 | signature: string; 26 | nbbs: number; 27 | callrefs: CallRef[]; 28 | codexrefs: CallRef[]; 29 | } 30 | export interface BinFile { 31 | arch: string; 32 | static: boolean; 33 | va: boolean; 34 | stripped: boolean; 35 | pic: boolean; 36 | relocs: boolean; 37 | sanitize: boolean; 38 | baddr: number; 39 | binsz: number; 40 | bintype: string; 41 | bits: number; 42 | canary: boolean; 43 | class: string; 44 | compiler: string; 45 | endian: string; 46 | machine: string; 47 | nx: boolean; 48 | os: string; 49 | laddr: number; 50 | linenum: boolean; 51 | havecode: boolean; 52 | intrp: string; 53 | } 54 | export interface Reference { 55 | from: number; 56 | type: string; 57 | perm: string; 58 | opcode: string; 59 | fcn_addr: number; 60 | fcn_name: string; 61 | realname: string; 62 | refname: string; 63 | } 64 | export interface BasicBlock { 65 | addr: number; 66 | size: number; 67 | jump: number; 68 | fail: number; 69 | opaddr: number; 70 | inputs: number; 71 | outputs: number; 72 | ninstr: number; 73 | instrs: number[]; 74 | traced: boolean; 75 | } 76 | export interface Instruction { 77 | type: InstructionType; 78 | addr: number; 79 | opcode: string; 80 | pseudo: string; 81 | mnemonic: string; 82 | sign: boolean; 83 | family: InstructionFamily; 84 | description: string; 85 | esil: string; 86 | opex: any; 87 | size: number; 88 | ptr: number; 89 | bytes: string; 90 | id: number; 91 | refptr: number; 92 | direction: "read" | "write"; 93 | stackptr: number; 94 | stack: string; 95 | } 96 | export interface R2Pipe { 97 | cmd(cmd: string): string; 98 | log(msg: string): string; 99 | } 100 | export declare class R2Api { 101 | r2: R2Pipe; 102 | constructor(r2: R2Pipe); 103 | clearScreen(): void; 104 | getRegisters(): any; 105 | setRegisters(obj: any): void; 106 | analyzeProgram(): void; 107 | hex(s: number | string): string; 108 | step(): R2Api; 109 | stepOver(): R2Api; 110 | math(expr: number | string): number; 111 | searchString(s: string): SearchResult[]; 112 | binInfo(): BinFile; 113 | skip(): void; 114 | ptr(s: string | number): NativePointer; 115 | cmd(s: string): string; 116 | cmdj(s: string): any; 117 | log(s: string): string; 118 | clippy(msg: string): void; 119 | ascii(msg: string): void; 120 | listFunctions(): Function[]; 121 | listFlags(): Flag[]; 122 | } 123 | export declare class NativePointer { 124 | addr: string; 125 | api: R2Api; 126 | constructor(api: R2Api, s: string | number); 127 | readByteArray(len: number): any; 128 | add(a: number): NativePointer; 129 | sub(a: number): NativePointer; 130 | writeCString(s: string): NativePointer; 131 | readCString(): string; 132 | instruction(): Instruction; 133 | analyzeFunction(): void; 134 | name(): string; 135 | basicBlock(): BasicBlock; 136 | functionBasicBlocks(): BasicBlock[]; 137 | xrefs(): Reference[]; 138 | } 139 | -------------------------------------------------------------------------------- /typescript/tolua/types/r2pipe.d.ts: -------------------------------------------------------------------------------- 1 | export type InstructionType = "mov" | "jmp" | "cmp" | "nop" | "call"; 2 | export type InstructionFamily = "cpu" | "fpu" | "priv"; 3 | export interface SearchResult { 4 | offset: number; 5 | type: string; 6 | data: string; 7 | } 8 | export interface Flag { 9 | name: string; 10 | size: number; 11 | offset: number; 12 | } 13 | export interface CallRef { 14 | addr: number; 15 | type: string; 16 | at: number; 17 | } 18 | export interface Function { 19 | offset: number; 20 | name: string; 21 | size: number; 22 | noreturn: boolean; 23 | stackframe: number; 24 | ebbs: number; 25 | signature: string; 26 | nbbs: number; 27 | callrefs: CallRef[]; 28 | codexrefs: CallRef[]; 29 | } 30 | export interface BinFile { 31 | arch: string; 32 | static: boolean; 33 | va: boolean; 34 | stripped: boolean; 35 | pic: boolean; 36 | relocs: boolean; 37 | sanitize: boolean; 38 | baddr: number; 39 | binsz: number; 40 | bintype: string; 41 | bits: number; 42 | canary: boolean; 43 | class: string; 44 | compiler: string; 45 | endian: string; 46 | machine: string; 47 | nx: boolean; 48 | os: string; 49 | laddr: number; 50 | linenum: boolean; 51 | havecode: boolean; 52 | intrp: string; 53 | } 54 | export interface Reference { 55 | from: number; 56 | type: string; 57 | perm: string; 58 | opcode: string; 59 | fcn_addr: number; 60 | fcn_name: string; 61 | realname: string; 62 | refname: string; 63 | } 64 | export interface BasicBlock { 65 | addr: number; 66 | size: number; 67 | jump: number; 68 | fail: number; 69 | opaddr: number; 70 | inputs: number; 71 | outputs: number; 72 | ninstr: number; 73 | instrs: number[]; 74 | traced: boolean; 75 | } 76 | export interface Instruction { 77 | type: InstructionType; 78 | addr: number; 79 | opcode: string; 80 | pseudo: string; 81 | mnemonic: string; 82 | sign: boolean; 83 | family: InstructionFamily; 84 | description: string; 85 | esil: string; 86 | opex: any; 87 | size: number; 88 | ptr: number; 89 | bytes: string; 90 | id: number; 91 | refptr: number; 92 | direction: "read" | "write"; 93 | stackptr: number; 94 | stack: string; 95 | } 96 | export interface R2Pipe { 97 | cmd(cmd: string): string; 98 | log(msg: string): string; 99 | } 100 | export declare class R2Api { 101 | r2: R2Pipe; 102 | constructor(r2: R2Pipe); 103 | clearScreen(): void; 104 | getRegisters(): any; 105 | setRegisters(obj: any): void; 106 | analyzeProgram(): void; 107 | hex(s: number | string): string; 108 | step(): R2Api; 109 | stepOver(): R2Api; 110 | math(expr: number | string): number; 111 | searchString(s: string): SearchResult[]; 112 | binInfo(): BinFile; 113 | skip(): void; 114 | ptr(s: string | number): NativePointer; 115 | cmd(s: string): string; 116 | cmdj(s: string): any; 117 | log(s: string): string; 118 | clippy(msg: string): void; 119 | ascii(msg: string): void; 120 | listFunctions(): Function[]; 121 | listFlags(): Flag[]; 122 | } 123 | export declare class NativePointer { 124 | addr: string; 125 | api: R2Api; 126 | constructor(api: R2Api, s: string | number); 127 | readByteArray(len: number): any; 128 | add(a: number): NativePointer; 129 | sub(a: number): NativePointer; 130 | writeCString(s: string): NativePointer; 131 | readCString(): string; 132 | instruction(): Instruction; 133 | analyzeFunction(): void; 134 | name(): string; 135 | basicBlock(): BasicBlock; 136 | functionBasicBlocks(): BasicBlock[]; 137 | xrefs(): Reference[]; 138 | } 139 | -------------------------------------------------------------------------------- /csharp/repl/main.cs: -------------------------------------------------------------------------------- 1 | /* radare2 - MIT - Copyright 2016 pancake */ 2 | 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using Mono.CSharp; 7 | using Newtonsoft.Json; 8 | 9 | class R2Repl { 10 | Evaluator e; 11 | CSharpShell shell = null; 12 | Hashtable argFlags; 13 | 14 | public static void Main(string[] args) { 15 | var repl = new R2Repl (args); 16 | repl.Run(); 17 | } 18 | 19 | private bool RunArgs() { 20 | bool Result = true; 21 | if (argFlags.Contains("-e")) { 22 | foreach (string str in (List)argFlags["-e"]) { 23 | this.e.Run(str); 24 | } 25 | } 26 | if (argFlags.Contains("-i")) { 27 | foreach (string str in (List)argFlags["-i"]) { 28 | string text = System.IO.File.ReadAllText(str); 29 | this.e.Run(text); 30 | Result = false; 31 | } 32 | } 33 | return Result; 34 | } 35 | 36 | private void ShowHelp() { 37 | Console.WriteLine(@" 38 | Usage: r2repl.exe [-i script.cs] [-e csharp-expression] [file-to-open-in-r2] 39 | "); 40 | } 41 | 42 | private string[] ParseArgs(string[] args) { 43 | var newArg = new List(); 44 | argFlags = new Hashtable(); 45 | string mode = null; 46 | foreach (string arg in args) { 47 | switch (arg) { 48 | case "-h": 49 | ShowHelp(); 50 | return null; 51 | case "-e": 52 | case "-i": 53 | mode = arg; 54 | break; 55 | default: 56 | if (mode != null) { 57 | if (!argFlags.Contains(mode)) { 58 | argFlags[mode] = new List(); 59 | } 60 | ((List)argFlags[mode]).Add(arg); 61 | mode = null; 62 | } else { 63 | newArg.Add(arg); 64 | } 65 | break; 66 | } 67 | } 68 | return newArg.ToArray(); 69 | } 70 | 71 | public R2Repl(string[] args) { 72 | this.e = new Evaluator(new CompilerContext( 73 | new CompilerSettings { 74 | WarningLevel = 0, 75 | ShowFullPaths = true 76 | }, new ConsoleReportPrinter())); 77 | 78 | e.Run("LoadAssembly(\"Mono.Posix\")"); 79 | e.Run("LoadAssembly(\"r2pipe\")"); 80 | e.Run("LoadAssembly(\"Newtonsoft.Json\")"); 81 | e.Run("using System;"); 82 | e.Run("using System.Collections;"); 83 | e.Run("using System.Collections.Generic;"); 84 | e.Run("using Mono.Unix;"); 85 | e.Run("using Newtonsoft.Json;"); 86 | 87 | e.Run(@" 88 | /* example */ 89 | public class Opcode { 90 | public string opcode; 91 | public string family; 92 | public string type; 93 | public string esil; 94 | public int address; 95 | public int size; 96 | } 97 | 98 | public class r2w { 99 | public r2pipe.IR2Pipe Instance; 100 | public r2w() { 101 | Instance = new r2pipe.RlangPipe(); 102 | } 103 | public r2w(string file) { 104 | Instance = new r2pipe.R2Pipe(file); 105 | } 106 | public string cmd(string cmd) { 107 | return Instance.RunCommand(cmd).Trim(); 108 | } 109 | public dynamic cmdj(string cmd) { 110 | return JsonConvert.DeserializeObject(this.cmd(cmd)); 111 | } 112 | public Opcode[] Opcodes(int n) { 113 | var ops = new List(); 114 | foreach (var op in cmdj(""aoj 10"")) { 115 | ops.Add (op.ToObject()); 116 | } 117 | return ops.ToArray(); 118 | } 119 | public void Seek(string addr) { 120 | cmd(""s "" + addr); 121 | } 122 | } 123 | "); 124 | args = ParseArgs(args); 125 | if (args == null) { 126 | /* exit */ 127 | return; 128 | } 129 | if (args.Length > 0) { 130 | e.Run("var r2 = new r2w(\""+args[0]+"\");"); 131 | } else { 132 | try { 133 | e.Run("var r2 = new r2w();"); 134 | } catch (Exception _) { 135 | Console.WriteLine(@" 136 | Cannot find R2PIPE environment. See: csharp-r2 -h 137 | Run this from r2 like this: '#!pipe mono main.exe' 138 | "); 139 | return; 140 | } 141 | } 142 | if (RunArgs()) { 143 | this.shell = new CSharpShell (e); 144 | } 145 | } 146 | 147 | public void Run() { 148 | string[] nullArgs = new string[0]; 149 | if (this.shell != null) { 150 | shell.Run (nullArgs); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /mujs/jsapi.c: -------------------------------------------------------------------------------- 1 | /* lang.mujs plugin for r2 - 2022 - pancake */ 2 | 3 | static const char *const r2_js = 4 | "var r2 = {cmd: r2cmd, call: r2call, cmdj: function(x) {\n" 5 | " return JSON.parse(r2cmd(x));\n" 6 | " }\n" 7 | "};\n" 8 | ; 9 | static const char *require_js = 10 | // XXX inspect or dump ! 11 | "function inspect(x) { try { var o = JSON.parse(x); } catch (e) { o = x; }\nreturn JSON.stringify(o,null, 2); }\n" 12 | "var dump = inspect;\n" 13 | "var exports = {}\n" 14 | "function require(name) {\n" 15 | "var cache = require.cache;\n" 16 | "if (name in cache) return cache[name];\n" 17 | "var exports = {};\n" 18 | "cache[name] = exports;\n" 19 | "Function('exports', readFileSync(name+'.js'))(exports);\n" 20 | "return exports;\n" 21 | "}\n" 22 | "require.cache = Object.create(null);\n" 23 | ; 24 | 25 | static const char *const fs_js = 26 | "var fs = {}\n" 27 | "fs.readFileSync = readFileSync;\n" 28 | "fs.writeFileSync = writeFileSync;\n" 29 | ; 30 | 31 | static const char *stacktrace_js = 32 | "Error.prototype.toString = function() {\n" 33 | "var s = this.name;\n" 34 | "if ('message' in this) s += ': ' + this.message;\n" 35 | "if ('stackTrace' in this) s += this.stackTrace;\n" 36 | "return s;\n" 37 | "};\n" 38 | ; 39 | static const char *console_js = 40 | "var console = { log: print, debug: print, warn: print, error: print };" 41 | ; 42 | 43 | static void jsB_write(js_State *J) { 44 | const char *filename = js_tostring(J, 1); 45 | const char *data = js_tostring(J, 2); 46 | bool append = false; // TODO fs.writeFileSync(path, data,{flag:'a+'}); //'a+' is append mode 47 | r_file_dump (filename, (const ut8*)data, strlen (data), append); 48 | js_pushundefined(J); 49 | } 50 | 51 | static void jsB_read(js_State *J) { 52 | // TODO: check r2 sandbox 53 | const char *filename = js_tostring (J, 1); 54 | #if 0 55 | FILE *f; 56 | char *s; 57 | int n, t; 58 | 59 | f = fopen(filename, "rb"); 60 | if (!f) { 61 | js_error(J, "cannot open file '%s': %s", filename, strerror(errno)); 62 | } 63 | 64 | if (fseek(f, 0, SEEK_END) < 0) { 65 | fclose(f); 66 | js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); 67 | } 68 | 69 | n = ftell(f); 70 | if (n < 0) { 71 | fclose(f); 72 | js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno)); 73 | } 74 | 75 | if (fseek(f, 0, SEEK_SET) < 0) { 76 | fclose(f); 77 | js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); 78 | } 79 | 80 | s = malloc(n + 1); 81 | if (!s) { 82 | fclose(f); 83 | js_error(J, "out of memory"); 84 | } 85 | 86 | t = fread(s, 1, n, f); 87 | if (t != n) { 88 | free(s); 89 | fclose(f); 90 | js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno)); 91 | } 92 | s[n] = 0; 93 | js_pushstring(J, s); 94 | free(s); 95 | fclose(f); 96 | #else 97 | size_t sz = 0; 98 | char *data = r_file_slurp (filename, &sz); 99 | if (data) { 100 | js_pushstring (J, data); 101 | free (data); 102 | } else { 103 | js_error (J, "cannot read data from file '%s': %s", filename, strerror (errno)); 104 | } 105 | #endif 106 | } 107 | 108 | static void jsB_print(js_State *J) { 109 | int i, top = js_gettop(J); 110 | for (i = 1; i < top; i++) { 111 | const char *s = js_tostring(J, i); 112 | // r_cons_printf ("%s\n", s); 113 | // r_cons_flush (); 114 | if (i > 1) putchar(' '); 115 | fputs(s, stdout); 116 | } 117 | putchar('\n'); 118 | js_pushundefined(J); 119 | } 120 | 121 | static void jsB_gc(js_State *J) { 122 | int report = js_toboolean(J, 1); 123 | js_gc(J, report); 124 | js_pushundefined(J); 125 | } 126 | 127 | static const char *const base64_js = 128 | "var Base64 = { encode : b64, decode: function(x) { return b64(x,1); }\n" 129 | ; 130 | 131 | static void jsB_b64(js_State *J) { 132 | const char *input = js_tostring (J, 1); 133 | bool decode = js_toboolean (J, 2); 134 | if (decode) { 135 | int res = 0; 136 | ut8 *r = sdb_decode (input, &res); 137 | if (r) { 138 | js_pushstring (J, (const char *)r); 139 | free (r); 140 | } else { 141 | js_error (J, "Invalid base64 string"); 142 | } 143 | } else { 144 | char *r = sdb_encode ((const ut8*) input, -1); 145 | js_pushstring (J, r); 146 | free (r); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /python/python/core.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2016-2025 - pancake */ 2 | 3 | #include "core.h" 4 | 5 | // TODO: XXX remove globals 6 | R_TH_LOCAL RCore *Gcore = NULL; 7 | #if R2_VERSION_NUMBER > 50909 8 | static R_TH_LOCAL void *py_core_call_cb = NULL; 9 | #endif 10 | 11 | #if R2_VERSION_NUMBER > 50909 12 | static bool py_core_call(RCorePluginSession *s, const char *str); 13 | #else 14 | static int py_core_call(void *user, const char *str); 15 | #endif 16 | 17 | #if R2_VERSION_NUMBER > 50909 18 | static bool py_core_call(RCorePluginSession *s, const char *str) { 19 | if (!Gcore) { 20 | return false; 21 | } 22 | if (!py_core_call_cb) { 23 | return false; 24 | } 25 | PyObject *arglist = Py_BuildValue ("(z)", str); 26 | PyObject *result = PyObject_CallObject ((PyObject *)py_core_call_cb, arglist); 27 | if (result) { 28 | int res = 0; 29 | if (PyBool_Check (result)) { 30 | if (result == Py_True) { 31 | Py_DECREF (result); 32 | Py_DECREF (arglist); 33 | return true; 34 | } 35 | } else if (PyLong_Check (result)) { 36 | res = (int)PyLong_AsLong (result); 37 | Py_DECREF (result); 38 | Py_DECREF (arglist); 39 | return res != 0; 40 | } else if (PyUnicode_Check (result)) { 41 | const char *resstr = PyBytes_AS_STRING (result); 42 | if (resstr != NULL) { 43 | r_cons_print (NULL, resstr); 44 | Py_DECREF (result); 45 | Py_DECREF (arglist); 46 | return true; 47 | } 48 | } 49 | Py_XDECREF (result); 50 | } 51 | Py_XDECREF (arglist); 52 | return false; 53 | } 54 | #else 55 | static int py_core_call(void *user, const char *str) { 56 | RListIter *iter; 57 | RCorePlugin *cp; 58 | if (!Gcore) { 59 | return 0; 60 | } 61 | r_list_foreach (Gcore->rcmd->plist, iter, cp) { 62 | if (cp->data && cp->call == py_core_call) { 63 | void *py_core_call_cb = cp->data; 64 | PyObject *arglist = Py_BuildValue ("(z)", str); 65 | PyObject *result = PyObject_CallObject (py_core_call_cb, arglist); 66 | if (result) { 67 | int res = 0; 68 | if (PyBool_Check (result)) { 69 | if (result == Py_True) { 70 | return 1; 71 | } 72 | } else if (PyLong_Check (result)) { 73 | res = (int)PyLong_AsLong (result); 74 | if (res) { 75 | return res; 76 | } 77 | } else if (PyUnicode_Check (result)) { 78 | const char *resstr = PyBytes_AS_STRING (result); 79 | if (resstr != NULL) { 80 | r_cons_print (NULL, resstr); 81 | return 1; 82 | } 83 | } 84 | } 85 | } 86 | } 87 | return 0; 88 | } 89 | #endif 90 | 91 | void Radare_plugin_core_free(RCorePlugin *ap) { 92 | if (ap) { 93 | #if R2_VERSION_NUMBER > 50808 94 | free ((char *)ap->meta.name); 95 | free ((char *)ap->meta.license); 96 | free ((char *)ap->meta.desc); 97 | #else 98 | free ((char *)ap->name); 99 | free ((char *)ap->license); 100 | free ((char *)ap->desc); 101 | #endif 102 | free (ap); 103 | } 104 | } 105 | 106 | PyObject *Radare_plugin_core(Radare* self, PyObject *args) { 107 | PyObject *arglist = Py_BuildValue ("(i)", 0); 108 | PyObject *o = PyObject_CallObject (args, arglist); 109 | if (o == NULL) { 110 | return NULL; 111 | } 112 | 113 | RCorePlugin *ap = R_NEW0 (RCorePlugin); 114 | if (!ap) { 115 | return NULL; 116 | } 117 | #if R2_VERSION_NUMBER > 50808 118 | RPluginMeta meta = { 119 | .name = getS (o, "name"), 120 | .license = getS (o, "license"), 121 | .desc = getS (o, "desc") 122 | }; 123 | memcpy ((RPluginMeta *)&ap->meta, &meta, sizeof (RPluginMeta)); 124 | #else 125 | ap->name = getS (o, "name"); 126 | ap->license = getS (o, "license"); 127 | ap->desc = getS (o, "desc"); 128 | #endif 129 | void *ptr = getF (o, "call"); 130 | if (ptr) { 131 | Py_INCREF (ptr); 132 | #if R2_VERSION_NUMBER > 50909 133 | py_core_call_cb = ptr; 134 | #else 135 | ap->data = ptr; 136 | #endif 137 | ap->call = py_core_call; 138 | } 139 | Py_DECREF (o); 140 | Py_DECREF (arglist); 141 | 142 | RLibStruct lp = { 143 | .type = R_LIB_TYPE_CORE, 144 | .data = ap, 145 | .free = (void (*)(void *data))Radare_plugin_core_free 146 | }; 147 | #if R2_VERSION_NUMBER > 50808 148 | R_LOG_DEBUG ("PLUGIN [python] Loading core: %s", ap->meta.name); 149 | #else 150 | R_LOG_DEBUG ("PLUGIN [python] Loading core: %s", ap->name); 151 | #endif 152 | r_lib_open_ptr (Gcore->lib, "python-r_core.py", NULL, &lp); 153 | Py_RETURN_TRUE; 154 | } 155 | -------------------------------------------------------------------------------- /python/python/asm.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2009-2023 - pancake */ 2 | 3 | #include "asm.h" 4 | #include "core.h" 5 | 6 | #if R2_VERSION_NUMBER < 50800 7 | 8 | void py_export_asm_enum(PyObject *tp_dict) { 9 | 10 | #define PYENUM(name) {\ 11 | PyObject *o = PyLong_FromLong(name); \ 12 | if (o) { \ 13 | PyDict_SetItemString(tp_dict, #name, o); \ 14 | Py_DECREF(o); \ 15 | }\ 16 | } 17 | 18 | // R_SYS_ENDIAN_* 19 | PYENUM(R_SYS_ENDIAN_NONE); 20 | PYENUM(R_SYS_ENDIAN_LITTLE); 21 | PYENUM(R_SYS_ENDIAN_BIG); 22 | PYENUM(R_SYS_ENDIAN_BI); 23 | #undef PYENUM 24 | } 25 | 26 | /* TODO : move into a struct stored in the plugin struct */ 27 | static void *py_assemble_cb = NULL; 28 | static void *py_disassemble_cb = NULL; 29 | 30 | static int check_list_result(PyObject *result, const char *fcn_name) { 31 | if (!result) { 32 | eprintf ("Error while calling %s in Python\n", fcn_name); 33 | PyErr_Print (); 34 | return 0; 35 | } 36 | if (!PyList_Check (result)) { 37 | PyObject *str = PyObject_Str (result); 38 | Py_DECREF (result); 39 | if (!str) { 40 | PyErr_Print (); 41 | } else { 42 | if (PyUnicode_Check (str)) { 43 | eprintf ("Unknown type returned from %s. List was expected, got %s.\n", fcn_name, PyUnicode_AsUTF8 (str)); 44 | } else { 45 | eprintf ("Unknown type returned from %s. List was expected.\n", fcn_name); 46 | } 47 | Py_DECREF (str); 48 | } 49 | return 0; 50 | } 51 | return 1; 52 | } 53 | 54 | static int py_assemble(RAsm *a, RAsmOp *op, const char *str) { 55 | int i, size = 0; 56 | int seize = -1; 57 | const char *opstr = str; 58 | ut8 *buf = (ut8*)r_strbuf_get (&op->buf); 59 | if (py_assemble_cb) { 60 | PyObject *arglist = Py_BuildValue ("(zK)", str, a->pc); 61 | PyObject *result = PyObject_CallObject (py_assemble_cb, arglist); 62 | if (check_list_result (result, "assemble")) { 63 | seize = size = PyList_Size (result); 64 | for (i = 0; i < size ; i++) { 65 | PyObject *len = PyList_GetItem (result, i); 66 | buf[i] = PyNumber_AsSsize_t (len, NULL); 67 | } 68 | Py_DECREF (result); 69 | } 70 | } 71 | op->size = size = seize; 72 | r_strbuf_set (&op->buf_asm, opstr); 73 | //r_hex_bin2str ((ut8*)r_strbuf_get (&op->buf), op->size, r_strbuf_get (&op->buf_hex)); 74 | return seize; 75 | } 76 | 77 | static int py_disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { 78 | int size = 0; 79 | int seize = -1; 80 | r_asm_op_init (op); 81 | r_strbuf_set (&op->buf_asm, "invalid"); 82 | if (py_disassemble_cb) { 83 | Py_buffer pybuf = { 84 | .buf = (void *) buf, // Warning: const is lost when casting 85 | .len = len, 86 | .readonly = 1, 87 | .ndim = 1, 88 | .itemsize = 1, 89 | }; 90 | PyObject *memview = PyMemoryView_FromBuffer (&pybuf); 91 | #if 0 92 | PyObject *arglist = Py_BuildValue ("(NKN)", memview, len, a->pc); 93 | PyObject *result = PyObject_CallObject (py_disassemble_cb, arglist); 94 | #endif 95 | PyObject *result = PyObject_CallFunction (py_disassemble_cb, "NIK", memview, len, a->pc); 96 | if (check_list_result (result, "disassemble")) { 97 | PyObject *pylen = PyList_GetItem (result, 0); 98 | PyObject *pystr = PyList_GetItem (result, 1); 99 | seize = PyNumber_AsSsize_t (pylen, NULL); 100 | r_strbuf_set (&op->buf_asm, PyUnicode_AsUTF8 (pystr)); 101 | Py_DECREF (result); 102 | } 103 | } 104 | op->size = size = seize; 105 | int buflen = R_MAX (1, op->size); 106 | buflen = R_MIN (buflen, len); 107 | char *res = calloc (buflen, 3); 108 | if (res) { 109 | r_asm_op_set_buf (op, buf, buflen); 110 | free (res); 111 | } 112 | return seize; 113 | } 114 | 115 | void Radare_plugin_asm_free(RAsmPlugin *ap) { 116 | free ((char *)ap->name); 117 | free ((char *)ap->arch); 118 | free ((char *)ap->license); 119 | free ((char *)ap->desc); 120 | free (ap); 121 | } 122 | 123 | PyObject *Radare_plugin_asm(Radare* self, PyObject *args) { 124 | PyObject *arglist = Py_BuildValue ("(i)", 0); 125 | PyObject *o = PyObject_CallObject (args, arglist); 126 | 127 | RAsmPlugin *ap = R_NEW0 (RAsmPlugin); 128 | if (!ap) { 129 | return NULL; 130 | } 131 | ap->name = getS (o,"name"); 132 | ap->arch = getS (o, "arch"); 133 | ap->license = getS (o, "license"); 134 | ap->desc = getS (o, "desc"); 135 | ap->bits = getI (o, "bits"); 136 | ap->endian = getI (o, "endian"); 137 | void *ptr = getF (o, "disassemble"); 138 | if (ptr) { 139 | Py_INCREF (ptr); 140 | py_disassemble_cb = ptr; 141 | // ap->disassemble = py_disassemble; 142 | } 143 | ptr = getF (o, "assemble"); 144 | if (ptr) { 145 | Py_INCREF (ptr); 146 | py_assemble_cb = ptr; 147 | ap->assemble = py_assemble; 148 | } 149 | Py_DECREF (o); 150 | 151 | RLibStruct lp = {0}; 152 | lp.type = R_LIB_TYPE_ASM; 153 | lp.data = ap; 154 | lp.free = (void (*)(void *data))Radare_plugin_asm_free; 155 | r_lib_open_ptr (core->lib, "python.py", NULL, &lp); 156 | Py_RETURN_TRUE; 157 | } 158 | #endif 159 | -------------------------------------------------------------------------------- /zforth/core.zf: -------------------------------------------------------------------------------- 1 | 2 | ( system calls ) 3 | 4 | : emit 0 sys ; 5 | : . 1 sys ; 6 | : tell 2 sys ; 7 | : quit 128 sys ; 8 | : sin 129 sys ; 9 | : include 130 sys ; 10 | : save 131 sys ; 11 | 12 | ( r2 forth words ) 13 | : r2cmd 132 sys ; 14 | : nl 10 0 sys ; ( new line ) 15 | : drop2 drop drop ; 16 | 17 | 18 | ( dictionary access. These are shortcuts through the primitive operations are !!, @@ and ,, ) 19 | 20 | : ! 0 !! ; 21 | : @ 0 @@ ; 22 | : , 0 ,, ; 23 | : # 0 ## ; 24 | 25 | 26 | ( compiler state ) 27 | 28 | : [ 0 compiling ! ; immediate 29 | : ] 1 compiling ! ; 30 | : postpone 1 _postpone ! ; immediate 31 | 32 | 33 | ( some operators and shortcuts ) 34 | : 1+ 1 + ; 35 | : 1- 1 - ; 36 | : over 1 pick ; 37 | : +! dup @ rot + swap ! ; 38 | : inc 1 swap +! ; 39 | : dec -1 swap +! ; 40 | : < - <0 ; 41 | : > swap < ; 42 | : <= over over >r >r < r> r> = + ; 43 | : >= swap <= ; 44 | : =0 0 = ; 45 | : not =0 ; 46 | : != = not ; 47 | : cr 10 emit ; 48 | : br 32 emit ; 49 | : .. dup . ; 50 | : here h @ ; 51 | 52 | 53 | ( memory management ) 54 | 55 | : allot h +! ; 56 | : var : ' lit , here 5 allot here swap ! 5 allot postpone ; ; 57 | : const : ' lit , , postpone ; ; 58 | 59 | ( 'begin' gets the current address, a jump or conditional jump back is generated 60 | by 'again', 'until' ) 61 | 62 | : begin here ; immediate 63 | : again ' jmp , , ; immediate 64 | : until ' jmp0 , , ; immediate 65 | 66 | 67 | ( '{ ... ... ... n x}' repeat n times definition - eg. : 5hello { ." hello " 5 x} ; ) 68 | 69 | : { ( -- ) ' lit , 0 , ' >r , here ; immediate 70 | : x} ( -- ) ' r> , ' 1+ , ' dup , ' >r , ' = , postpone until ' r> , ' drop , ; immediate 71 | 72 | 73 | ( vectored execution - execute XT eg. ' hello exe ) 74 | 75 | : exe ( XT -- ) ' lit , here dup , ' >r , ' >r , ' exit , here swap ! ; immediate 76 | 77 | ( execute XT n times e.g. ' hello 3 times ) 78 | : times ( XT n -- ) { >r dup >r exe r> r> dup x} drop drop ; 79 | 80 | 81 | ( 'if' prepares conditional jump, address will be filled in by 'else' or 'fi' ) 82 | 83 | : if ' jmp0 , here 999 , ; immediate 84 | : unless ' not , postpone if ; immediate 85 | : else ' jmp , here 999 , swap here swap ! ; immediate 86 | : fi here swap ! ; immediate 87 | 88 | 89 | ( forth style 'do' and 'loop', including loop iterators 'i' and 'j' ) 90 | 91 | : i ' lit , 0 , ' pickr , ; immediate 92 | : j ' lit , 2 , ' pickr , ; immediate 93 | : do ' swap , ' >r , ' >r , here ; immediate 94 | : loop+ ' r> , ' + , ' dup , ' >r , ' lit , 1 , ' pickr , ' >= , ' jmp0 , , ' r> , ' drop , ' r> , ' drop , ; immediate 95 | : loop ' lit , 1 , postpone loop+ ; immediate 96 | 97 | 98 | ( Create string literal, puts length and address on the stack ) 99 | 100 | : s" compiling @ if ' lits , here 0 , fi here begin key dup 34 = if drop 101 | compiling @ if here swap - swap ! else dup here swap - fi exit else , fi 102 | again ; immediate 103 | 104 | ( Print string literal ) 105 | 106 | : ." compiling @ if postpone s" ' tell , else begin key dup 34 = if drop exit else emit fi again 107 | fi ; immediate 108 | 109 | 110 | ( 111 | vi: ts=3 sw=3 ft=forth 112 | ) 113 | 114 | 115 | 116 | ( ====================================== ) 117 | 118 | 119 | ( methods for handling the dictionary ) 120 | 121 | ( 'next' increases the given dictionary address by the size of the cell 122 | located at that address ) 123 | 124 | : next dup # + ; 125 | 126 | ( 'words' generates a list of all define words ) 127 | 128 | : name dup @ 31 & swap next dup next rot tell @ ; 129 | : words latest @ begin name br dup 0 = until cr drop ; 130 | : prim? ( w -- bool ) @ 32 & ; 131 | : a->xt ( w -- xt ) dup dup @ 31 & swap next next + swap prim? if @ fi ; 132 | : xt->a ( xt -- w ) latest @ begin dup a->xt 2 pick = if swap drop exit fi next @ dup 0 = until swap drop ; 133 | : lit?jmp? ( a -- a boolean ) dup @ dup 1 = swap dup 18 = swap 19 = + + ; 134 | : disas ( a -- a ) dup dup . br br @ xt->a name drop lit?jmp? if br next dup @ . fi cr ; 135 | 136 | ( 'see' needs starting address on stack: e.g. ' words see ) 137 | : see ( xt -- ) dup xt->a name cr drop begin disas next dup @ =0 until drop ; 138 | 139 | ( 'dump' memory make hex dump len bytes from addr ) 140 | : hex_t ' lit , here dup , s" 0123456789abcdef" allot swap ! ; immediate 141 | : *hex_t hex_t ; 142 | : .hex *hex_t + @ emit ; 143 | : >nib ( n -- low high ) dup 15 & swap -16 & 16 / ; 144 | : ffemit ( n -- ) >nib .hex .hex ; 145 | : ffffemit ( n -- ) >nib >nib >nib { .hex 4 x} ; 146 | : @LSB ( addr -- LSB ) 2 @@ 255 & ; 147 | : between? ( n low_lim high_lim -- bool ) 2 pick > rot rot > & ; 148 | : 8hex ( a -- a_new ) { dup @LSB ffemit 32 emit 1+ 8 x} 32 emit ; 149 | : 16ascii ( a -- a_new ) 124 emit { dup @LSB dup 31 127 between? if emit else drop 46 emit fi 1+ 16 x} 124 emit ; 150 | : .addr ( a -- ) ffffemit ." " ; 151 | : 16line ( a -- a_new ) dup .addr dup { 8hex 2 x} drop 16ascii cr ; 152 | : dump ( addr len -- ) over + swap begin 16line over over < until drop drop ; 153 | 154 | -------------------------------------------------------------------------------- /python/examples/test-py-arch.py: -------------------------------------------------------------------------------- 1 | # Example Python Arch plugin written in Python 2 | # ============================================ 3 | # 4 | # -- astuder 5 | # 6 | # To locad the plugin launch radare2 with 'r2 -i test-py-arch.py ..' 7 | # or run '#!python test-py-arch.py' on the radare2 console 8 | 9 | import r2lang 10 | from r2lang import R 11 | 12 | def pyarch(a): 13 | # called when arch is activated in radare2, useful to run r2 commands 14 | # with rlang.cmd() to set variables or create IO maps 15 | def init(): 16 | r2lang.cmd("e asm.syntax=intel") 17 | return 18 | 19 | # describes layout of register file for the architecture 20 | # return: string with layout of the register file 21 | def regs(): 22 | return "=PC pc\n" + \ 23 | "=SP sp\n" + \ 24 | "=A0 r0\n" + \ 25 | "gpr r0 .32 0 0\n" + \ 26 | "gpr r1 .32 4 0\n" + \ 27 | "gpr r2 .32 8 0\n" + \ 28 | "gpr r3 .32 12 0\n" + \ 29 | "gpr r4 .32 16 0\n" + \ 30 | "gpr r5 .32 20 0\n" + \ 31 | "gpr sp .32 24 0\n" + \ 32 | "gpr pc .32 28 0\n" 33 | 34 | # provides radare2 with information about instruction size and memory alignment 35 | # query: attribute requested 36 | # return: value of requested attribute 37 | def info(query): 38 | arch_info = { 39 | R.R_ARCH_INFO_MINOP_SIZE: 1, 40 | R.R_ARCH_INFO_MAXOP_SIZE: 2, 41 | R.R_ARCH_INFO_INVOP_SIZE: 1, # invalid op size 42 | R.R_ARCH_INFO_CODE_ALIGN: 1, 43 | R.R_ARCH_INFO_DATA_ALIGN: 1, 44 | R.R_ARCH_INFO_DATA2_ALIGN: 2, 45 | R.R_ARCH_INFO_DATA4_ALIGN: 4, 46 | R.R_ARCH_INFO_DATA8_ALIGN: 8 47 | } 48 | res = arch_info.get(query) 49 | if res is None: 50 | return 0 51 | else: 52 | return res 53 | 54 | # decodes machine code and returns information about the instruction 55 | # buf: buffer with bytes to decode 56 | # pc: memory address where the buffer came from 57 | # mask: information requested by radare, use is optional for better performance 58 | # see radare2/libr/include/r_arch.h for documentation 59 | # return: list object with: 60 | # number of bytes processed in from buf to decode instruction 61 | # dict with disassembly and metadata about the instruction, most important fields are: 62 | # mnemonic: string with disassembled instruction, as shown to user 63 | # type: type of instruction 64 | # jump: target address for branch instructions 65 | # ptr: address for instructions that access memory 66 | # see radare2/libr/include/r_anal/op.h for more details and complete list of fields 67 | def decode(buf, pc, mask): 68 | ops = { 69 | 0: { 70 | "op": { 71 | "mnemonic" : "nop", 72 | "type" : R.R_ANAL_OP_TYPE_NOP, 73 | "cycles" : 1, 74 | }, 75 | "size": 1 76 | }, 77 | 1: { 78 | "op": { 79 | "mnemonic" : "mov r{}, 0x{:02x}".format(buf[1], buf[2]), 80 | "type" : R.R_ANAL_OP_TYPE_MOV, 81 | "cycles" : 2, 82 | "ptr" : buf[2], 83 | "direction" : R.R_ANAL_OP_DIR_READ, 84 | }, 85 | "size": 3 86 | }, 87 | 2: { 88 | "op": { 89 | "mnemonic" : "fadd r{}, 0x{:02x}".format(buf[1], buf[2]), 90 | "type" : R.R_ANAL_OP_TYPE_ADD, 91 | "family" : R.R_ANAL_OP_FAMILY_FPU, 92 | "cycles" : 2, 93 | "val" : buf[2], 94 | }, 95 | "size": 3 96 | }, 97 | 3: { 98 | "op": { 99 | "mnemonic" : "jne 0x{:04x}".format((buf[1] << 8) | buf[2]), 100 | "type" : R.R_ANAL_OP_TYPE_CJMP, 101 | "cycles" : 2, 102 | "jump" : (buf[1] << 8) | buf[2], 103 | "fail" : pc+3, 104 | "cond" : R.R_ANAL_COND_NE, 105 | "eob" : True 106 | }, 107 | "size": 3 108 | } 109 | } 110 | decoded_op = ops.get(buf[0]) 111 | if decoded_op is None: 112 | return [ 2, None ] 113 | return [ decoded_op.get("size"), decoded_op.get("op") ] 114 | 115 | # assembles provided string into machine code 116 | # addr: memory address where assembled instruction will be located 117 | # str: line of code to assemble 118 | # return: bytes of assembled code, or None on error 119 | def encode(addr, str): 120 | import pyparsing as pp 121 | p = pp.Word(pp.alphanums) + pp.Optional( pp.Word(pp.alphanums) + pp.Optional(',' + pp.Word(pp.alphanums))) 122 | asm = p.parseString(str) 123 | if asm[0] == "nop": 124 | return b'\x00' 125 | elif asm[0] == "mov" and len(asm) == 4: 126 | if asm[1].startswith("r"): 127 | if asm[3].isdigit(): 128 | return bytes([1, int(asm[1][1:]), int(asm[3])]) 129 | if asm[3].startswith("0x"): 130 | return bytes([1, int(asm[1][1:]), int(asm[3], 16)]) 131 | return None 132 | 133 | # definition of the architecture this plugin implements 134 | # return: dict with metadata about the plugin, and the functions that implement the plugin 135 | # name: pretty name of the plugin 136 | # arch: identifier used for referencing architecture in radare, e.g. via: e asm.arch=x 137 | # bits: bits of this architecture 138 | # regs: layout of register file 139 | # info: info about instruction size and memory alignment 140 | # decode: disassemble code 141 | # encode: assemble code 142 | return { 143 | "name": "MyPyArch", 144 | "arch": "pyarch", 145 | "bits": 32, 146 | "license": "GPL", 147 | "desc": "arch plugin in python", 148 | "init": init, 149 | "regs": regs, 150 | "info": info, 151 | "decode": decode, 152 | "encode": encode, 153 | } 154 | 155 | # The r2lang.plugin function registers the plugin with radare2 156 | if not r2lang.plugin("arch", pyarch): 157 | print("Failed to register the python arch plugin.") 158 | -------------------------------------------------------------------------------- /typescript/mujs/r2pipe.ts: -------------------------------------------------------------------------------- 1 | export type InstructionType = "mov" | "jmp" | "cmp" | "nop" | "call"; 2 | export type InstructionFamily = "cpu" | "fpu" | "priv"; 3 | 4 | export interface SearchResult { 5 | offset: number; 6 | type: string; 7 | data: string; 8 | }; 9 | 10 | export interface Flag { 11 | name: string; 12 | size: number; 13 | offset: number; 14 | }; 15 | export interface CallRef { 16 | addr: number; 17 | type: string; 18 | at: number; 19 | }; 20 | 21 | export interface Function { 22 | offset: number; 23 | name: string; 24 | size: number; 25 | noreturn: boolean; 26 | stackframe: number; 27 | ebbs: number; 28 | signature: string; 29 | nbbs: number; 30 | callrefs: CallRef[]; 31 | codexrefs: CallRef[]; 32 | }; 33 | 34 | export interface BinFile { 35 | arch: string; 36 | static: boolean; 37 | va: boolean; 38 | stripped: boolean; 39 | pic: boolean; 40 | relocs: boolean; 41 | sanitize: boolean; 42 | baddr: number; 43 | binsz: number; 44 | bintype: string; 45 | bits: number; 46 | canary: boolean; 47 | class: string; 48 | compiler: string; 49 | endian: string; 50 | machine: string; 51 | nx: boolean; 52 | os: string; 53 | laddr: number; 54 | linenum: boolean; 55 | havecode: boolean; 56 | intrp: string; 57 | 58 | }; 59 | 60 | export interface Reference { 61 | from: number; 62 | type: string; 63 | perm: string; 64 | opcode: string; 65 | fcn_addr: number; 66 | fcn_name: string; 67 | realname: string; 68 | refname: string; 69 | }; 70 | 71 | export interface BasicBlock { 72 | addr: number, 73 | size: number, 74 | jump: number, 75 | fail: number, 76 | opaddr: number, 77 | inputs: number, 78 | outputs: number, 79 | ninstr: number, 80 | instrs: number[], 81 | traced: boolean 82 | }; 83 | 84 | export interface Instruction { 85 | type: InstructionType; 86 | addr: number; 87 | opcode: string; 88 | pseudo: string; 89 | mnemonic: string; 90 | sign: boolean; 91 | family: InstructionFamily; 92 | description: string; 93 | esil: string; 94 | opex: any; 95 | size: number; 96 | ptr: number; 97 | bytes: string; 98 | id: number; 99 | refptr: number; 100 | direction: "read" | "write"; 101 | stackptr: number; 102 | stack: string; // "inc"|"dec"|"get"|"set"|"nop"|"null"; 103 | } 104 | 105 | export interface R2Pipe { 106 | cmd(cmd: string): string; 107 | log(msg: string): string; 108 | } 109 | 110 | 111 | export class R2Api { 112 | public r2: R2Pipe; 113 | 114 | constructor(r2: R2Pipe) { 115 | this.r2 = r2; 116 | } 117 | 118 | clearScreen() { 119 | this.r2.cmd("!clear"); 120 | } 121 | getRegisters(): any { 122 | // this.r2.log("winrar" + JSON.stringify(JSON.parse(this.r2.cmd("drj")),null, 2) ); 123 | return this.cmdj("drj"); 124 | } 125 | setRegisters(obj: any) { 126 | for (let r of Object.keys(obj)) { 127 | const v = obj[r]; 128 | this.r2.cmd("dr " + r + "=" + v); 129 | } 130 | } 131 | analyzeProgram(): void { 132 | this.r2.cmd("aa"); 133 | } 134 | hex(s: number | string): string { 135 | return this.r2.cmd("?v " + s).trim(); 136 | } 137 | step(): R2Api { 138 | this.r2.cmd("ds"); 139 | return this; 140 | } 141 | stepOver(): R2Api { 142 | this.r2.cmd("dso"); 143 | return this; 144 | } 145 | math(expr: number | string): number { 146 | return +this.r2.cmd("?v " + expr); 147 | } 148 | searchString(s: string): SearchResult[] { 149 | const res: SearchResult[] = this.cmdj("/j " + s); 150 | return res; 151 | } 152 | binInfo(): BinFile { 153 | try { 154 | return this.cmdj("ij~{bin}"); 155 | } catch (e: any) { 156 | return {} as BinFile; 157 | } 158 | } 159 | skip() { 160 | this.r2.cmd("dss"); 161 | } 162 | ptr(s: string | number): NativePointer { 163 | return new NativePointer(this, s); 164 | } 165 | cmd(s: string): string { 166 | return this.r2.cmd(s); 167 | } 168 | cmdj(s: string): any { 169 | return JSON.parse(this.cmd(s)); 170 | } 171 | log(s: string) { 172 | return this.r2.log(s); 173 | } 174 | clippy(msg: string): void { 175 | this.r2.log(this.r2.cmd("?E " + msg)); 176 | } 177 | ascii(msg: string): void { 178 | this.r2.log(this.r2.cmd("?ea " + msg)); 179 | } 180 | listFunctions() : Function[] { 181 | return this.cmdj("aflj"); 182 | } 183 | listFlags() : Flag[] { 184 | return this.cmdj("fj"); 185 | } 186 | } 187 | 188 | export class NativePointer { 189 | addr: string; 190 | api: R2Api; 191 | constructor(api: R2Api, s: string | number) { 192 | this.api = api; 193 | // this.api.r2.log("NP " + s); 194 | this.addr = "" + s; 195 | } 196 | readByteArray(len: number) { 197 | return JSON.parse(this.api.cmd(`p8j ${len}@${this.addr}`)); 198 | } 199 | add(a: number): NativePointer { 200 | this.addr = this.api.cmd(`?v ${this.addr} + ${a}`); 201 | return this; 202 | } 203 | sub(a: number): NativePointer { 204 | this.addr = this.api.cmd(`?v ${this.addr} - ${a}`); 205 | return this; 206 | } 207 | writeCString(s: string): NativePointer { 208 | this.api.cmd("\"w " + s + "\""); 209 | return this; 210 | } 211 | readCString(): string { 212 | return JSON.parse(this.api.cmd(`psj@${this.addr}`)).string; 213 | } 214 | instruction(): Instruction { 215 | const op: any = this.api.cmdj(`aoj@${this.addr}`)[0]; 216 | return op; 217 | } 218 | analyzeFunction() { 219 | this.api.cmd("af@" + this.addr); 220 | } 221 | name(): string { 222 | return this.api.cmd("fd " + this.addr).trim(); 223 | } 224 | basicBlock(): BasicBlock { 225 | const bb: BasicBlock = this.api.cmdj("abj@" + this.addr); 226 | return bb; 227 | } 228 | functionBasicBlocks(): BasicBlock[] { 229 | const bbs : BasicBlock[] = this.api.cmdj("afbj@"+this.addr); 230 | return bbs; 231 | } 232 | xrefs(): Reference[] { 233 | return this.api.cmdj("axtj@" + this.addr); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /typescript/tolua/r2pipe.ts: -------------------------------------------------------------------------------- 1 | export type InstructionType = "mov" | "jmp" | "cmp" | "nop" | "call"; 2 | export type InstructionFamily = "cpu" | "fpu" | "priv"; 3 | 4 | export interface SearchResult { 5 | offset: number; 6 | type: string; 7 | data: string; 8 | }; 9 | 10 | export interface Flag { 11 | name: string; 12 | size: number; 13 | offset: number; 14 | }; 15 | export interface CallRef { 16 | addr: number; 17 | type: string; 18 | at: number; 19 | }; 20 | 21 | export interface Function { 22 | offset: number; 23 | name: string; 24 | size: number; 25 | noreturn: boolean; 26 | stackframe: number; 27 | ebbs: number; 28 | signature: string; 29 | nbbs: number; 30 | callrefs: CallRef[]; 31 | codexrefs: CallRef[]; 32 | }; 33 | 34 | export interface BinFile { 35 | arch: string; 36 | static: boolean; 37 | va: boolean; 38 | stripped: boolean; 39 | pic: boolean; 40 | relocs: boolean; 41 | sanitize: boolean; 42 | baddr: number; 43 | binsz: number; 44 | bintype: string; 45 | bits: number; 46 | canary: boolean; 47 | class: string; 48 | compiler: string; 49 | endian: string; 50 | machine: string; 51 | nx: boolean; 52 | os: string; 53 | laddr: number; 54 | linenum: boolean; 55 | havecode: boolean; 56 | intrp: string; 57 | 58 | }; 59 | 60 | export interface Reference { 61 | from: number; 62 | type: string; 63 | perm: string; 64 | opcode: string; 65 | fcn_addr: number; 66 | fcn_name: string; 67 | realname: string; 68 | refname: string; 69 | }; 70 | 71 | export interface BasicBlock { 72 | addr: number, 73 | size: number, 74 | jump: number, 75 | fail: number, 76 | opaddr: number, 77 | inputs: number, 78 | outputs: number, 79 | ninstr: number, 80 | instrs: number[], 81 | traced: boolean 82 | }; 83 | 84 | export interface Instruction { 85 | type: InstructionType; 86 | addr: number; 87 | opcode: string; 88 | pseudo: string; 89 | mnemonic: string; 90 | sign: boolean; 91 | family: InstructionFamily; 92 | description: string; 93 | esil: string; 94 | opex: any; 95 | size: number; 96 | ptr: number; 97 | bytes: string; 98 | id: number; 99 | refptr: number; 100 | direction: "read" | "write"; 101 | stackptr: number; 102 | stack: string; // "inc"|"dec"|"get"|"set"|"nop"|"null"; 103 | } 104 | 105 | export interface R2Pipe { 106 | cmd(cmd: string): string; 107 | log(msg: string): string; 108 | } 109 | 110 | 111 | export class R2Api { 112 | public r2: R2Pipe; 113 | 114 | constructor(r2: R2Pipe) { 115 | this.r2 = r2; 116 | } 117 | 118 | clearScreen() { 119 | this.r2.cmd("!clear"); 120 | } 121 | getRegisters(): any { 122 | // this.r2.log("winrar" + JSON.stringify(JSON.parse(this.r2.cmd("drj")),null, 2) ); 123 | return this.cmdj("drj"); 124 | } 125 | setRegisters(obj: any) { 126 | for (let r of Object.keys(obj)) { 127 | const v = obj[r]; 128 | this.r2.cmd("dr " + r + "=" + v); 129 | } 130 | } 131 | analyzeProgram(): void { 132 | this.r2.cmd("aa"); 133 | } 134 | hex(s: number | string): string { 135 | return this.r2.cmd("?v " + s).trim(); 136 | } 137 | step(): R2Api { 138 | this.r2.cmd("ds"); 139 | return this; 140 | } 141 | stepOver(): R2Api { 142 | this.r2.cmd("dso"); 143 | return this; 144 | } 145 | math(expr: number | string): number { 146 | return +this.r2.cmd("?v " + expr); 147 | } 148 | searchString(s: string): SearchResult[] { 149 | const res: SearchResult[] = this.cmdj("/j " + s); 150 | return res; 151 | } 152 | binInfo(): BinFile { 153 | try { 154 | return this.cmdj("ij~{bin}"); 155 | } catch (e: any) { 156 | return {} as BinFile; 157 | } 158 | } 159 | skip() { 160 | this.r2.cmd("dss"); 161 | } 162 | ptr(s: string | number): NativePointer { 163 | return new NativePointer(this, s); 164 | } 165 | cmd(s: string): string { 166 | return this.r2.cmd(s); 167 | } 168 | cmdj(s: string): any { 169 | return JSON.parse(this.cmd(s)); 170 | } 171 | log(s: string) { 172 | return this.r2.log(s); 173 | } 174 | clippy(msg: string): void { 175 | this.r2.log(this.r2.cmd("?E " + msg)); 176 | } 177 | ascii(msg: string): void { 178 | this.r2.log(this.r2.cmd("?ea " + msg)); 179 | } 180 | listFunctions() : Function[] { 181 | return this.cmdj("aflj"); 182 | } 183 | listFlags() : Flag[] { 184 | return this.cmdj("fj"); 185 | } 186 | } 187 | 188 | export class NativePointer { 189 | addr: string; 190 | api: R2Api; 191 | constructor(api: R2Api, s: string | number) { 192 | this.api = api; 193 | // this.api.r2.log("NP " + s); 194 | this.addr = "" + s; 195 | } 196 | readByteArray(len: number) { 197 | return JSON.parse(this.api.cmd(`p8j ${len}@${this.addr}`)); 198 | } 199 | add(a: number): NativePointer { 200 | this.addr = this.api.cmd(`?v ${this.addr} + ${a}`); 201 | return this; 202 | } 203 | sub(a: number): NativePointer { 204 | this.addr = this.api.cmd(`?v ${this.addr} - ${a}`); 205 | return this; 206 | } 207 | writeCString(s: string): NativePointer { 208 | this.api.cmd("\"w " + s + "\""); 209 | return this; 210 | } 211 | readCString(): string { 212 | return JSON.parse(this.api.cmd(`psj@${this.addr}`)).string; 213 | } 214 | instruction(): Instruction { 215 | const op: any = this.api.cmdj(`aoj@${this.addr}`)[0]; 216 | return op; 217 | } 218 | analyzeFunction() { 219 | this.api.cmd("af@" + this.addr); 220 | } 221 | name(): string { 222 | return this.api.cmd("fd " + this.addr).trim(); 223 | } 224 | basicBlock(): BasicBlock { 225 | const bb: BasicBlock = this.api.cmdj("abj@" + this.addr); 226 | return bb; 227 | } 228 | functionBasicBlocks(): BasicBlock[] { 229 | const bbs : BasicBlock[] = this.api.cmdj("afbj@"+this.addr); 230 | return bbs; 231 | } 232 | xrefs(): Reference[] { 233 | return this.api.cmdj("axtj@" + this.addr); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /lua/lib/r2api.lua.c: -------------------------------------------------------------------------------- 1 | const char *r2api_lua = "\x2d\x2d\x20\x72\x65\x71\x75\x69\x72\x65\x22\x6a\x73\x6f\x6e\x22\x0a\x2d\x2d\x20\x6c\x6f\x63\x61\x6c\x20\x69\x6e\x73\x70\x65\x63\x74\x20\x3d\x20\x72\x65\x71\x75\x69\x72\x65\x22\x69\x6e\x73\x70\x65\x63\x74\x22\x0a\x0a\x2d\x2d\x20\x67\x65\x6e\x65\x72\x69\x63\x20\x75\x74\x69\x6c\x69\x74\x69\x65\x73\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x73\x70\x6c\x69\x74\x28\x74\x65\x78\x74\x2c\x20\x73\x65\x70\x29\x0a\x09\x73\x65\x70\x20\x3d\x20\x73\x65\x70\x20\x6f\x72\x20\x22\x5c\x6e\x22\x0a\x09\x74\x65\x78\x74\x20\x3d\x20\x63\x68\x6f\x6d\x70\x28\x74\x65\x78\x74\x29\x0a\x09\x6c\x6f\x63\x61\x6c\x20\x6c\x69\x6e\x65\x73\x20\x3d\x20\x7b\x7d\x0a\x09\x6c\x6f\x63\x61\x6c\x20\x70\x6f\x73\x20\x3d\x20\x31\x0a\x09\x77\x68\x69\x6c\x65\x20\x74\x72\x75\x65\x20\x64\x6f\x0a\x09\x09\x6c\x6f\x63\x61\x6c\x20\x62\x2c\x65\x20\x3d\x20\x74\x65\x78\x74\x3a\x66\x69\x6e\x64\x28\x73\x65\x70\x2c\x20\x70\x6f\x73\x29\x0a\x09\x09\x69\x66\x20\x6e\x6f\x74\x20\x62\x20\x74\x68\x65\x6e\x20\x74\x61\x62\x6c\x65\x2e\x69\x6e\x73\x65\x72\x74\x28\x6c\x69\x6e\x65\x73\x2c\x20\x74\x65\x78\x74\x3a\x73\x75\x62\x28\x70\x6f\x73\x29\x29\x20\x62\x72\x65\x61\x6b\x20\x65\x6e\x64\x0a\x09\x09\x74\x61\x62\x6c\x65\x2e\x69\x6e\x73\x65\x72\x74\x28\x6c\x69\x6e\x65\x73\x2c\x20\x74\x65\x78\x74\x3a\x73\x75\x62\x28\x70\x6f\x73\x2c\x62\x2d\x31\x29\x29\x0a\x09\x09\x70\x6f\x73\x20\x3d\x20\x65\x20\x2b\x20\x31\x0a\x09\x65\x6e\x64\x0a\x09\x72\x65\x74\x75\x72\x6e\x20\x6c\x69\x6e\x65\x73\x0a\x65\x6e\x64\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x74\x72\x69\x6d\x28\x74\x65\x78\x74\x29\x0a\x09\x69\x66\x20\x74\x65\x78\x74\x20\x3d\x3d\x20\x6e\x69\x6c\x20\x74\x68\x65\x6e\x20\x72\x65\x74\x75\x72\x6e\x20\x22\x22\x20\x65\x6e\x64\x0a\x09\x74\x65\x78\x74\x20\x3d\x20\x73\x74\x72\x69\x6e\x67\x2e\x67\x73\x75\x62\x28\x74\x65\x78\x74\x2c\x20\x22\x20\x2a\x24\x22\x2c\x20\x22\x22\x29\x0a\x09\x74\x65\x78\x74\x20\x3d\x20\x73\x74\x72\x69\x6e\x67\x2e\x67\x73\x75\x62\x28\x74\x65\x78\x74\x2c\x20\x22\x5c\x6e\x24\x22\x2c\x20\x22\x22\x29\x0a\x09\x72\x65\x74\x75\x72\x6e\x20\x73\x74\x72\x69\x6e\x67\x2e\x67\x73\x75\x62\x28\x74\x65\x78\x74\x2c\x20\x22\x5e\x20\x2a\x22\x2c\x20\x22\x22\x29\x0a\x65\x6e\x64\x0a\x0a\x2d\x2d\x20\x72\x32\x61\x70\x69\x20\x73\x74\x61\x72\x74\x73\x20\x68\x65\x72\x65\x0a\x0a\x72\x32\x20\x3d\x20\x7b\x7d\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x2e\x63\x6d\x64\x28\x78\x29\x0a\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x32\x63\x6d\x64\x28\x78\x29\x0a\x65\x6e\x64\x0a\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x2e\x63\x6d\x64\x6a\x28\x78\x29\x0a\x20\x20\x6c\x6f\x63\x61\x6c\x20\x72\x65\x73\x20\x3d\x20\x74\x72\x69\x6d\x28\x72\x32\x63\x6d\x64\x28\x78\x29\x29\x0a\x20\x20\x69\x66\x20\x72\x65\x73\x5b\x30\x5d\x20\x3d\x3d\x20\x22\x5b\x22\x20\x74\x68\x65\x6e\x20\x61\x73\x73\x65\x72\x74\x28\x22\x55\x46\x43\x4b\x22\x29\x20\x65\x6e\x64\x0a\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6a\x73\x6f\x6e\x2e\x64\x65\x63\x6f\x64\x65\x28\x72\x65\x73\x29\x0a\x65\x6e\x64\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x2e\x67\x65\x74\x43\x6f\x6e\x66\x69\x67\x28\x78\x29\x0a\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x32\x63\x6d\x64\x28\x22\x65\x20\x22\x2e\x2e\x78\x29\x0a\x65\x6e\x64\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x2e\x73\x65\x74\x43\x6f\x6e\x66\x69\x67\x28\x78\x2c\x20\x79\x29\x0a\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x32\x63\x6d\x64\x28\x22\x65\x20\x22\x2e\x2e\x78\x2e\x2e\x22\x3d\x22\x2e\x2e\x79\x29\x0a\x65\x6e\x64\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x2e\x61\x6e\x61\x6c\x79\x7a\x65\x50\x72\x6f\x67\x72\x61\x6d\x28\x29\x0a\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x32\x63\x6d\x64\x28\x22\x61\x61\x22\x29\x0a\x65\x6e\x64\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x2e\x66\x75\x6e\x63\x74\x69\x6f\x6e\x42\x61\x73\x69\x63\x42\x6c\x6f\x63\x6b\x73\x28\x29\x0a\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x70\x6c\x69\x74\x28\x72\x32\x63\x6d\x64\x28\x22\x61\x62\x6c\x71\x22\x29\x2c\x22\x5c\x6e\x22\x29\x0a\x65\x6e\x64\x0a\x0a\x2d\x2d\x20\x6c\x6f\x63\x61\x6c\x20\x69\x6e\x73\x70\x65\x63\x74\x20\x3d\x20\x72\x65\x71\x75\x69\x72\x65\x22\x69\x6e\x73\x70\x65\x63\x74\x22\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x72\x32\x3a\x70\x74\x72\x20\x28\x61\x74\x29\x0a\x09\x6f\x20\x3d\x20\x7b\x61\x64\x64\x72\x20\x3d\x20\x74\x72\x69\x6d\x28\x61\x74\x29\x7d\x20\x20\x20\x2d\x2d\x20\x63\x72\x65\x61\x74\x65\x20\x6f\x62\x6a\x65\x63\x74\x20\x69\x66\x20\x75\x73\x65\x72\x20\x64\x6f\x65\x73\x20\x6e\x6f\x74\x20\x70\x72\x6f\x76\x69\x64\x65\x20\x6f\x6e\x65\x0a\x09\x73\x65\x74\x6d\x65\x74\x61\x74\x61\x62\x6c\x65\x28\x6f\x2c\x20\x73\x65\x6c\x66\x29\x0a\x09\x73\x65\x6c\x66\x2e\x5f\x5f\x69\x6e\x64\x65\x78\x20\x3d\x20\x73\x65\x6c\x66\x0a\x09\x6f\x2e\x72\x65\x61\x64\x42\x79\x74\x65\x73\x20\x3d\x20\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x73\x65\x6c\x66\x2c\x20\x6e\x29\x0a\x09\x09\x72\x65\x74\x75\x72\x6e\x20\x6a\x73\x6f\x6e\x2e\x64\x65\x63\x6f\x64\x65\x28\x72\x32\x63\x6d\x64\x28\x22\x70\x38\x6a\x20\x22\x2e\x2e\x6e\x2e\x2e\x22\x40\x22\x2e\x2e\x6f\x2e\x61\x64\x64\x72\x29\x29\x0a\x09\x65\x6e\x64\x0a\x09\x6f\x2e\x69\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\x6e\x20\x3d\x20\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x73\x65\x6c\x66\x29\x0a\x09\x09\x72\x65\x74\x75\x72\x6e\x20\x6a\x73\x6f\x6e\x2e\x64\x65\x63\x6f\x64\x65\x28\x72\x32\x63\x6d\x64\x28\x22\x61\x6f\x6a\x40\x22\x2e\x2e\x6f\x2e\x61\x64\x64\x72\x2e\x2e\x22\x7e\x7b\x5b\x30\x5d\x7d\x22\x29\x29\x0a\x09\x65\x6e\x64\x0a\x09\x6f\x2e\x61\x64\x64\x20\x3d\x20\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x73\x65\x6c\x66\x2c\x20\x78\x29\x0a\x09\x09\x6f\x2e\x61\x64\x64\x72\x20\x3d\x20\x74\x72\x69\x6d\x28\x72\x32\x63\x6d\x64\x28\x22\x3f\x76\x20\x22\x2e\x2e\x6f\x2e\x61\x64\x64\x72\x2e\x2e\x22\x2b\x22\x2e\x2e\x78\x29\x29\x0a\x09\x09\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x0a\x09\x65\x6e\x64\x0a\x09\x72\x65\x74\x75\x72\x6e\x20\x6f\x0a\x65\x6e\x64\x0a\x0a\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x68\x65\x78\x28\x78\x29\x0a\x09\x72\x65\x74\x75\x72\x6e\x20\x73\x74\x72\x69\x6e\x67\x2e\x66\x6f\x72\x6d\x61\x74\x28\x22\x30\x78\x25\x30\x38\x78\x22\x2c\x20\x78\x29\x0a\x65\x6e\x64\x0a" 2 | ; 3 | -------------------------------------------------------------------------------- /zforth/zforth.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2024 pancake */ 2 | /* zForth extension for radare2 */ 3 | 4 | #include 5 | #include "zforth.h" 6 | 7 | // XXX 8 | //#define RUBYAPI LIBDIR"/ruby1.8/radare.rb" 9 | #define RUBYAPI "/usr/lib/radare2/"R2_VERSION"/radare.rb" 10 | 11 | #include "r_core.h" 12 | 13 | static RCore *Gcore = NULL; 14 | 15 | zf_result do_eval(const char *src, int line, const char *buf) { 16 | const char *msg = NULL; 17 | zf_result rv = zf_eval (buf); 18 | 19 | switch (rv) { 20 | case ZF_OK: break; 21 | case ZF_ABORT_INTERNAL_ERROR: msg = "internal error"; break; 22 | case ZF_ABORT_OUTSIDE_MEM: msg = "outside memory"; break; 23 | case ZF_ABORT_DSTACK_OVERRUN: msg = "dstack overrun"; break; 24 | case ZF_ABORT_DSTACK_UNDERRUN: msg = "dstack underrun"; break; 25 | case ZF_ABORT_RSTACK_OVERRUN: msg = "rstack overrun"; break; 26 | case ZF_ABORT_RSTACK_UNDERRUN: msg = "rstack underrun"; break; 27 | case ZF_ABORT_NOT_A_WORD: msg = "not a word"; break; 28 | case ZF_ABORT_COMPILE_ONLY_WORD: msg = "compile-only word"; break; 29 | case ZF_ABORT_INVALID_SIZE: msg = "invalid size"; break; 30 | case ZF_ABORT_DIVISION_BY_ZERO: msg = "division by zero"; break; 31 | default: msg = "unknown error"; 32 | } 33 | 34 | if (msg) { 35 | fprintf (stderr, "\033[31m"); 36 | if (src) { 37 | fprintf (stderr, "%s:%d: ", src, line); 38 | } 39 | fprintf (stderr, "%s\033[0m\n", msg); 40 | } 41 | return rv; 42 | } 43 | static void save(const char *fname) { 44 | size_t len; 45 | void *p = zf_dump(&len); 46 | FILE *f = fopen(fname, "wb"); 47 | if(f) { 48 | fwrite(p, 1, len, f); 49 | fclose(f); 50 | } 51 | } 52 | 53 | void include(const char *fname) { 54 | char buf[256]; 55 | FILE *f = fopen (fname, "rb"); 56 | int line = 1; 57 | if(f) { 58 | while (fgets (buf, sizeof(buf), f)) { 59 | do_eval (fname, line++, buf); 60 | } 61 | fclose (f); 62 | } else { 63 | fprintf(stderr, "error opening file '%s': %s\n", fname, strerror(errno)); 64 | } 65 | } 66 | 67 | // TODO: use rlog 68 | void zf_host_trace(const char *fmt, va_list va) { 69 | fprintf (stderr, "\033[1;30m"); 70 | vfprintf (stderr, fmt, va); 71 | fprintf (stderr, "\033[0m"); 72 | } 73 | 74 | // TODO use rnum 75 | zf_cell zf_host_parse_num(const char *buf) { 76 | zf_cell v; 77 | int n = 0; 78 | int r = sscanf (buf, ZF_SCAN_FMT"%n", &v, &n); 79 | if (r != 1 || buf[n] != '\0') { 80 | zf_abort (ZF_ABORT_NOT_A_WORD); 81 | } 82 | return v; 83 | } 84 | 85 | 86 | #define ZF_SYSCALL_R2CMD ZF_SYSCALL_USER + 10 87 | 88 | zf_input_state zf_host_sys(zf_syscall_id id, const char *input) { 89 | switch ((int)id) { 90 | /* The core system callbacks */ 91 | case ZF_SYSCALL_EMIT: 92 | putchar ((char)zf_pop()); 93 | fflush (stdout); 94 | break; 95 | case ZF_SYSCALL_PRINT: 96 | printf(ZF_CELL_FMT " ", zf_pop()); 97 | break; 98 | 99 | case ZF_SYSCALL_TELL: { 100 | zf_cell len = zf_pop (); 101 | zf_cell addr = zf_pop (); 102 | if(addr >= ZF_DICT_SIZE - len) { 103 | zf_abort (ZF_ABORT_OUTSIDE_MEM); 104 | } 105 | void *buf = (uint8_t *)zf_dump(NULL) + (int)addr; 106 | (void)fwrite (buf, 1, len, stdout); 107 | fflush(stdout); } 108 | break; 109 | 110 | /* Application specific callbacks */ 111 | 112 | case ZF_SYSCALL_USER + 0: 113 | printf("\n"); 114 | exit(0); 115 | break; 116 | 117 | case ZF_SYSCALL_USER + 1: 118 | zf_push(sin(zf_pop())); 119 | break; 120 | 121 | case ZF_SYSCALL_USER + 2: 122 | if(input == NULL) { 123 | return ZF_INPUT_PASS_WORD; 124 | } 125 | include(input); 126 | break; 127 | 128 | case ZF_SYSCALL_USER + 3: 129 | save ("zforth.save"); 130 | break; 131 | 132 | case ZF_SYSCALL_USER + 4: // ZF_SYSCALL_R2CMD: 133 | { 134 | zf_cell len = zf_pop(); 135 | zf_cell addr = zf_pop(); 136 | if(addr >= ZF_DICT_SIZE - len) { 137 | zf_abort(ZF_ABORT_OUTSIDE_MEM); 138 | } 139 | void *buf = (uint8_t *)zf_dump(NULL) + (int)addr; 140 | char *cmd = r_str_ndup (buf, len); 141 | bool utf8 = r_config_get_i (Gcore->config, "scr.utf8"); 142 | int color = r_config_get_i (Gcore->config, "scr.color"); 143 | r_config_set_i (Gcore->config, "scr.color", 0); 144 | r_config_set_b (Gcore->config, "scr.utf8", false); 145 | char *res = r_core_cmd_str (Gcore, cmd); 146 | if (!res) { 147 | R_LOG_ERROR ("Cannot execute command"); 148 | return ZF_INPUT_INTERPRET; 149 | } 150 | res = r_str_replace_all (res, " \"", " '"); 151 | r_config_set_i (Gcore->config, "scr.color", color); 152 | r_config_set_b (Gcore->config, "scr.utf8", utf8); 153 | free (cmd); 154 | char *out = r_str_newf ("s\" %s \"", res); 155 | do_eval (cmd, 0, out); 156 | free (out); 157 | // eprintf ("--> %s\n", res); 158 | free (res); 159 | } 160 | break; 161 | default: 162 | R_LOG_ERROR ("unhandled syscall %d", id); 163 | break; 164 | } 165 | 166 | return ZF_INPUT_INTERPRET; 167 | } 168 | 169 | static bool run(RLangSession *ls, const char *code, int len) { 170 | RCore *core = ls->lang->user; 171 | Gcore = core; 172 | // zf_result err = zf_eval (code); 173 | zf_result err = do_eval ("-", 0, code); 174 | if (err != ZF_OK) { 175 | fprintf (stderr, "error %d handled\n", err); 176 | return false; 177 | } 178 | return true; 179 | } 180 | 181 | static bool run_file(RLangSession *ls, const char *file) { 182 | RCore *core = ls->lang->user; 183 | Gcore = core; 184 | if (r_file_exists (file)) { 185 | char *contents = r_file_slurp (file, NULL); 186 | zf_eval (contents); 187 | return true; 188 | } 189 | R_LOG_ERROR ("lang_zforth: Cannot open '%s'\n", file); 190 | return false; 191 | } 192 | 193 | #define buf core_zf 194 | // include("zForth/forth/core.zf"); 195 | #include "core_zf.h" 196 | #undef buf 197 | 198 | static bool init(RLangSession *user) { 199 | int trace = 0; 200 | zf_init (trace); 201 | zf_bootstrap (); 202 | 203 | zf_eval ((const char *)core_zf); 204 | return true; 205 | } 206 | 207 | static const char *help = 208 | "zForth plugin usage:\n" 209 | " 1 2 + .\n"; 210 | 211 | static RLangPlugin r_lang_plugin_ruby = { 212 | .meta = { 213 | .name = "zforth", 214 | .desc = "zForth language extension", 215 | }, 216 | .ext = "zf", 217 | .init = &init, 218 | .help = &help, 219 | .run = &run, 220 | .run_file = &run_file, 221 | .set_argv = NULL, 222 | }; 223 | 224 | #ifndef CORELIB 225 | RLibStruct radare_plugin = { 226 | .type = R_LIB_TYPE_LANG, 227 | .version = R2_VERSION, 228 | .data = &r_lang_plugin_ruby, 229 | }; 230 | #endif 231 | -------------------------------------------------------------------------------- /lua/lua.c: -------------------------------------------------------------------------------- 1 | /* lang.lua plugin for r2 - 2013-2024 - pancake */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define LIBDIR PREFIX"/lib" 11 | 12 | #include "lib/inspect.lua.c" 13 | #undef _BUFFER_SIZE 14 | #include "lib/json.lua.c" 15 | #undef _BUFFER_SIZE 16 | #include "lib/r2api.lua.c" 17 | 18 | static void stackDump (lua_State *L) { 19 | int i, top = lua_gettop (L); 20 | if (top < 1) { 21 | return; 22 | } 23 | for (i = 1; i <= top; i++) { /* repeat for each level */ 24 | int t = lua_type (L, i); 25 | switch (t) { 26 | case LUA_TSTRING: /* strings */ 27 | printf ("`%s'", lua_tostring(L, i)); 28 | break; 29 | case LUA_TBOOLEAN: /* booleans */ 30 | printf (lua_toboolean(L, i) ? "true" : "false"); 31 | break; 32 | case LUA_TNUMBER: /* numbers */ 33 | printf ("%g", lua_tonumber(L, i)); 34 | break; 35 | default: /* other values */ 36 | printf ("%s", lua_typename(L, t)); 37 | break; 38 | } 39 | printf(" "); /* put a separator */ 40 | } 41 | printf ("\n"); /* end the listing */ 42 | } 43 | 44 | static bool lua_run(RLangSession *s, const char *code, int len) { 45 | RCore *core = s->lang->user; 46 | lua_State *L = s->plugin_data; 47 | if (len < 1) { 48 | len = strlen (code); 49 | } 50 | lua_settop (L, 0); // reset the lua stack 51 | luaL_loadbuffer (L, code, len, ""); // \n included 52 | if (lua_pcall (L, 0, 0, 1) != LUA_OK) { 53 | R_LOG_ERROR ("syntax: %s in %s\n", lua_tostring (L, -1), ""); 54 | } 55 | stackDump (L); // show stack dump if anything is still there 56 | clearerr (stdin); 57 | return true; 58 | } 59 | 60 | static bool report_error(lua_State *L, int status) { 61 | if (status) { 62 | const char *msg = lua_tostring (L, -1); 63 | if (!msg) { 64 | msg = "(error with no message)"; 65 | } 66 | R_LOG_ERROR ("lua error: %s", msg); 67 | lua_pop (L, 1); 68 | return false; 69 | } 70 | return true; 71 | } 72 | 73 | static bool r_lua_file(RLangSession *s, const char *file) { 74 | lua_State *L = s->plugin_data; 75 | int res = luaL_loadfile (L, file); 76 | if (res != LUA_OK) { 77 | report_error (L, res); 78 | return false; 79 | } 80 | res = lua_pcall (L, 0, 0, 0); 81 | if (res != LUA_OK) { 82 | report_error (L, res); 83 | return false; 84 | } 85 | return true; 86 | } 87 | 88 | static int lua_cmd_str(lua_State *L) { 89 | lua_getglobal (L, "RCoreStar"); 90 | RCore *core = (RCore *)lua_touserdata (L, -1); 91 | const char *s = lua_tostring (L, 1); /* get argument */ 92 | char *str = r_core_cmd_str (core, s); 93 | lua_pushstring (L, r_str_get (str)); /* push result */ 94 | free (str); 95 | return 1; /* number of results */ 96 | } 97 | 98 | static int lua_cmd(lua_State *L) { 99 | lua_getglobal (L, "RCoreStar"); 100 | RCore *core = (RCore *)lua_touserdata (L, -1); 101 | const char *s = lua_tostring (L, 1); /* get argument */ 102 | lua_pushnumber (L, r_core_cmd (core, s, 0)); /* push result */ 103 | return 1; /* number of results */ 104 | } 105 | 106 | static bool init(RLangSession *s) { 107 | lua_State *L = luaL_newstate (); 108 | if (!L) { 109 | return false; 110 | } 111 | lua_gc (L, LUA_GCSTOP, 0); 112 | luaL_openlibs (L); 113 | luaopen_base (L); 114 | luaopen_string (L); 115 | //luaopen_io(L); // PANIC!! 116 | lua_gc (L, LUA_GCRESTART, 0); 117 | s->plugin_data = L; 118 | 119 | // we save the RCore pointer into this unused luaglobal state field 120 | // L->l_G->ud_warn = s->lang->user; 121 | void **ud = (void **)lua_newuserdata(L, sizeof(void *)); 122 | *ud = s->lang->user; // Store the original void* in the allocated memory 123 | // Store it in a global variable or table 124 | lua_setglobal(L, "RCoreStar"); 125 | #if 0 126 | // this mode is buggy because scripts can modify this global 127 | // and make r2cmd calls crash or execute arbitrary code 128 | lua_pushlightuserdata (L, lang->user); 129 | lua_setglobal (L, "core"); 130 | #endif 131 | 132 | lua_register (L, "r2cmd", &lua_cmd_str); 133 | lua_pushcfunction (L, lua_cmd_str); 134 | lua_setglobal (L, "r2cmd"); 135 | 136 | #if 0 137 | // DEPRECATED: cmd = radare_cmd_str 138 | lua_register(G.state, "cmd", &lua_cmd); 139 | lua_pushcfunction(G.state,lua_cmd); 140 | lua_setglobal(G.state,"cmd"); 141 | #endif 142 | #if 0 143 | luaL_loadbuffer (G.state, (const char *)json_lua, 9639, "json.lua"); 144 | luaL_loadbuffer (G.state, (const char *)inspect_lua, -1, "inspect.lua"); 145 | if (lua_pcall (G.state, 0, 0, 1) != 0) { 146 | eprintf ("syntax error(lang_lua): %s in %s\n", 147 | lua_tostring(G.state, -1), "inspect.lua"); 148 | } 149 | luaL_loadbuffer (G.state, (const char *)r2api_lua, -1, "r2api.lua"); 150 | if (lua_pcall (G.state, 0, 0, 1) != 0) { 151 | eprintf ("syntax error(lang_lua): %s in %s\n", 152 | lua_tostring(G.state, -1), "r2api"); 153 | } 154 | #else 155 | lua_run (s, (const char *)json_lua, -1); 156 | lua_run (s, (const char *)r2api_lua, -1); 157 | lua_run (s, (const char *)inspect_lua, -1); 158 | lua_run (s, "json.parse = json.decode", 0); 159 | lua_run (s, "JSON = json", 0); 160 | #endif 161 | 162 | // add custom loader for requiring from memory instead 163 | lua_run (s, "package.path=os.getenv(\"HOME\")..\"/.local/share/radare2/plugins/lua/?.lua;\"..package.path", 0); 164 | // lua_run (s, "json = require \"json\"", 0); 165 | lua_run (s, "function r2cmdj(x)\n" \ 166 | " return json.decode(r2cmd(x))\n" 167 | "end\n", 0); 168 | /* 169 | // this requires the native bindings to be built, nobody does that in 2019 170 | lua_run (s, "require \"r_core\"", 0); 171 | sprintf (a, "c=r_core.RCore_ncast(0x%"PFMT64x")", 172 | (ut64)(size_t)(void*)core); 173 | lua_run (s, a, 0); 174 | */ 175 | 176 | //-- load template 177 | /// DEPRECATED theres no need for this. better embed everything in into this .c 178 | // r_lua_file (NULL, LIBDIR"/radare2/"R2_VERSION"/r2api.lua"); 179 | // r_lua_file (NULL, LIBDIR"/radare2/"R2_VERSION"/r2api.lua"); 180 | s->plugin_data = L; 181 | return true; 182 | } 183 | 184 | static RLangPlugin r_lang_plugin_lua = { 185 | .meta = { 186 | .name = "lua", 187 | .license = "BSD-3-Clause", // LUA license is not an SPDX standard lol 188 | .desc = "LUA 5.4.4 language extension", 189 | }, 190 | .ext = "lua", 191 | .run = lua_run, 192 | .init = init, 193 | .run_file = r_lua_file, 194 | }; 195 | 196 | #ifndef CORELIB 197 | RLibStruct radare_plugin = { 198 | .type = R_LIB_TYPE_LANG, 199 | .data = &r_lang_plugin_lua, 200 | }; 201 | #endif 202 | -------------------------------------------------------------------------------- /duktape/duk/duk_console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Minimal 'console' binding. 3 | * 4 | * https://github.com/DeveloperToolsWG/console-object/blob/master/api.md 5 | * https://developers.google.com/web/tools/chrome-devtools/debug/console/console-reference 6 | * https://developer.mozilla.org/en/docs/Web/API/console 7 | */ 8 | 9 | #include 10 | #include 11 | #include "duktape.h" 12 | #include "duk_console.h" 13 | 14 | /* XXX: Add some form of log level filtering. */ 15 | 16 | /* XXX: Should all output be written via e.g. console.write(formattedMsg)? 17 | * This would make it easier for user code to redirect all console output 18 | * to a custom backend. 19 | */ 20 | 21 | /* XXX: Init console object using duk_def_prop() when that call is available. */ 22 | 23 | static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) { 24 | duk_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx); 25 | FILE *output = (flags & DUK_CONSOLE_STDOUT_ONLY) ? stdout : stderr; 26 | duk_idx_t n = duk_get_top(ctx); 27 | duk_idx_t i; 28 | 29 | duk_get_global_string(ctx, "console"); 30 | duk_get_prop_string(ctx, -1, "format"); 31 | 32 | for (i = 0; i < n; i++) { 33 | if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) { 34 | /* Slow path formatting. */ 35 | duk_dup(ctx, -1); /* console.format */ 36 | duk_dup(ctx, i); 37 | duk_call(ctx, 1); 38 | duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */ 39 | } 40 | } 41 | 42 | duk_pop_2(ctx); 43 | 44 | duk_push_string(ctx, " "); 45 | duk_insert(ctx, 0); 46 | duk_join(ctx, n); 47 | 48 | if (error_name) { 49 | duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1)); 50 | duk_push_string(ctx, "name"); 51 | duk_push_string(ctx, error_name); 52 | duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */ 53 | duk_get_prop_string(ctx, -1, "stack"); 54 | } 55 | 56 | fprintf(output, "%s\n", duk_to_string(ctx, -1)); 57 | if (flags & DUK_CONSOLE_FLUSH) { 58 | fflush(output); 59 | } 60 | return 0; 61 | } 62 | 63 | static duk_ret_t duk__console_assert(duk_context *ctx) { 64 | if (duk_to_boolean(ctx, 0)) { 65 | return 0; 66 | } 67 | duk_remove(ctx, 0); 68 | 69 | return duk__console_log_helper(ctx, "AssertionError"); 70 | } 71 | 72 | static duk_ret_t duk__console_log(duk_context *ctx) { 73 | return duk__console_log_helper(ctx, NULL); 74 | } 75 | 76 | static duk_ret_t duk__console_trace(duk_context *ctx) { 77 | return duk__console_log_helper(ctx, "Trace"); 78 | } 79 | 80 | static duk_ret_t duk__console_info(duk_context *ctx) { 81 | return duk__console_log_helper(ctx, NULL); 82 | } 83 | 84 | static duk_ret_t duk__console_warn(duk_context *ctx) { 85 | return duk__console_log_helper(ctx, NULL); 86 | } 87 | 88 | static duk_ret_t duk__console_error(duk_context *ctx) { 89 | return duk__console_log_helper(ctx, "Error"); 90 | } 91 | 92 | static duk_ret_t duk__console_dir(duk_context *ctx) { 93 | /* For now, just share the formatting of .log() */ 94 | return duk__console_log_helper(ctx, 0); 95 | } 96 | 97 | static void duk__console_reg_vararg_func(duk_context *ctx, duk_c_function func, const char *name, duk_uint_t flags) { 98 | duk_push_c_function(ctx, func, DUK_VARARGS); 99 | duk_push_string(ctx, "name"); 100 | duk_push_string(ctx, name); 101 | duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); /* Improve stacktraces by displaying function name */ 102 | duk_set_magic(ctx, -1, (duk_int_t) flags); 103 | duk_put_prop_string(ctx, -2, name); 104 | } 105 | 106 | void duk_console_init(duk_context *ctx, duk_uint_t flags) { 107 | duk_uint_t flags_orig; 108 | 109 | /* If both DUK_CONSOLE_STDOUT_ONLY and DUK_CONSOLE_STDERR_ONLY where specified, 110 | * just turn off DUK_CONSOLE_STDOUT_ONLY and keep DUK_CONSOLE_STDERR_ONLY. 111 | */ 112 | if ((flags & DUK_CONSOLE_STDOUT_ONLY) && (flags & DUK_CONSOLE_STDERR_ONLY)) { 113 | flags &= ~DUK_CONSOLE_STDOUT_ONLY; 114 | } 115 | /* Remember the (possibly corrected) flags we received. */ 116 | flags_orig = flags; 117 | 118 | duk_push_object(ctx); 119 | 120 | /* Custom function to format objects; user can replace. 121 | * For now, try JX-formatting and if that fails, fall back 122 | * to ToString(v). 123 | */ 124 | duk_eval_string(ctx, 125 | "(function (E) {" 126 | "return function format(v){" 127 | "try{" 128 | "return E('jx',v);" 129 | "}catch(e){" 130 | "return String(v);" /* String() allows symbols, ToString() internal algorithm doesn't. */ 131 | "}" 132 | "};" 133 | "})(Duktape.enc)"); 134 | duk_put_prop_string(ctx, -2, "format"); 135 | 136 | flags = flags_orig; 137 | if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) { 138 | /* No output indicators were specified; these levels go to stdout. */ 139 | flags |= DUK_CONSOLE_STDOUT_ONLY; 140 | } 141 | duk__console_reg_vararg_func(ctx, duk__console_assert, "assert", flags); 142 | duk__console_reg_vararg_func(ctx, duk__console_log, "log", flags); 143 | duk__console_reg_vararg_func(ctx, duk__console_log, "debug", flags); /* alias to console.log */ 144 | duk__console_reg_vararg_func(ctx, duk__console_trace, "trace", flags); 145 | duk__console_reg_vararg_func(ctx, duk__console_info, "info", flags); 146 | 147 | flags = flags_orig; 148 | if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) { 149 | /* No output indicators were specified; these levels go to stderr. */ 150 | flags |= DUK_CONSOLE_STDERR_ONLY; 151 | } 152 | duk__console_reg_vararg_func(ctx, duk__console_warn, "warn", flags); 153 | duk__console_reg_vararg_func(ctx, duk__console_error, "error", flags); 154 | duk__console_reg_vararg_func(ctx, duk__console_error, "exception", flags); /* alias to console.error */ 155 | duk__console_reg_vararg_func(ctx, duk__console_dir, "dir", flags); 156 | 157 | duk_put_global_string(ctx, "console"); 158 | 159 | /* Proxy wrapping: ensures any undefined console method calls are 160 | * ignored silently. This was required specifically by the 161 | * DeveloperToolsWG proposal (and was implemented also by Firefox: 162 | * https://bugzilla.mozilla.org/show_bug.cgi?id=629607). This is 163 | * apparently no longer the preferred way of implementing console. 164 | * When Proxy is enabled, whitelist at least .toJSON() to avoid 165 | * confusing JX serialization of the console object. 166 | */ 167 | 168 | if (flags & DUK_CONSOLE_PROXY_WRAPPER) { 169 | /* Tolerate failure to initialize Proxy wrapper in case 170 | * Proxy support is disabled. 171 | */ 172 | (void) duk_peval_string_noresult(ctx, 173 | "(function(){" 174 | "var D=function(){};" 175 | "var W={toJSON:true};" /* whitelisted */ 176 | "console=new Proxy(console,{" 177 | "get:function(t,k){" 178 | "var v=t[k];" 179 | "return typeof v==='function'||W[k]?v:D;" 180 | "}" 181 | "});" 182 | "})();" 183 | ); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /python/python/anal.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2017-2022 - pancake, xvilka */ 2 | 3 | // Exporting the R_ANAL_* enum constants 4 | #include 5 | #include "anal.h" 6 | #include "core.h" 7 | 8 | void py_export_anal_enum(PyObject *tp_dict) { 9 | 10 | #define PYENUM(name) {\ 11 | PyObject *o = PyLong_FromLong(name); \ 12 | if (o) { \ 13 | PyDict_SetItemString(tp_dict, #name, o); \ 14 | Py_DECREF(o); \ 15 | }\ 16 | } 17 | 18 | // R_ANAL_OP_FAMILY_* 19 | PYENUM (R_ANAL_OP_FAMILY_UNKNOWN); 20 | PYENUM (R_ANAL_OP_FAMILY_CPU); 21 | PYENUM (R_ANAL_OP_FAMILY_FPU); 22 | #if 0 23 | PYENUM (R_ANAL_OP_FAMILY_MMX); 24 | PYENUM (R_ANAL_OP_FAMILY_SSE); 25 | #endif 26 | PYENUM (R_ANAL_OP_FAMILY_PRIV); 27 | PYENUM (R_ANAL_OP_FAMILY_CRYPTO); 28 | PYENUM (R_ANAL_OP_FAMILY_VIRT); 29 | PYENUM (R_ANAL_OP_FAMILY_IO); 30 | PYENUM (R_ANAL_OP_FAMILY_LAST); 31 | // R_ANAL_OP_TYPE_* 32 | PYENUM (R_ANAL_OP_TYPE_COND); 33 | PYENUM (R_ANAL_OP_TYPE_REP); 34 | PYENUM (R_ANAL_OP_TYPE_MEM); 35 | PYENUM (R_ANAL_OP_TYPE_REG); 36 | PYENUM (R_ANAL_OP_TYPE_IND); 37 | PYENUM (R_ANAL_OP_TYPE_NULL); 38 | PYENUM (R_ANAL_OP_TYPE_JMP); 39 | PYENUM (R_ANAL_OP_TYPE_UJMP); 40 | PYENUM (R_ANAL_OP_TYPE_RJMP); 41 | PYENUM (R_ANAL_OP_TYPE_IJMP); 42 | PYENUM (R_ANAL_OP_TYPE_IRJMP); 43 | PYENUM (R_ANAL_OP_TYPE_CJMP); 44 | PYENUM (R_ANAL_OP_TYPE_MJMP); 45 | PYENUM (R_ANAL_OP_TYPE_UCJMP); 46 | PYENUM (R_ANAL_OP_TYPE_CALL); 47 | PYENUM (R_ANAL_OP_TYPE_UCALL); 48 | PYENUM (R_ANAL_OP_TYPE_RCALL); 49 | PYENUM (R_ANAL_OP_TYPE_ICALL); 50 | PYENUM (R_ANAL_OP_TYPE_IRCALL); 51 | PYENUM (R_ANAL_OP_TYPE_CCALL); 52 | PYENUM (R_ANAL_OP_TYPE_UCCALL); 53 | PYENUM (R_ANAL_OP_TYPE_RET); 54 | PYENUM (R_ANAL_OP_TYPE_CRET); 55 | PYENUM (R_ANAL_OP_TYPE_ILL); 56 | PYENUM (R_ANAL_OP_TYPE_UNK); 57 | PYENUM (R_ANAL_OP_TYPE_NOP); 58 | PYENUM (R_ANAL_OP_TYPE_MOV); 59 | PYENUM (R_ANAL_OP_TYPE_CMOV); 60 | PYENUM (R_ANAL_OP_TYPE_TRAP); 61 | PYENUM (R_ANAL_OP_TYPE_SWI); 62 | PYENUM (R_ANAL_OP_TYPE_UPUSH); 63 | PYENUM (R_ANAL_OP_TYPE_PUSH); 64 | PYENUM (R_ANAL_OP_TYPE_POP); 65 | PYENUM (R_ANAL_OP_TYPE_CMP); 66 | PYENUM (R_ANAL_OP_TYPE_ACMP); 67 | PYENUM (R_ANAL_OP_TYPE_ADD); 68 | PYENUM (R_ANAL_OP_TYPE_SUB); 69 | PYENUM (R_ANAL_OP_TYPE_IO); 70 | PYENUM (R_ANAL_OP_TYPE_MUL); 71 | PYENUM (R_ANAL_OP_TYPE_DIV); 72 | PYENUM (R_ANAL_OP_TYPE_SHR); 73 | PYENUM (R_ANAL_OP_TYPE_SHL); 74 | PYENUM (R_ANAL_OP_TYPE_SAL); 75 | PYENUM (R_ANAL_OP_TYPE_SAR); 76 | PYENUM (R_ANAL_OP_TYPE_OR); 77 | PYENUM (R_ANAL_OP_TYPE_AND); 78 | PYENUM (R_ANAL_OP_TYPE_XOR); 79 | PYENUM (R_ANAL_OP_TYPE_NOR); 80 | PYENUM (R_ANAL_OP_TYPE_NOT); 81 | PYENUM (R_ANAL_OP_TYPE_STORE); 82 | PYENUM (R_ANAL_OP_TYPE_LOAD); 83 | PYENUM (R_ANAL_OP_TYPE_LEA); 84 | PYENUM (R_ANAL_OP_TYPE_LEAVE); 85 | PYENUM (R_ANAL_OP_TYPE_ROR); 86 | PYENUM (R_ANAL_OP_TYPE_ROL); 87 | PYENUM (R_ANAL_OP_TYPE_XCHG); 88 | PYENUM (R_ANAL_OP_TYPE_MOD); 89 | PYENUM (R_ANAL_OP_TYPE_SWITCH); 90 | PYENUM (R_ANAL_OP_TYPE_CASE); 91 | PYENUM (R_ANAL_OP_TYPE_LENGTH); 92 | PYENUM (R_ANAL_OP_TYPE_CAST); 93 | PYENUM (R_ANAL_OP_TYPE_NEW); 94 | PYENUM (R_ANAL_OP_TYPE_ABS); 95 | PYENUM (R_ANAL_OP_TYPE_CPL); 96 | PYENUM (R_ANAL_OP_TYPE_CRYPTO); 97 | PYENUM (R_ANAL_OP_TYPE_SYNC); 98 | // R_ANAL_STACK 99 | PYENUM (R_ANAL_STACK_NULL); 100 | PYENUM (R_ANAL_STACK_NOP); 101 | PYENUM (R_ANAL_STACK_INC); 102 | PYENUM (R_ANAL_STACK_GET); 103 | PYENUM (R_ANAL_STACK_SET); 104 | PYENUM (R_ANAL_STACK_RESET); 105 | PYENUM (R_ANAL_STACK_ALIGN); 106 | // R_ANAL_ARCHINFO 107 | PYENUM (R_ANAL_ARCHINFO_MIN_OP_SIZE); 108 | PYENUM (R_ANAL_ARCHINFO_MAX_OP_SIZE); 109 | PYENUM (R_ANAL_ARCHINFO_INV_OP_SIZE); 110 | PYENUM (R_ANAL_ARCHINFO_ALIGN); 111 | PYENUM (R_ANAL_ARCHINFO_DATA_ALIGN); 112 | #undef E 113 | } 114 | 115 | #define READ_REG(dict, reg) \ 116 | if (dict && PyDict_Check(dict)) { \ 117 | reg->name = getS (dict, "name"); \ 118 | reg->type = getI (dict, "type"); \ 119 | reg->size = getI (dict, "size"); \ 120 | reg->offset = getI (dict, "offset"); \ 121 | reg->packed_size = getI (dict, "packed_size"); \ 122 | reg->is_float = getB (dict, "is_float"); \ 123 | reg->flags = getS (dict, "flags"); \ 124 | reg->index = getI (dict, "index"); \ 125 | reg->arena = getI (dict, "arena"); \ 126 | } 127 | 128 | #define READ_VAL(dict, val, tmpreg) \ 129 | if (dict && PyDict_Check(dict)) { \ 130 | val->absolute = getI (dict, "absolute"); \ 131 | val->memref = getI (dict, "memref"); \ 132 | val->base = getI (dict, "base"); \ 133 | val->delta = getI (dict, "delta"); \ 134 | val->imm = getI (dict, "imm"); \ 135 | val->mul = getI (dict, "mul"); \ 136 | /* val->seg = getI (dict, "seg"); */ \ 137 | tmpreg = getO (dict, "reg"); \ 138 | READ_REG(tmpreg, val->reg) \ 139 | tmpreg = getO (dict, "regdelta"); \ 140 | READ_REG(tmpreg, val->regdelta) \ 141 | } 142 | 143 | static void *py_set_reg_profile_cb = NULL; 144 | static void *py_anal_cb = NULL; 145 | static void *py_archinfo_cb = NULL; 146 | 147 | static bool py_set_reg_profile(RAnal *a) { 148 | const char *profstr = ""; 149 | if (py_set_reg_profile_cb) { 150 | PyObject *result = PyObject_CallObject (py_set_reg_profile_cb, NULL); 151 | if (result) { 152 | profstr = PyUnicode_AsUTF8 (result); 153 | return r_reg_set_profile_string (a->reg, profstr); 154 | } else { 155 | eprintf ("Unknown type returned. String was expected.\n"); 156 | PyErr_Print(); 157 | } 158 | } 159 | return -1; 160 | } 161 | 162 | static int py_anal(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) { 163 | PyObject *tmpreg = NULL; 164 | int size = 0; 165 | int seize = -1; 166 | int i = 0; 167 | if (!op) return -1; 168 | if (py_anal_cb) { 169 | memset(op, 0, sizeof (RAnalOp)); 170 | // anal(addr, buf) - returns size + dictionary (structure) for RAnalOp 171 | Py_buffer pybuf = { 172 | .buf = (void *) buf, // Warning: const is lost when casting 173 | .len = len, 174 | .readonly = 1, 175 | .ndim = 1, 176 | .itemsize = 1, 177 | }; 178 | PyObject *memview = PyMemoryView_FromBuffer (&pybuf); 179 | PyObject *arglist = Py_BuildValue ("(NK)", memview, addr); 180 | PyObject *result = PyObject_CallObject (py_anal_cb, arglist); 181 | if (result && PyList_Check (result)) { 182 | PyObject *len = PyList_GetItem (result, 0); 183 | PyObject *dict = PyList_GetItem (result, 1); 184 | if (dict && PyDict_Check (dict)) { 185 | seize = PyNumber_AsSsize_t (len, NULL); 186 | op->type = getI (dict, "type"); 187 | op->cycles = getI (dict, "cycles"); 188 | op->size = seize; 189 | op->addr = getI (dict, "addr"); 190 | op->delay = getI (dict, "delay"); 191 | op->jump = getI (dict, "jump"); 192 | op->fail = getI (dict, "fail"); 193 | op->stackop = getI (dict, "stackop"); 194 | op->stackptr = getI (dict, "stackptr"); 195 | op->ptr = getI (dict, "ptr"); 196 | op->eob = getB (dict, "eob"); 197 | #if 0 198 | // Loading 'src' and 'dst' values 199 | // SRC is is a list of 3 elements 200 | PyObject *tmpsrc = getO (dict, "src"); 201 | if (tmpsrc && PyList_Check (tmpsrc)) { 202 | for (i = 0; i < 3; i++) { 203 | PyObject *tmplst = PyList_GetItem (tmpsrc, i); 204 | // Read value and underlying regs 205 | READ_VAL (tmplst, op->src[i], tmpreg) 206 | } 207 | } 208 | PyObject *tmpdst = getO (dict, "dst"); 209 | // Read value and underlying regs 210 | READ_VAL (tmpdst, op->dst, tmpreg) 211 | #endif 212 | // Loading 'var' value if presented 213 | r_strbuf_set (&op->esil, getS (dict, "esil")); 214 | op->mnemonic = r_str_new (getS (dict, "mnemonic")); 215 | // TODO: Add opex support here 216 | Py_DECREF (dict); 217 | } 218 | Py_DECREF (result); 219 | } else { 220 | eprintf ("Unknown type returned. List was expected.\n"); 221 | PyErr_Print (); 222 | } 223 | } 224 | op->size = size = seize; 225 | return seize; 226 | } 227 | 228 | static int py_archinfo(RAnal *a, int query) { 229 | if (py_archinfo_cb) { 230 | PyObject *arglist = Py_BuildValue ("(i)", query); 231 | PyObject *result = PyObject_CallObject (py_archinfo_cb, arglist); 232 | if (result) { 233 | return PyLong_AsLong (result); /* Python only returns long... */ 234 | } 235 | eprintf ("Unknown type returned. Int was expected.\n"); 236 | } 237 | return -1; 238 | } 239 | 240 | void Radare_plugin_anal_free(RAnalPlugin *ap) { 241 | free ((char *)ap->name); 242 | free ((char *)ap->arch); 243 | free ((char *)ap->license); 244 | free ((char *)ap->desc); 245 | free (ap); 246 | } 247 | 248 | PyObject *Radare_plugin_anal(Radare* self, PyObject *args) { 249 | void *ptr = NULL; 250 | PyObject *arglist = Py_BuildValue("(i)", 0); 251 | PyObject *o = PyObject_CallObject (args, arglist); 252 | 253 | RAnalPlugin *ap = R_NEW0 (RAnalPlugin); 254 | ap->name = getS (o,"name"); 255 | ap->arch = getS (o, "arch"); 256 | ap->license = getS (o, "license"); 257 | ap->desc = getS (o, "desc"); 258 | ap->bits = getI (o, "bits"); 259 | ap->esil = getI (o, "esil"); 260 | ptr = getF (o, "op"); 261 | if (ptr) { 262 | Py_INCREF (ptr); 263 | py_anal_cb = ptr; 264 | ap->op = py_anal; 265 | } 266 | ptr = getF (o, "set_reg_profile"); 267 | if (ptr) { 268 | Py_INCREF (ptr); 269 | py_set_reg_profile_cb = ptr; 270 | ap->set_reg_profile = py_set_reg_profile; 271 | } 272 | ptr = getF (o, "archinfo"); 273 | if (ptr) { 274 | Py_INCREF (ptr); 275 | py_archinfo_cb = ptr; 276 | ap->archinfo = py_archinfo; 277 | } 278 | Py_DECREF (o); 279 | 280 | RLibStruct lp = {}; 281 | lp.type = R_LIB_TYPE_ANAL; 282 | lp.data = ap; 283 | lp.free = (void (*)(void *data))Radare_plugin_anal_free; 284 | r_lib_open_ptr (core->lib, "python.py", NULL, &lp); 285 | Py_RETURN_TRUE; 286 | } 287 | -------------------------------------------------------------------------------- /lua/lib/inspect.lua: -------------------------------------------------------------------------------- 1 | local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table 2 | inspect = {Options = {}, } 3 | 4 | 5 | inspect._VERSION = 'inspect.lua 3.1.0' 6 | inspect._URL = 'http://github.com/kikito/inspect.lua' 7 | inspect._DESCRIPTION = 'human-readable representations of tables' 8 | inspect._LICENSE = [[ 9 | MIT LICENSE 10 | 11 | Copyright (c) 2022 Enrique García Cota 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a 14 | copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to 18 | permit persons to whom the Software is furnished to do so, subject to 19 | the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 28 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 29 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 30 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | ]] 32 | inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end }) 33 | inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end }) 34 | 35 | local tostring = tostring 36 | local rep = string.rep 37 | local match = string.match 38 | local char = string.char 39 | local gsub = string.gsub 40 | local fmt = string.format 41 | 42 | local function rawpairs(t) 43 | return next, t, nil 44 | end 45 | 46 | 47 | 48 | local function smartQuote(str) 49 | if match(str, '"') and not match(str, "'") then 50 | return "'" .. str .. "'" 51 | end 52 | return '"' .. gsub(str, '"', '\\"') .. '"' 53 | end 54 | 55 | 56 | local shortControlCharEscapes = { 57 | ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", 58 | ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127", 59 | } 60 | local longControlCharEscapes = { ["\127"] = "\127" } 61 | for i = 0, 31 do 62 | local ch = char(i) 63 | if not shortControlCharEscapes[ch] then 64 | shortControlCharEscapes[ch] = "\\" .. i 65 | longControlCharEscapes[ch] = fmt("\\%03d", i) 66 | end 67 | end 68 | 69 | local function escape(str) 70 | return (gsub(gsub(gsub(str, "\\", "\\\\"), 71 | "(%c)%f[0-9]", longControlCharEscapes), 72 | "%c", shortControlCharEscapes)) 73 | end 74 | 75 | local function isIdentifier(str) 76 | return type(str) == "string" and not not str:match("^[_%a][_%a%d]*$") 77 | end 78 | 79 | local flr = math.floor 80 | local function isSequenceKey(k, sequenceLength) 81 | return type(k) == "number" and 82 | flr(k) == k and 83 | 1 <= (k) and 84 | k <= sequenceLength 85 | end 86 | 87 | local defaultTypeOrders = { 88 | ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, 89 | ['function'] = 5, ['userdata'] = 6, ['thread'] = 7, 90 | } 91 | 92 | local function sortKeys(a, b) 93 | local ta, tb = type(a), type(b) 94 | 95 | 96 | if ta == tb and (ta == 'string' or ta == 'number') then 97 | return (a) < (b) 98 | end 99 | 100 | local dta = defaultTypeOrders[ta] or 100 101 | local dtb = defaultTypeOrders[tb] or 100 102 | 103 | 104 | return dta == dtb and ta < tb or dta < dtb 105 | end 106 | 107 | local function getKeys(t) 108 | 109 | local seqLen = 1 110 | while rawget(t, seqLen) ~= nil do 111 | seqLen = seqLen + 1 112 | end 113 | seqLen = seqLen - 1 114 | 115 | local keys, keysLen = {}, 0 116 | for k in rawpairs(t) do 117 | if not isSequenceKey(k, seqLen) then 118 | keysLen = keysLen + 1 119 | keys[keysLen] = k 120 | end 121 | end 122 | table.sort(keys, sortKeys) 123 | return keys, keysLen, seqLen 124 | end 125 | 126 | local function countCycles(x, cycles) 127 | if type(x) == "table" then 128 | if cycles[x] then 129 | cycles[x] = cycles[x] + 1 130 | else 131 | cycles[x] = 1 132 | for k, v in rawpairs(x) do 133 | countCycles(k, cycles) 134 | countCycles(v, cycles) 135 | end 136 | countCycles(getmetatable(x), cycles) 137 | end 138 | end 139 | end 140 | 141 | local function makePath(path, a, b) 142 | local newPath = {} 143 | local len = #path 144 | for i = 1, len do newPath[i] = path[i] end 145 | 146 | newPath[len + 1] = a 147 | newPath[len + 2] = b 148 | 149 | return newPath 150 | end 151 | 152 | 153 | local function processRecursive(process, 154 | item, 155 | path, 156 | visited) 157 | if item == nil then return nil end 158 | if visited[item] then return visited[item] end 159 | 160 | local processed = process(item, path) 161 | if type(processed) == "table" then 162 | local processedCopy = {} 163 | visited[item] = processedCopy 164 | local processedKey 165 | 166 | for k, v in rawpairs(processed) do 167 | processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) 168 | if processedKey ~= nil then 169 | processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) 170 | end 171 | end 172 | 173 | local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) 174 | if type(mt) ~= 'table' then mt = nil end 175 | setmetatable(processedCopy, mt) 176 | processed = processedCopy 177 | end 178 | return processed 179 | end 180 | 181 | local function puts(buf, str) 182 | buf.n = buf.n + 1 183 | buf[buf.n] = str 184 | end 185 | 186 | 187 | 188 | local Inspector = {} 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | local Inspector_mt = { __index = Inspector } 200 | 201 | local function tabify(inspector) 202 | puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level)) 203 | end 204 | 205 | function Inspector:getId(v) 206 | local id = self.ids[v] 207 | local ids = self.ids 208 | if not id then 209 | local tv = type(v) 210 | id = (ids[tv] or 0) + 1 211 | ids[v], ids[tv] = id, id 212 | end 213 | return tostring(id) 214 | end 215 | 216 | function Inspector:putValue(v) 217 | local buf = self.buf 218 | local tv = type(v) 219 | if tv == 'string' then 220 | puts(buf, smartQuote(escape(v))) 221 | elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or 222 | tv == 'cdata' or tv == 'ctype' then 223 | puts(buf, tostring(v)) 224 | elseif tv == 'table' and not self.ids[v] then 225 | local t = v 226 | 227 | if t == inspect.KEY or t == inspect.METATABLE then 228 | puts(buf, tostring(t)) 229 | elseif self.level >= self.depth then 230 | puts(buf, '{...}') 231 | else 232 | if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end 233 | 234 | local keys, keysLen, seqLen = getKeys(t) 235 | 236 | puts(buf, '{') 237 | self.level = self.level + 1 238 | 239 | for i = 1, seqLen + keysLen do 240 | if i > 1 then puts(buf, ',') end 241 | if i <= seqLen then 242 | puts(buf, ' ') 243 | self:putValue(t[i]) 244 | else 245 | local k = keys[i - seqLen] 246 | tabify(self) 247 | if isIdentifier(k) then 248 | puts(buf, k) 249 | else 250 | puts(buf, "[") 251 | self:putValue(k) 252 | puts(buf, "]") 253 | end 254 | puts(buf, ' = ') 255 | self:putValue(t[k]) 256 | end 257 | end 258 | 259 | local mt = getmetatable(t) 260 | if type(mt) == 'table' then 261 | if seqLen + keysLen > 0 then puts(buf, ',') end 262 | tabify(self) 263 | puts(buf, ' = ') 264 | self:putValue(mt) 265 | end 266 | 267 | self.level = self.level - 1 268 | 269 | if keysLen > 0 or type(mt) == 'table' then 270 | tabify(self) 271 | elseif seqLen > 0 then 272 | puts(buf, ' ') 273 | end 274 | 275 | puts(buf, '}') 276 | end 277 | 278 | else 279 | puts(buf, fmt('<%s %d>', tv, self:getId(v))) 280 | end 281 | end 282 | 283 | 284 | 285 | 286 | function inspect.inspect(root, options) 287 | if root == nil then 288 | root = options 289 | options= {} 290 | end 291 | options = options or {} 292 | 293 | local depth = options.depth or (math.huge) 294 | local newline = options.newline or '\n' 295 | local indent = options.indent or ' ' 296 | local process = options.process 297 | 298 | if process then 299 | root = processRecursive(process, root, {}, {}) 300 | end 301 | 302 | local cycles = {} 303 | countCycles(root, cycles) 304 | 305 | local inspector = setmetatable({ 306 | buf = { n = 0 }, 307 | ids = {}, 308 | cycles = cycles, 309 | depth = depth, 310 | level = 0, 311 | newline = newline, 312 | indent = indent, 313 | }, Inspector_mt) 314 | 315 | inspector:putValue(root) 316 | 317 | return table.concat(inspector.buf) 318 | end 319 | 320 | setmetatable(inspect, { 321 | __call = function(_, root, options) 322 | return inspect.inspect(root, options) 323 | end, 324 | }) 325 | 326 | return inspect 327 | -------------------------------------------------------------------------------- /tcl/plugin.c: -------------------------------------------------------------------------------- 1 | /* lang.tcl plugin for r2 - 2023-2025 - pancake */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct { 10 | char *name; 11 | Tcl_Interp *interp; 12 | Tcl_Obj *call; // TCL command to invoke 13 | } TclCoreHack; 14 | 15 | typedef struct { 16 | RCore *core; 17 | Tcl_Interp *interp; 18 | RList *core_plugins; // list of TclCoreHack* 19 | } TclPluginContext; 20 | 21 | // Global removed: share context via core->lang->session->plugin_data 22 | 23 | static void tcl_free(char *blockPtr) { 24 | free (blockPtr); 25 | } 26 | 27 | static int r2cmd_tcl(void *clientData, Tcl_Interp *interp, int argc, const char **argv) { 28 | RCore *core = (RCore *)clientData; 29 | if (argc == 2) { 30 | char *s = r_core_cmd_str (core, argv[1]); 31 | Tcl_SetResult (interp, s, (Tcl_FreeProc *)tcl_free); 32 | return TCL_OK; 33 | } 34 | return TCL_ERROR; 35 | } 36 | 37 | static void tcl_corehack_free(void *p) { 38 | TclCoreHack *h = (TclCoreHack *)p; 39 | if (!h) return; 40 | if (h->call) { 41 | Tcl_DecrRefCount (h->call); 42 | } 43 | free (h->name); 44 | free (h); 45 | } 46 | 47 | static TclCoreHack *tcl_find_hack(TclPluginContext *ctx, const char *name) { 48 | if (!ctx || !ctx->core_plugins || !name) { 49 | return NULL; 50 | } 51 | RListIter *it; 52 | TclCoreHack *h; 53 | r_list_foreach (ctx->core_plugins, it, h) { 54 | if (h->name && !strcmp (h->name, name)) { 55 | return h; 56 | } 57 | } 58 | return NULL; 59 | } 60 | 61 | static bool tcl_core_init(RCorePluginSession *cps) { 62 | if (!cps || !cps->plugin || !cps->plugin->meta.name) { 63 | return false; 64 | } 65 | TclPluginContext *ctx = R_UNWRAP4 (cps->core, lang, session, plugin_data); 66 | if (!ctx) { 67 | return false; 68 | } 69 | TclCoreHack *h = tcl_find_hack (ctx, cps->plugin->meta.name); 70 | if (!h) { 71 | return false; 72 | } 73 | cps->data = h; 74 | return true; 75 | } 76 | 77 | static bool tcl_core_fini(RCorePluginSession *cps) { 78 | // nothing to do per-session; the hack is owned by the lang context list 79 | return true; 80 | } 81 | 82 | static bool tcl_core_call(RCorePluginSession *cps, const char *input) { 83 | if (!cps || !cps->data) { 84 | return false; 85 | } 86 | TclCoreHack *h = (TclCoreHack *)cps->data; 87 | Tcl_Interp *interp = h->interp; 88 | if (!interp || !h->call) { 89 | return false; 90 | } 91 | // Build argv: [call input] 92 | Tcl_Obj *objv[2]; 93 | objv[0] = h->call; 94 | objv[1] = Tcl_NewStringObj (input? input: "", -1); 95 | Tcl_IncrRefCount (objv[1]); 96 | int rc = Tcl_EvalObjv (interp, 2, objv, TCL_EVAL_GLOBAL); 97 | Tcl_DecrRefCount (objv[1]); 98 | if (rc == TCL_ERROR) { 99 | const char *error_msg = Tcl_GetStringResult (interp); 100 | R_LOG_ERROR ("TCL core plugin error: %s", error_msg); 101 | Tcl_ResetResult (interp); 102 | return false; 103 | } 104 | // Interpret result 105 | Tcl_Obj *res = Tcl_GetObjResult (interp); 106 | int b = 0; 107 | if (Tcl_GetBooleanFromObj (interp, res, &b) == TCL_OK) { 108 | Tcl_ResetResult (interp); 109 | return b ? true : false; 110 | } 111 | const char *s = Tcl_GetString (res); 112 | if (s && *s) { 113 | r_cons_print (NULL, s); 114 | r_cons_print (NULL, "\n"); 115 | Tcl_ResetResult (interp); 116 | return true; 117 | } 118 | Tcl_ResetResult (interp); 119 | return false; 120 | } 121 | 122 | static void tcl_core_plugin_free(RCorePlugin *ap) { 123 | if (!ap) { 124 | return; 125 | } 126 | free ((char *)ap->meta.name); 127 | free ((char *)ap->meta.license); 128 | free ((char *)ap->meta.desc); 129 | free (ap); 130 | } 131 | 132 | static int r2plugin_tcl(void *clientData, Tcl_Interp *interp, int argc, const char **argv) { 133 | TclPluginContext *ctx = (TclPluginContext *)clientData; 134 | if (!ctx || !ctx->core) { 135 | return TCL_ERROR; 136 | } 137 | if (argc != 3) { 138 | Tcl_SetResult (interp, "Usage: r2plugin core ", TCL_STATIC); 139 | return TCL_ERROR; 140 | } 141 | if (strcmp (argv[1], "core")) { 142 | Tcl_SetResult (interp, "Only 'core' plugins are supported", TCL_STATIC); 143 | return TCL_ERROR; 144 | } 145 | // Call provider proc with no args; it must return a dict 146 | Tcl_Obj *prov = Tcl_NewStringObj (argv[2], -1); 147 | Tcl_IncrRefCount (prov); 148 | int rc = Tcl_EvalObjv (interp, 1, &prov, TCL_EVAL_GLOBAL); 149 | Tcl_DecrRefCount (prov); 150 | if (rc == TCL_ERROR) { 151 | const char *error_msg = Tcl_GetStringResult (interp); 152 | R_LOG_ERROR ("TCL plugin provider error: %s", error_msg); 153 | Tcl_ResetResult (interp); 154 | return TCL_ERROR; 155 | } 156 | Tcl_Obj *res = Tcl_GetObjResult (interp); 157 | if (!res) { 158 | Tcl_SetResult (interp, "provider returned empty result", TCL_STATIC); 159 | return TCL_ERROR; 160 | } 161 | // Parse dict: name, desc?, license?, call 162 | Tcl_Obj *val = NULL; 163 | Tcl_Obj *key = NULL; 164 | // name 165 | key = Tcl_NewStringObj ("name", -1); 166 | Tcl_IncrRefCount (key); 167 | if (Tcl_DictObjGet (interp, res, key, &val) != TCL_OK || !val) { 168 | Tcl_DecrRefCount (key); 169 | Tcl_SetResult (interp, "provider dict must contain 'name'", TCL_STATIC); 170 | return TCL_ERROR; 171 | } 172 | const char *name = Tcl_GetString (val); 173 | Tcl_DecrRefCount (key); 174 | if (!name || !*name) { 175 | Tcl_SetResult (interp, "invalid plugin name", TCL_STATIC); 176 | return TCL_ERROR; 177 | } 178 | // call 179 | key = Tcl_NewStringObj ("call", -1); 180 | Tcl_IncrRefCount (key); 181 | if (Tcl_DictObjGet (interp, res, key, &val) != TCL_OK || !val) { 182 | Tcl_DecrRefCount (key); 183 | Tcl_SetResult (interp, "provider dict must contain 'call'", TCL_STATIC); 184 | return TCL_ERROR; 185 | } 186 | Tcl_Obj *callCmd = val; // keep reference 187 | Tcl_IncrRefCount (callCmd); 188 | Tcl_DecrRefCount (key); 189 | // desc (optional) 190 | const char *desc = NULL; 191 | key = Tcl_NewStringObj ("desc", -1); 192 | Tcl_IncrRefCount (key); 193 | if (Tcl_DictObjGet (interp, res, key, &val) == TCL_OK && val) { 194 | desc = Tcl_GetString (val); 195 | } 196 | Tcl_DecrRefCount (key); 197 | // license (optional) 198 | const char *license = NULL; 199 | key = Tcl_NewStringObj ("license", -1); 200 | Tcl_IncrRefCount (key); 201 | if (Tcl_DictObjGet (interp, res, key, &val) == TCL_OK && val) { 202 | license = Tcl_GetString (val); 203 | } 204 | Tcl_DecrRefCount (key); 205 | 206 | // Check duplicate 207 | if (tcl_find_hack (ctx, name)) { 208 | Tcl_DecrRefCount (callCmd); 209 | Tcl_SetResult (interp, "core plugin already registered", TCL_STATIC); 210 | return TCL_OK; // mimic other langs: return false-ish; but return OK with message 211 | } 212 | 213 | // Build and register RCorePlugin 214 | RCorePlugin *ap = R_NEW0 (RCorePlugin); 215 | ap->meta.name = strdup (name); 216 | ap->meta.desc = desc? strdup (desc): NULL; 217 | ap->meta.license = license? strdup (license): NULL; 218 | ap->init = tcl_core_init; 219 | ap->fini = tcl_core_fini; 220 | ap->call = tcl_core_call; 221 | 222 | TclCoreHack *hack = R_NEW0 (TclCoreHack); 223 | hack->name = strdup (name); 224 | hack->interp = interp; 225 | hack->call = callCmd; // already refcounted 226 | if (!ctx->core_plugins) { 227 | ctx->core_plugins = r_list_newf (tcl_corehack_free); 228 | } 229 | r_list_append (ctx->core_plugins, hack); 230 | 231 | RLibStruct lp = { 232 | .type = R_LIB_TYPE_CORE, 233 | .data = ap, 234 | .free = (void (*)(void *))tcl_core_plugin_free, 235 | .version = R2_VERSION, 236 | }; 237 | int ret = r_lib_open_ptr (ctx->core->lib, ap->meta.name, NULL, &lp); 238 | // Return boolean result 239 | Tcl_SetObjResult (interp, Tcl_NewBooleanObj (ret == 1)); 240 | return TCL_OK; 241 | } 242 | 243 | static bool runstr(RLangSession *s, const char *code, int len) { 244 | TclPluginContext *pluginContext = (TclPluginContext *)s->plugin_data; 245 | Tcl_Interp *interp = pluginContext->interp; 246 | if (Tcl_Eval (interp, code) == TCL_ERROR) { 247 | const char *error_msg = Tcl_GetStringResult (interp); 248 | R_LOG_ERROR ("TCL Error: %s", error_msg); 249 | Tcl_ResetResult (interp); 250 | return true; 251 | } 252 | Tcl_ResetResult (interp); 253 | return false; 254 | } 255 | 256 | static bool init(RLangSession * R_NULLABLE s) { 257 | if (s == NULL) { 258 | return true; 259 | } 260 | TclPluginContext *pluginContext = R_NEW0 (TclPluginContext); 261 | pluginContext->core = s->lang->user; 262 | s->plugin_data = pluginContext; 263 | int argc = 0; 264 | char **argv = NULL; 265 | pluginContext->interp = Tcl_CreateInterp (); 266 | Tcl_Init (pluginContext->interp); 267 | Tcl_CreateCommand (pluginContext->interp, "r2cmd", r2cmd_tcl, pluginContext->core, NULL); 268 | Tcl_CreateCommand (pluginContext->interp, "r2plugin", r2plugin_tcl, pluginContext, NULL); 269 | return true; 270 | } 271 | 272 | static bool fini(RLangSession *s) { 273 | TclPluginContext *pluginContext = (TclPluginContext *)s->plugin_data; 274 | Tcl_DeleteInterp (pluginContext->interp); 275 | if (pluginContext->core_plugins) { 276 | r_list_free (pluginContext->core_plugins); 277 | pluginContext->core_plugins = NULL; 278 | } 279 | R_FREE (s->plugin_data); 280 | return true; 281 | } 282 | 283 | static bool runfile(RLangSession *s, const char *file) { 284 | TclPluginContext *pluginContext = (TclPluginContext *)s->plugin_data; 285 | char *data = r_file_slurp (file, NULL); 286 | if (!data) { 287 | R_LOG_ERROR ("Failed to slurp file: %s", file); 288 | return false; 289 | } 290 | char *line = r_str_newf ("source %s", file); 291 | if (!line) { 292 | free (data); 293 | return false; 294 | } 295 | Tcl_Interp *interp = pluginContext->interp; 296 | if (Tcl_Eval (interp, line) == TCL_ERROR) { 297 | const char *error_msg = Tcl_GetStringResult (interp); 298 | R_LOG_ERROR ("TCL Error: %s", error_msg); 299 | free (line); 300 | free (data); 301 | Tcl_ResetResult (interp); 302 | return false; 303 | } 304 | free (line); 305 | free (data); 306 | Tcl_ResetResult (interp); 307 | return true; 308 | } 309 | 310 | static RLangPlugin r_lang_plugin_tcl = { 311 | .meta = { 312 | .name = "tcl", 313 | .license = "MIT", 314 | .desc = "TCL/TK scripting for radare2", 315 | .author = "pancake" 316 | }, 317 | .ext = "tcl", 318 | .init = (void*)init, 319 | .fini = (void*)fini, 320 | .run = runstr, 321 | .run_file = (void*)runfile, 322 | }; 323 | 324 | #ifndef CORELIB 325 | RLibStruct radare_plugin = { 326 | .type = R_LIB_TYPE_LANG, 327 | .data = &r_lang_plugin_tcl, 328 | }; 329 | #endif 330 | -------------------------------------------------------------------------------- /python/radare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """python api for it 3 | 4 | This is the API provided with radare to use python inside radare as 5 | scripting language for extending its features or automatize some 6 | tasks analyzing code, patching binaries or debugging programs. 7 | 8 | Here's a small example of use: 9 | 10 | from radare import * 11 | 12 | seek(0x1024) 13 | print(hex(3)) 14 | write("90 90 90") 15 | print(hex(3)) 16 | 17 | quit() 18 | 19 | """ 20 | # Already imported from radare's core 21 | import r 22 | import string 23 | import binascii 24 | 25 | 26 | def hex2bin(str): 27 | """ 28 | Converts an ascii-hexpair based string into a binary array of bytes 29 | """ 30 | return binascii.a2b_hex(str.replace(" ", "")) 31 | 32 | 33 | def bin2hex(binstr): 34 | """ 35 | Converts a binary array of bytes into an ascii-hexpair based string 36 | """ 37 | hexstr = binascii.b2a_hex(binstr).lower() 38 | return hexstr 39 | 40 | 41 | # TODO: skip commented lines 42 | def slurp_hexpair(file): 43 | """ 44 | Returns the hexpair string contained in a hexpair-based file 45 | in a single line 46 | """ 47 | fd = open(file, "r") 48 | s = fd.readlines().join("\n") 49 | fd.close() 50 | return s 51 | 52 | 53 | # slurp a raw file or a symbol, returning the hexpair string 54 | def slurp(file): 55 | """ 56 | Returns the hexpair-based representation of a binary file 57 | """ 58 | fd = open(file, "r") 59 | str = bin2hex(fd.read()) 60 | fd.close() 61 | return str 62 | 63 | 64 | # def slurp_symbol(file,symbol): 65 | 66 | 67 | def __str_to_hash(str): 68 | list = str.split("\n") 69 | w = [] 70 | t = {} 71 | for i in range(1, len(list)): 72 | w = list[i].split("=") 73 | if len(w) > 1: 74 | a = w[0].strip() 75 | b = w[1].strip() 76 | if b[0:2] == "0x": 77 | t[a] = int(b, 16) 78 | elif (b.find(" ") == -1) and (b[0] >= "0" and b[0] <= "9"): 79 | t[a] = int(b, 10) 80 | else: 81 | t[a] = b 82 | return t 83 | 84 | 85 | def analyze_opcode(addr=None): 86 | """ 87 | Returns a hashtable containing the information of the analysis of the opcode in the current seek. 88 | This is: 'opcode', 'size', 'type', 'bytes', 'offset', 'ref', 'jump' and 'fail' 89 | """ 90 | if addr == None: 91 | return __str_to_hash(r.cmd("ao")) 92 | return __str_to_hash(r.cmd("ao @ 0x%x" % addr)) 93 | 94 | 95 | def analyze_block(addr=None): 96 | """ 97 | Returns a hashtable containing the information of the analysis of the basic block found in the current seek. 98 | This is: 'offset', 'type', 'size', 'call#', 'n_calls', 'true', 'false' and 'bytes' 99 | """ 100 | if addr == None: 101 | return __str_to_hash(r.cmd("ab")) 102 | return __str_to_hash(r.cmd("ab @ 0x%x" % addr)) 103 | 104 | 105 | def endian_set(big): 106 | r.cmd("eval cfg.bigendian=%d" % big) 107 | 108 | 109 | def write(hexpair): 110 | r.cmd("wx %s" % hexpair) 111 | 112 | 113 | def write_asm(opcode): 114 | r.cmd("wa %s" % opcode) 115 | 116 | 117 | def write_string(str): 118 | r.cmd("w %s" % str) 119 | 120 | 121 | def write_wide_string(str): 122 | r.cmd("ww %s" % str) 123 | 124 | 125 | def write_from_file(file): 126 | r.cmd("wf %s" % file) 127 | 128 | 129 | def write_from_hexpair_file(file): 130 | r.cmd("wF %s" % file) 131 | 132 | 133 | def seek_undo(): 134 | r.cmd("undo") 135 | 136 | 137 | def seek_redo(): 138 | r.cmd("uu") 139 | 140 | 141 | def seek_history(): 142 | ret = [] 143 | list = r.cmd("u*").split("\n") 144 | for i in range(1, len(list)): 145 | w = list[i].split(" ") 146 | if len(w) > 3: 147 | t = {} 148 | t["addr"] = w[0].strip() 149 | ret.append(t) 150 | return ret 151 | 152 | 153 | def seek_history_reset(): 154 | r.cmd("u!") 155 | 156 | 157 | def write_undo(num): 158 | return r.cmd("uw %d" % num) 159 | 160 | 161 | def write_redo(num): 162 | return r.cmd("uw -%d" % num) 163 | 164 | 165 | def write_history(): 166 | ret = [] 167 | list = r.cmd("wu").split("\n") 168 | for i in range(1, len(list)): 169 | w = list[i].split(" ") 170 | if len(w) > 3: 171 | t = {} 172 | t["size"] = int(w[2].strip(), 10) 173 | t["addr"] = int(w[3].strip(), 16) 174 | # TODO moar nfo here 175 | ret.append(t) 176 | return ret 177 | 178 | 179 | def flag_space_set(name): 180 | r.cmd("fs %s" % name) 181 | 182 | 183 | def flag_list(mask): 184 | ret = [] 185 | list = r.cmd("f~%s" % mask).split("\n") 186 | for i in range(1, len(list)): 187 | w = list[i].split(" ") 188 | if len(w) > 3: 189 | t = {} 190 | t["addr"] = int(w[1].strip(), 16) 191 | t["size"] = int(w[3].strip(), 10) 192 | t["name"] = w[4].strip() 193 | ret.append(t) 194 | return ret 195 | 196 | 197 | def flag_set(name, addr=None): 198 | if addr == None: 199 | r.cmd("f %s" % name) 200 | else: 201 | r.cmd("f %s @ 0xx" % name, addr) 202 | 203 | 204 | def flag_rename(old_name, new_name): 205 | r.cmd("fr %s %s" % (old_name, new_name)) 206 | 207 | 208 | def flag_unset(name): 209 | r.cmd("f -%s" % name) 210 | 211 | 212 | def flag_get(name): 213 | return r.cmd("? %s" % name).split(" ")[0].strip() 214 | 215 | 216 | def meta_comment_add(msg): 217 | r.cmd("CC %s" % msg) 218 | 219 | 220 | def type_code(len): 221 | r.cmd("Cc %d" % len) 222 | 223 | 224 | def type_data(len): 225 | r.cmd("Cd %d" % len) 226 | 227 | 228 | def type_string(len): 229 | r.cmd("Cs %d" % len) 230 | 231 | 232 | def copy(num, addr=None): 233 | if addr == None: 234 | r.cmd("y %d" % num) 235 | else: 236 | r.cmd("y %d @ 0x%x" % (num, addr)) 237 | 238 | 239 | def paste(num, addr=None): 240 | if addr == None: 241 | r.cmd("yy %d" % num) 242 | else: 243 | r.cmd("yy %d @ 0x%x" % (num, addr)) 244 | 245 | 246 | def asm(opcode): 247 | """ 248 | Returns the hexpair strin representation of the assembled opcode 249 | """ 250 | return r.cmd("!rasm '%s'" % opcode) 251 | 252 | 253 | def dis(num, addr=None): 254 | """ 255 | Disassemble 'num' opcodes from the current seek and returns the output 256 | """ 257 | if addr == None: 258 | return r.cmd("pd %d" % num) 259 | return r.cmd("pd %d @ 0x%x" % (num, addr)) 260 | 261 | 262 | def str(addr=None): 263 | """ 264 | Returns a zero-terminated string found in current seek 265 | """ 266 | if addr == None: 267 | return r.cmd("pz").strip() 268 | return r.cmd("pz @ 0x%x" % addr).strip() 269 | 270 | 271 | def dword(num, addr=None): 272 | if addr == None: 273 | return r.cmd("p64 %d" % num).strip() 274 | return r.cmd("p64 %d @ 0x%x" % (num, addr)).strip() 275 | 276 | 277 | def word(num, addr=None): 278 | if addr == None: 279 | return r.cmd("p32 %d" % num).strip() 280 | return r.cmd("p32 %d @ 0x%x" % (num, addr)).strip() 281 | 282 | 283 | def half(num, addr=None): 284 | if addr == None: 285 | return r.cmd("p16 %d" % num).strip() 286 | return r.cmd("p16 %d @ 0x%x" % (num, addr)).strip() 287 | 288 | 289 | def hex(num, addr=None): 290 | if addr == None: 291 | return r.cmd("p8 %d" % num).strip() 292 | return r.cmd("p8 %d @ 0x%x" % (num, addr)).strip() 293 | 294 | 295 | def eval_get(key): 296 | return r.cmd("eval %s" % key).strip() 297 | 298 | 299 | def eval_set(key, value): 300 | r.cmd("eval %s = %s" % (key, value)) 301 | 302 | 303 | def eval_hash_get(): 304 | return __str_to_hash("e") 305 | 306 | 307 | def eval_hash_set(hash): 308 | l = list(hash.keys()) 309 | for i in range(0, len(l)): 310 | key = l[i] 311 | value = hash[key] 312 | r.cmd("e %s=%s" % (key, value)) 313 | 314 | 315 | def get_byte(addr): 316 | return r.cmd("? [1:%s]~[0]" % addr) 317 | 318 | 319 | def write_to_files(file, size): 320 | r.cmd("wT %s %s", file, size) 321 | 322 | 323 | def seek(addr): 324 | r.cmd("s %s" % addr) 325 | 326 | 327 | def cmp(hexpairs, addr): 328 | r.cmd("c %s @ 0x%x" % (hexpairs, addr)) 329 | 330 | 331 | def cmp_file(file, addr): 332 | r.cmd("cf %s @ 0x%x" % (file, addr)) 333 | 334 | 335 | def dbg_attach(pid): 336 | print(r.cmd("!attach %d" % pid)) 337 | 338 | 339 | def dbg_detach(pid): 340 | print(r.cmd("!detach %d" % pid)) 341 | 342 | 343 | def dbg_continue(): 344 | print(r.cmd("!cont")) 345 | 346 | 347 | def dbg_step(num): 348 | if num < 1: 349 | num = 1 350 | r.cmd("!step %d" % num) 351 | 352 | 353 | def dbg_step_over(num): 354 | if num < 1: 355 | num = 1 356 | r.cmd("!stepo %d", num) 357 | 358 | 359 | def dbg_jmp(addr): 360 | r.cmd("!jmp " + addr) 361 | 362 | 363 | def dbg_call(addr): 364 | r.cmd("!call " + addr) 365 | 366 | 367 | def dbg_bp_set(addr, type): 368 | r.cmd("!bp " + addr) 369 | 370 | 371 | def dbg_bp_unset(addr, type): 372 | r.cmd("!bp -" + addr) 373 | 374 | 375 | def dbg_alloc(size): 376 | return r.cmd("!alloc %s" % size) 377 | 378 | 379 | def dbg_free(addr): 380 | r.cmd("!free %s" % addr) 381 | 382 | 383 | def dbg_backtrace(): 384 | ret = [] 385 | list = r.cmd("!bt").split("\n") 386 | for i in range(1, len(list)): 387 | w = list[i].split(" ") 388 | if len(w) > 3: 389 | t = {} 390 | t["addr"] = int(w[1].strip(), 16) 391 | t["framesz"] = int(w[2].strip(), 10) 392 | t["varsz"] = int(w[3].strip(), 10) 393 | ret.append(t) 394 | return ret 395 | 396 | 397 | def dbg_dump(name): 398 | r.cmd("!dump %s" % name) 399 | 400 | 401 | def dbg_restore(name): 402 | r.cmd("!restore %s" % name) 403 | 404 | 405 | def dbg_register_get(name): 406 | r.cmd("!reg %s" % (name)) 407 | 408 | 409 | def dbg_register_set(name, value): 410 | r.cmd("!reg %s=%s" % (name, value)) 411 | 412 | 413 | def trace_at(addr): 414 | return __str_to_hash(r.cmd("at %s" % addr)) 415 | 416 | 417 | def trace_list(): 418 | return r.cmd("at*").split("\n") 419 | 420 | 421 | def trace_reset(): 422 | r.cmd("at-") 423 | 424 | 425 | def trace_ranges(): 426 | return r.cmd("at").split("\n") 427 | 428 | 429 | def hash(algo, size): 430 | return r.cmd("#%s %d" % (algo, size)) 431 | 432 | 433 | def graph(addr=None): 434 | if addr == None: 435 | r.cmd("ag") 436 | else: 437 | r.cmd("ag @ %s" % addr) 438 | 439 | 440 | def cmd(str): 441 | return r.cmd(str) 442 | 443 | 444 | def quit(): 445 | r.cmd("q!") 446 | -------------------------------------------------------------------------------- /python/python/io.c: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2009-2025 - pancake */ 2 | 3 | #include "io.h" 4 | #include "core.h" 5 | 6 | typedef struct { 7 | ut64 off; 8 | PyObject *result; 9 | void *py_io_open_cb; 10 | void *py_io_check_cb; 11 | void *py_io_read_cb; 12 | void *py_io_system_cb; 13 | void *py_io_seek_cb; 14 | void *py_io_close_cb; 15 | } DescData; 16 | 17 | #if R2_VERSION_NUMBER >= 50909 18 | #define IOPDATA 1 19 | #else 20 | #define IOPDATA 0 21 | #endif 22 | 23 | static bool py_io_check(RIO *io, const char *path, bool many); 24 | 25 | static bool py_io_check_internal(RIOPlugin *py_io_plugin, RIO *io, const char *path, bool many) { 26 | bool res = false; 27 | PyObject *arglist = Py_BuildValue ("(zO)", path, many? Py_True: Py_False); 28 | #if IOPDATA 29 | DescData *dd = py_io_plugin->data; 30 | #else 31 | DescData *dd = py_io_plugin->widget; 32 | #endif 33 | if (!dd) { 34 | R_LOG_ERROR ("iop.data is nul"); 35 | return false; 36 | } 37 | Py_INCREF (arglist); 38 | PyObject *result = PyObject_CallObject (dd->py_io_check_cb, arglist); 39 | if (result && PyBool_Check (result)) { 40 | res = result == Py_True; 41 | Py_DECREF (result); 42 | } 43 | if (arglist) { 44 | Py_DECREF (arglist); 45 | } 46 | return res; 47 | } 48 | 49 | static RIOPlugin *iop_check(RIO *io, const char *path) { 50 | SdbListIter *iter; 51 | RIOPlugin *iop; 52 | ls_foreach (io->plugins, iter, iop) { 53 | if (iop->check == py_io_check) { 54 | if (py_io_check_internal (iop, io, path, false)) { 55 | R_LOG_INFO ("Plugin found"); 56 | return iop; 57 | } 58 | } 59 | } 60 | return NULL; 61 | } 62 | 63 | static RIODesc* py_io_open(RIO *io, const char *path, int rw, int mode) { 64 | RIOPlugin *py_io_plugin = iop_check (io, path); 65 | if (!py_io_plugin) { 66 | R_LOG_ERROR ("Cannot find io plugin for %s", path); 67 | return NULL; 68 | } 69 | #if IOPDATA 70 | DescData *iodd = py_io_plugin->data; 71 | #else 72 | DescData *iodd = py_io_plugin->widget; 73 | #endif 74 | PyObject *arglist = Py_BuildValue ("(zii)", path, rw, mode); 75 | PyObject *result = PyObject_CallObject (iodd->py_io_open_cb, arglist); 76 | if (!result) { // exception was thrown 77 | return NULL; 78 | } 79 | if (arglist) { 80 | Py_DECREF (arglist); 81 | } 82 | if (result) { 83 | Py_INCREF (result); 84 | } 85 | DescData *dd = r_mem_dup (iodd, sizeof (DescData)); 86 | dd->result = result; 87 | return r_io_desc_new (io, py_io_plugin, path, rw, mode, dd); 88 | } 89 | 90 | static bool py_io_check(RIO *io, const char *path, bool many) { 91 | RIOPlugin *py_io_plugin = iop_check (io, path); 92 | if (py_io_plugin) { 93 | return py_io_check_internal (py_io_plugin, io, path, many); 94 | } 95 | return false; 96 | } 97 | 98 | static ut64 py_io_seek(RIO *io, RIODesc *fd, ut64 offset, int whence) { 99 | DescData *dd = fd->data; 100 | if (dd->py_io_seek_cb) { 101 | DescData *dd = fd->data; 102 | PyObject *arglist = Py_BuildValue ("(NKi)", (PyObject *)dd->result, offset, whence); 103 | if (!arglist) { 104 | return UT64_MAX; 105 | } 106 | Py_INCREF (arglist); 107 | PyObject *result = PyObject_CallObject (dd->py_io_seek_cb, arglist); 108 | if (result) { 109 | if (PyLong_Check (result)) { 110 | dd->off = PyLong_AsLong (result); 111 | } else if (PyLong_Check (result)) { 112 | dd->off = PyLong_AsLongLong (result); 113 | } 114 | return dd->off; 115 | } else { 116 | R_LOG_ERROR ("seek callback returns nothing"); 117 | } 118 | // PyObject_Print (result, stderr, 0); 119 | // eprintf ("SEEK Unknown type returned. Number was expected.\n"); 120 | switch (whence) { 121 | case 0: return dd->off = offset; 122 | case 1: return dd->off += offset; 123 | case 2: return 512; // wtf is this assumption 124 | } 125 | return UT64_MAX; 126 | } 127 | return UT64_MAX; 128 | } 129 | 130 | static int py_io_read(RIO *io, RIODesc *fd, ut8 *buf, int count) { 131 | DescData *dd = fd->data; 132 | if (!dd->py_io_read_cb) { 133 | return -1; 134 | } 135 | PyObject *arglist = Py_BuildValue ("(Oi)", (PyObject *)dd->result, count); 136 | Py_INCREF (arglist); 137 | PyObject *result = PyObject_CallObject (dd->py_io_read_cb, arglist); 138 | if (result) { 139 | if (PyByteArray_Check (result)) { 140 | const char *ptr = PyByteArray_AsString (result); 141 | ssize_t size = PyByteArray_Size (result); 142 | ssize_t limit = R_MIN (size, (ssize_t)count); 143 | memset (buf, io->Oxff, limit); 144 | memcpy (buf, ptr, limit); 145 | count = (int)limit; 146 | } else if (PyUnicode_Check (result)) { 147 | // PyObject* repr = PyObject_Repr(result); 148 | // PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~"); 149 | ssize_t size; 150 | const char *ptr = PyUnicode_AsUTF8AndSize (result, &size); 151 | ssize_t limit = R_MIN (size, (ssize_t)count); 152 | memset (buf, io->Oxff, limit); 153 | memcpy (buf, ptr, limit); 154 | count = (int)limit; 155 | } else if (PyBytes_Check (result)) { 156 | size_t size = PyBytes_Size (result); 157 | size_t limit = R_MIN (size, (size_t)count); 158 | memset (buf, io->Oxff, limit); 159 | memcpy (buf, PyBytes_AS_STRING (result), limit); 160 | // eprintf ("result is a string DONE %d %d\n" , count, size); 161 | count = (int)limit; 162 | } else if (PyList_Check (result)) { 163 | int i, size = PyList_Size (result); 164 | int limit = R_MIN (size, count); 165 | memset (buf, io->Oxff, count); 166 | for (i = 0; i < limit; i++) { 167 | PyObject *len = PyList_GetItem (result, i); 168 | buf[i] = PyNumber_AsSsize_t (len, NULL); 169 | } 170 | count = (int)limit; 171 | } 172 | } else { 173 | R_LOG_ERROR ("Nothing returned from the read callback"); 174 | } 175 | if (arglist) { 176 | Py_DECREF (arglist); 177 | } 178 | if (result) { 179 | Py_DECREF (result); 180 | } 181 | return count; 182 | } 183 | 184 | static char *py_io_system(RIO *io, RIODesc *desc, const char *cmd) { 185 | DescData *dd = desc->data; 186 | if (R_STR_ISEMPTY (cmd)) { 187 | return NULL; 188 | } 189 | char *res = NULL; 190 | if (dd->py_io_system_cb) { 191 | PyObject *arglist = Py_BuildValue ("(Oz)", (PyObject *)dd->result, cmd); 192 | if (!arglist) { 193 | return NULL; 194 | } 195 | Py_INCREF (arglist); 196 | PyObject *result = PyObject_CallObject (dd->py_io_system_cb, arglist); 197 | if (result) { 198 | const char *ptr = NULL; 199 | if (PyUnicode_Check (result)) { 200 | ssize_t size; 201 | const char *ptr = PyUnicode_AsUTF8AndSize (result, &size); 202 | if (ptr) { 203 | res = strdup (ptr); 204 | } else { 205 | R_LOG_ERROR ("Cannot parse string tuple"); 206 | } 207 | } else if (PyBool_Check (result)) { 208 | if (result == Py_False) { 209 | res = strdup ("error"); 210 | } 211 | // res = strdup (r_str_bool (result == Py_True)); 212 | } else if (PyLong_Check (result)) { 213 | long n = PyLong_AsLong (result); 214 | res = r_str_newf ("%ld", n); 215 | } else { 216 | R_LOG_ERROR ("Unknown type returned. Boolean was expected"); 217 | } 218 | } else { 219 | R_LOG_ERROR ("RLang.Python.System returned None"); 220 | } 221 | if (arglist) { 222 | Py_DECREF (arglist); 223 | } 224 | if (result) { 225 | Py_DECREF (result); 226 | } 227 | } 228 | return res; 229 | } 230 | 231 | static bool py_io_close(RIODesc *desc) { 232 | DescData *dd = desc->data; 233 | int ret = 0; 234 | if (dd && dd->py_io_close_cb) { 235 | PyObject *arglist = Py_BuildValue ("(N)", (PyObject *)dd->result); 236 | PyObject *result = PyObject_CallObject (dd->py_io_close_cb, arglist); 237 | if (result && PyLong_Check (result)) { 238 | ret = PyLong_AsLong (result); 239 | Py_DECREF (result); 240 | } 241 | if (arglist) { 242 | Py_DECREF (arglist); 243 | } 244 | #if 0 245 | while (Py_REFCNT (dd->result)) { // HACK 246 | Py_DECREF (dd->result); 247 | } 248 | #endif 249 | R_FREE (desc->data); 250 | } 251 | return ret != 0; 252 | } 253 | 254 | void Radare_plugin_io_free(RIOPlugin *ap) { 255 | #if IOPDATA 256 | free (ap->data); 257 | #endif 258 | #if R2_VERSION_NUMBER > 50808 259 | free ((char *)ap->meta.name); 260 | free ((char *)ap->meta.desc); 261 | free ((char *)ap->meta.license); 262 | #else 263 | free ((char *)ap->name); 264 | free ((char *)ap->desc); 265 | free ((char *)ap->license); 266 | #endif 267 | free (ap); 268 | } 269 | 270 | PyObject *Radare_plugin_io(Radare* self, PyObject *args) { 271 | PyObject *arglist = Py_BuildValue("(i)", 0); 272 | PyObject *o = PyObject_CallObject (args, arglist); 273 | 274 | RIOPlugin *ap = R_NEW0 (RIOPlugin); 275 | if (!ap) { 276 | return Py_False; 277 | } 278 | #if R2_VERSION_NUMBER > 50808 279 | RPluginMeta meta = { 280 | .name = getS (o, "name"), 281 | .desc = getS (o, "desc"), 282 | .license = getS (o, "license") 283 | }; 284 | memcpy ((void*)&ap->meta, &meta, sizeof(RPluginMeta)); 285 | #if 0 286 | ap->meta.name = getS (o, "name"); 287 | ap->meta.desc = getS (o, "desc"); 288 | ap->meta.license = getS (o, "license"); 289 | #endif 290 | #else 291 | ap->name = getS (o, "name"); 292 | ap->desc = getS (o, "desc"); 293 | ap->license = getS (o, "license"); 294 | #endif 295 | void *py_io_open_cb = NULL; 296 | void *py_io_check_cb = NULL; 297 | void *py_io_read_cb = NULL; 298 | void *py_io_system_cb = NULL; 299 | void *py_io_seek_cb = NULL; 300 | void *py_io_close_cb = NULL; 301 | 302 | void *ptr = getF (o, "open"); 303 | if (ptr) { 304 | Py_INCREF (ptr); 305 | py_io_open_cb = (void *)ptr; 306 | ap->open = py_io_open; 307 | } 308 | ptr = getF (o, "check"); 309 | if (ptr) { 310 | Py_INCREF (ptr); 311 | py_io_check_cb = (void *)ptr; 312 | ap->check = py_io_check; 313 | } 314 | ptr = getF (o, "read"); 315 | if (ptr) { 316 | Py_INCREF (ptr); 317 | py_io_read_cb = (void *)ptr; 318 | ap->read = py_io_read; 319 | } 320 | ptr = getF (o, "system"); 321 | if (ptr) { 322 | Py_INCREF (ptr); 323 | py_io_system_cb = (void *)ptr; 324 | ap->system = py_io_system; 325 | } 326 | ptr = getF (o, "seek"); 327 | if (ptr) { 328 | Py_INCREF (ptr); 329 | py_io_seek_cb = (void *)ptr; 330 | ap->seek = py_io_seek; 331 | } 332 | ptr = getF (o, "close"); 333 | if (ptr) { 334 | Py_INCREF (ptr); 335 | py_io_close_cb = (void *)ptr; 336 | ap->close = py_io_close; 337 | } 338 | #if 0 339 | ptr = getF (o, "write"); 340 | ptr = getF (o, "resize"); 341 | #endif 342 | if (o) { 343 | Py_DECREF (o); 344 | } 345 | #if R2_VERSION_NUMBER >= 50909 346 | DescData *dd = R_NEW0 (DescData); 347 | dd->py_io_open_cb = py_io_open_cb; 348 | dd->py_io_check_cb = py_io_check_cb; 349 | dd->py_io_system_cb = py_io_system_cb; 350 | dd->py_io_read_cb = py_io_read_cb; 351 | dd->py_io_seek_cb = py_io_seek_cb; 352 | dd->py_io_close_cb = py_io_close_cb; 353 | #if IOPDATA 354 | ap->data = dd; 355 | #else 356 | ap->widget = dd; 357 | #endif 358 | #endif 359 | RLibStruct lp = {}; 360 | lp.type = R_LIB_TYPE_IO; 361 | lp.data = ap; 362 | lp.free = (void (*)(void *data))Radare_plugin_io_free; 363 | R_LOG_DEBUG ("PLUGIN[python] Loading io: %s", meta.name); 364 | r_lib_open_ptr (Gcore->lib, "python.py", NULL, &lp); 365 | Py_RETURN_TRUE; 366 | } 367 | --------------------------------------------------------------------------------