IO plugins

All access to files, network, debugger and all input/output in general is wrapped by an IO abstraction layer that allows radare to treat all data as if it were just a file.

IO plugins are the ones used to wrap the open, read, write and 'system' on virtual file systems. You can make radare understand anything as a plain file. E.g. a socket connection, a remote radare session, a file, a process, a device, a gdb session.

So, when radare reads a block of bytes, it is the task of an IO plugin to get these bytes from any place and put them into internal buffer. An IO plugin is chosen by a file's URI to be opened. Some examples:

• Debugging URIs

$ r2 dbg:///bin/ls

$ r2 pid://1927

• Remote sessions

$ r2 rap://:1234

$ r2 rap://:1234//bin/ls

• Virtual buffers

$ r2 malloc://512

shortcut for

$ r2 -

You can get a list of the radare IO plugins by typing radare2 -L:

$ r2 -L

rw_ ar Open ar/lib files [ar|lib]://[file//path] (LGPL3)

rw_ bfdbg BrainFuck Debugger (bfdbg://path/to/file) (LGPL3)

rwd bochs Attach to a BOCHS debugger (LGPL3)

r_d debug Native debugger (dbg:///bin/ls dbg://1388 pidof:// waitfor://) (LGPL3) v0.2.0 pancake

rw_ default open local files using def_mmap:// (LGPL3)

rwd gdb Attach to gdbserver, 'qemu -s', gdb://localhost:1234 (LGPL3)

rw_ gprobe open gprobe connection using gprobe:// (LGPL3)

rw_ gzip read/write gzipped files (LGPL3)

rw_ http http get (http://rada.re/) (LGPL3)

rw_ ihex Intel HEX file (ihex://eeproms.hex) (LGPL)

r__ mach mach debug io (unsupported in this platform) (LGPL)

rw_ malloc memory allocation (malloc://1024 hex://cd8090) (LGPL3)

rw_ mmap open file using mmap:// (LGPL3)

rw_ null null-plugin (null://23) (LGPL3)

rw_ procpid /proc/pid/mem io (LGPL3)

rwd ptrace ptrace and /proc/pid/mem (if available) io (LGPL3)

rwd qnx Attach to QNX pdebug instance, qnx://host:1234 (LGPL3)

rw_ r2k kernel access API io (r2k://) (LGPL3)

rw_ r2pipe r2pipe io plugin (MIT)

rw_ r2web r2web io client (r2web://cloud.rada.re/cmd/) (LGPL3)

rw_ rap radare network protocol (rap://:port rap://host:port/file) (LGPL3)

rw_ rbuf RBuffer IO plugin: rbuf:// (LGPL)

rw_ self read memory from myself using 'self://' (LGPL3)

rw_ shm shared memory resources (shm://key) (LGPL3)

rw_ sparse sparse buffer allocation (sparse://1024 sparse://) (LGPL3)

rw_ tcp load files via TCP (listen or connect) (LGPL3)

rwd windbg Attach to a KD debugger (windbg://socket) (LGPL3)

rwd winedbg Wine-dbg io and debug.io plugin for r2 (MIT)

rw_ zip Open zip files [apk|ipa|zip|zipall]://[file//path] (BSD)

Implementing a new disassembly plugin

Radare2 has modular architecture, thus adding support for a new architecture is very easy, if you are fluent in C. For various reasons it might be easier to implement it out of the tree. For this we will need to create single C file, called asm_mycpu.c and makefile for it.

The key thing of RAsm plugin is a structure

RAsmPlugin r_asm_plugin_mycpu = {

.name = "mycpu",

.license = "LGPL3",

.desc = "MYCPU disassembly plugin",

.arch = "mycpu",

.bits = 32,

.endian = R_SYS_ENDIAN_LITTLE,

.disassemble = &disassemble

};

where .disassemble is a pointer to disassembly function, which accepts the bytes buffer and length:

static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len)

Makefile

NAME=asm_snes

R2_PLUGIN_PATH=$(shell r2 -H R2_USER_PLUGINS)

LIBEXT=$(shell r2 -H LIBEXT)

CFLAGS=-g -fPIC $(shell pkg-config --cflags r_anal)

LDFLAGS=-shared $(shell pkg-config --libs r_anal)

OBJS=$(NAME).o

LIB=$(NAME).$(LIBEXT)


all: $(LIB)


clean:

rm -f $(LIB) $(OBJS)


$(LIB): $(OBJS)

$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(LIB)


install:

cp -f asm_mycpu.$(SO_EXT) $(R2_PLUGIN_PATH)


uninstall:

rm -f $(R2_PLUGIN_PATH)/asm_mycpu.$(SO_EXT)

asm_mycpu.c

/* radare - LGPL - Copyright 2018 - user */


#include 

#include 

#include 

#include 

#include 


static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {

struct op_cmd cmd = {

.instr = "",

.operands = ""

};

if (len < 2) return -1;

int ret = decode_opcode (buf, len, &cmd);

if (ret > 0) {

snprintf (op->buf_asm, R_ASM_BUFSIZE, "%s %s",

cmd.instr, cmd.operands);

}

return op->size = ret;

}


RAsmPlugin r_asm_plugin_mycpu = {

.name = "mycpu",

.license = "LGPL3",

.desc = "MYCPU disassembly plugin",

.arch = "mycpu",

.bits = 32,

.endian = R_SYS_ENDIAN_LITTLE,

.disassemble = &disassemble

};


#ifndef R2_PLUGIN_INCORE

R_API RLibStruct radare_plugin = {

.type = R_LIB_TYPE_ASM,

.data = &r_asm_plugin_mycpu,

.version = R2_VERSION

};

#endif

After compiling radare2 will list this plugin in the output:

_d__ _8_32 mycpu LGPL3 MYCPU

Moving plugin into the tree

Pushing a new architecture into the main branch of r2 requires to modify several files in order to make it fit into the way the rest of plugins are built.

List of affected files:

• plugins.def.cfg : add the asm.mycpu plugin name string in there

• libr/asm/p/mycpu.mk : build instructions

• libr/asm/p/asm_mycpu.c : implementation

• libr/include/r_asm.h : add the struct definition in there

Check out how the NIOS II CPU disassembly plugin was implemented by reading those commits:

Implement RAsm plugin: https://github.com/radareorg/radare2/commit/933dc0ef6ddfe44c88bbb261165bf8f8b531476b

Implement RAnal plugin: https://github.com/radareorg/radare2/commit/ad430f0d52fbe933e0830c49ee607e9b0e4ac8f2

Implementing a new analysis plugin

After implementing disassembly plugin, you might have noticed that output is far from being good - no proper highlighting, no reference lines and so on. This is because radare2 requires every architecture plugin to provide also analysis information about every opcode. At the moment the implementation of disassembly and opcodes analysis is separated between two modules - RAsm and RAnal. Thus we need to write an analysis plugin too. The principle is very similar - you just need to create a C file and corresponding Makefile.

They structure of RAnal plugin looks like

RAnalPlugin r_anal_plugin_v810 = {

.name = "mycpu",

.desc = "MYCPU code analysis plugin",

.license = "LGPL3",

.arch = "mycpu",

.bits = 32,

.op = mycpu_op,

.esil = true,

.set_reg_profile = set_reg_profile,

};

Like with disassembly plugin there is a key function - mycpu_op which scans the opcode and builds RAnalOp structure. On the other hand, in this example analysis plugins also performs uplifting to ESIL, which is enabled in .esil = true statement. Thus, mycpu_op obliged to fill the corresponding RAnalOp ESIL field for the opcodes. Second important thing for ESIL uplifting and emulation - register profile, like in debugger, which is set within set_reg_profile function.

Makefile

NAME=anal_snes

R2_PLUGIN_PATH=$(shell r2 -H R2_USER_PLUGINS)

LIBEXT=$(shell r2 -H LIBEXT)

CFLAGS=-g -fPIC $(shell pkg-config --cflags r_anal)

LDFLAGS=-shared $(shell pkg-config --libs r_anal)

OBJS=$(NAME).o

LIB=$(NAME).$(LIBEXT)


all: $(LIB)


clean:

rm -f $(LIB) $(OBJS)


$(LIB): $(OBJS)

$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(LIB)


install:

cp -f anal_snes.$(SO_EXT) $(R2_PLUGIN_PATH)


uninstall:

rm -f $(R2_PLUGIN_PATH)/anal_snes.$(SO_EXT)

anal_snes.c:

/* radare - LGPL - Copyright 2015 - condret */


#include 

#include 

#include 

#include 

#include 

#include "snes_op_table.h"


static int snes_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {

memset (op, '\0', sizeof (RAnalOp));

op->size = snes_op[data[0]].len;

op->addr = addr;

op->type = R_ANAL_OP_TYPE_UNK;

switch (data[0]) {

case 0xea:

op->type = R_ANAL_OP_TYPE_NOP;

break;

}

return op->size;

}


struct r_anal_plugin_t r_anal_plugin_snes = {

.name = "snes",

.desc = "SNES analysis plugin",

.license = "LGPL3",

.arch = R_SYS_ARCH_NONE,

.bits = 16,

.init = NULL,

.fini = NULL,

.op = &snes_anop,

.set_reg_profile = NULL,

.fingerprint_bb = NULL,

.fingerprint_fcn = NULL,

.diff_bb = NULL,

.diff_fcn = NULL,

.diff_eval = NULL

};


#ifndef R2_PLUGIN_INCORE

R_API RLibStruct radare_plugin = {

.type = R_LIB_TYPE_ANAL,

.data = &r_anal_plugin_snes,

.version = R2_VERSION

};

#endif

After compiling radare2 will list this plugin in the output:

_dA_ _8_16 snes LGPL3 SuperNES CPU

snes_op_table.h: https://github.com/radareorg/radare2/blob/master/libr/asm/arch/snes/snes_op_table.h

Example:

6502: https://github.com/radareorg/radare2/commit/64636e9505f9ca8b408958d3c01ac8e3ce254a9b

SNES: https://github.com/radareorg/radare2/commit/60d6e5a1b9d244c7085b22ae8985d00027624b49

Implementing a new format

To enable virtual addressing

In info add et->has_va = 1; and ptr->srwx with the R_BIN_SCN_MAP; attribute

Create a folder with file format name in libr/bin/format

Makefile:

NAME=bin_nes

R2_PLUGIN_PATH=$(shell r2 -H R2_USER_PLUGINS)

LIBEXT=$(shell r2 -H LIBEXT)

CFLAGS=-g -fPIC $(shell pkg-config --cflags r_bin)

LDFLAGS=-shared $(shell pkg-config --libs r_bin)

OBJS=$(NAME).o

LIB=$(NAME).$(LIBEXT)


all: $(LIB)


clean:

rm -f $(LIB) $(OBJS)


$(LIB): $(OBJS)

$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(LIB)


install:

cp -f $(NAME).$(SO_EXT) $(R2_PLUGIN_PATH)


uninstall:

rm -f $(R2_PLUGIN_PATH)/$(NAME).$(SO_EXT)


bin_nes.c:

#include 

#include 


static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *b, ut64 loadaddr, Sdb *sdb) {

ut64 size;

const ut8 *buf = r_buf_data (b, &size);

r_return_val_if_fail (buf, false);

*bin_obj = r_bin_internal_nes_load (buf, size);

return *bin_obj != NULL;

}


static void destroy(RBinFile *bf) {

r_bin_free_all_nes_obj (bf->o->bin_obj);

bf->o->bin_obj = NULL;

}


static bool check_buffer(RBuffer *b) {

if (!buf || length < 4) return false;

return (!memcmp (buf, "\x4E\x45\x53\x1A", 4));

}


static RBinInfo* info(RBinFile *arch) {

RBinInfo \*ret = R_NEW0 (RBinInfo);

if (!ret) return NULL;


if (!arch || !arch->buf) {

free (ret);

return NULL;

}

ret->file = strdup (arch->file);

ret->type = strdup ("ROM");

ret->machine = strdup ("Nintendo NES");

ret->os = strdup ("nes");

ret->arch = strdup ("6502");

ret->bits = 8;


return ret;

}


struct r_bin_plugin_t r_bin_plugin_nes = {

.name = "nes",

.desc = "NES",

.license = "BSD",

.get_sdb = NULL,

.load_buffer = &load_buffer,

.destroy = &destroy,

.check_buffer = &check_buffer,

.baddr = NULL,

.entries = NULL,

.sections = NULL,

.info = &info,

};


#ifndef R2_PLUGIN_INCORE

R_API RLibStruct radare_plugin = {

.type = R_LIB_TYPE_BIN,

.data = &r_bin_plugin_nes,

.version = R2_VERSION

};

#endif


Some Examples

• XBE - https://github.com/radareorg/radare2/pull/972

• COFF - https://github.com/radareorg/radare2/pull/645

• TE - https://github.com/radareorg/radare2/pull/61

• Zimgz - https://github.com/radareorg/radare2/commit/d1351cf836df3e2e63043a6dc728e880316f00eb

• OMF - https://github.com/radareorg/radare2/commit/44fd8b2555a0446ea759901a94c06f20566bbc40

Write a debugger plugin

• Adding the debugger registers profile into the shlr/gdb/src/core.c

• Adding the registers profile and architecture support in the libr/debug/p/debug_native.c and libr/debug/p/debug_gdb.c

• Add the code to apply the profiles into the function r_debug_gdb_attach(RDebug *dbg, int pid)

If you want to add support for the gdb, you can see the register profile in the active gdb session using command maint print registers.

More to come..

• Related article: http://radare.today/posts/extending-r2-with-new-plugins/

Some commits related to "Implementing a new architecture"

• Extensa: https://github.com/radareorg/radare2/commit/6f1655c49160fe9a287020537afe0fb8049085d7

• Malbolge: https://github.com/radareorg/radare2/pull/579

• 6502: https://github.com/radareorg/radare2/pull/656

• h8300: https://github.com/radareorg/radare2/pull/664

• GBA: https://github.com/radareorg/radare2/pull/702

• CR16: https://github.com/radareorg/radare2/pull/721/ && 726

• XCore: https://github.com/radareorg/radare2/commit/bb16d1737ca5a471142f16ccfa7d444d2713a54d

• SharpLH5801: https://github.com/neuschaefer/radare2/commit/f4993cca634161ce6f82a64596fce45fe6b818e7

• MSP430: https://github.com/radareorg/radare2/pull/1426

• HP-PA-RISC: https://github.com/radareorg/radare2/commit/f8384feb6ba019b91229adb8fd6e0314b0656f7b

• V810: https://github.com/radareorg/radare2/pull/2899

• TMS320: https://github.com/radareorg/radare2/pull/596

Implementing a new pseudo architecture

This is an simple plugin for z80 that you may use as example:

https://github.com/radareorg/radare2/commit/8ff6a92f65331cf8ad74cd0f44a60c258b137a06

Загрузка...