Skip to content

Commit

Permalink
Implement r2snip to ease the maintainance and creation of code snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
radare committed Aug 5, 2018
1 parent 791cc5d commit c7f2ac9
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 21 deletions.
9 changes: 3 additions & 6 deletions first_steps/basic_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ If radare2 opens an executable file, by default it will open the file in VA mode
The 'print' command is abbreviated as `p` and has a number of submodes — the second letter specifying a desired print mode. Frequent variants include `px` to print in hexadecimal, and `pd` for disassembling.

To be allowed to write files, specify the `-w` option to radare2 when opening a file. The `w` command can be used to write strings, hexpairs (`x` subcommand), or even assembly opcodes (`a` subcommand). Examples:
```
> w hello world ; string
> wx 90 90 90 90 ; hexpairs
> wa jmp 0x8048140 ; assemble
> wf inline.bin ; write contents of file
```

![write examples](basic_usage_01.png)

Appending a `?` to a command will show its help message, for example, `p?`.
Appending `?*` will show commands starting with the given string, e.g. `p?*`.

Expand Down
4 changes: 2 additions & 2 deletions first_steps/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ It was useful to recover a deleted file from an HFS+ partition.

After that pancake decided to extend the tool to have a pluggable io to be able to attach to processes, implemented the debugger functionalities, support for multiple archs, code analysis, etc..

The project has evolved to provide a complete framework for analyzing binaries while making use of basic *NIX concepts. Those concepts include the famous "everything is a file", "small programs that interact using stdin/stdout", and "keep it simple" paradigms.
The project has evolved to provide a complete framework for analyzing binaries while making use of basic UNIX concepts. Those concepts include the famous "everything is a file", "small programs that interact using stdin/stdout", and "keep it simple" paradigms.

But then the need for scripting showed up the fragility of the initial monolitic design of the tool. Making it hard to use the api. A refactoring was needed, in 2009, radare was forked into radare2, a complete refactor of radare1, in a more flexible and dynamic way, enabling a much better integration for using r2 from different programming languages.

It's been a one man project, with some eventual contributions, to a big community project around 2014. The number of users was growing fast, and the author, and main developed had to switch the role from coder to manager, in order to manage the different developers that join the project.

Instructing the users to report their issues allows us to define the new directions of the project in order to evolve. Everything is managed in the [radare2 GitHub](https://github.com/radare/radare2) and discussed in the Telegram channel.

The project remains active at the moment of writing this book, and there are several side projects that provide a graphical user interface (Cutter), a decompiler (r2dec, radeco), Frida integration (r2frida), Yara, Unicorn, Keystone, and many other projects indexed in the r2pm (the radare2 package manager).
The project remains active at the moment of writing this book, and there are several side projects that provide a graphical user interface (Cutter), a decompiler (r2dec, radeco), Frida integration (r2frida), Yara, Unicorn, Keystone, and many other projects indexed in the r2pm (the radare2 package manager).
7 changes: 6 additions & 1 deletion r2/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
R2PNG=node r2png/index.js
R2SNIP=node r2snip.js
D=../img-white/

all:
$(R2SNIP) `find ../| grep snippets$$`
mkdir -p $(D)/configuration
$(R2PNG) bins/ls 'e??~color' > $(D)/configuration/e--color.png
#$(R2PNG) bins/ls 'e??~color' > $(D)/configuration/e--color.png
$(R2PNG) - 'hello world' > a.png
#$(R2PNG) bins/ls 'pd 1 @ 0x00404894' > output.png


33 changes: 21 additions & 12 deletions r2/r2png/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ const file = process.argv[2];
const cmds = process.argv.slice(3)
const text2png = require('text2png');


if (process.argv.length < 4) {
console.error('Usage: r2png [file] [cmds ...] > output.png');
process.exit(1);
}

function log(x) {
if (x) {
console.error(x);
}
}

main().then(log).catch(log);

function replaceAll (txt, replace, with_this) {
replace = replace.replace('|', '\\|');
return txt.replace(new RegExp(replace, 'g'), with_this);
Expand Down Expand Up @@ -105,20 +112,22 @@ process.stdout.write(png);
}

async function main() {
const r2 = await r2promise.open(file, ['-escr.color=0']);
let res = '';
for (let cmd of cmds) {
const seek = (await r2.cmd('?vx $$')).trim();
const out = await r2.cmd(cmd);
res += '['+seek+']> ' + cmd + '\n' + out;
if (file === '"') {
render2 (cmds.join('\n'));
} else {
const r2 = await r2promise.open(file, ['-escr.color=0']);
let res = '';
for (let cmd of cmds) {
const seek = (await r2.cmd('?vx $$')).trim();
const out = await r2.cmd(cmd);
res += '['+seek+']> ' + cmd + '\n' + out;
}
// render (res);
render2 (res);
await r2.quit();
}
// render (res);
render2 (res);
await r2.quit();
}

main().then(_ => console.error(_)).catch(_ => console.error(_));

/*
r2pipe.open(file, ['-escr.color=0'], (err, r2) => {
r2.cmd(cmds, (err, res) => {
Expand Down
66 changes: 66 additions & 0 deletions r2/r2snip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const fs = require('fs');
const path = require('path');
const snippets = process.argv.slice(2);
const { spawnSync } = require('child_process');

for (let snip of snippets) {
const dir = path.dirname(snip);
const text = fs.readFileSync(snip);
parseSnippet(dir, text.toString('utf8'))
}

function system(cmd, args) {
const result = spawnSync(cmd, args, { stdio: ['ignore', 'pipe', 2]});
return result.stdout;
}

function buildSnippetImage(output, mode, args) {
if (mode === 'string') {
console.error('PNG STR', output);
const png = system("node", ['r2png/index.js', '"', ...args]);
fs.writeFileSync(output, png);
} else {
// we need to parse the first arg to get the filename. lets use - for now
console.error('PNG R2R', output);
const png = system("node", ['r2png/index.js', ...args]);
fs.writeFileSync(output, png);
}
}

function parseSnippet(dir, text) {
var filename = '';
var readMode = '';
var args = [];
var comment = {};
for (let _line of text.split('\n')) {
const line = _line.trim();
if (readMode) {
if (line === readMode) {
const mode = (readMode === '"')? 'string': 'commands';
if (mode === 'commands') {
args = [comment.open, ...args];
}
// console.error("RUN", filename, mode, args);
buildSnippetImage(path.join(dir, filename), mode, args);
readMode = '';
args = [];
continue;
}
args.push(line);
continue;
}
if (line.startsWith('//')) {
const words = line.substring(2).trim().split(' ');
comment[words[0]] = words[1];
}
if (line.endsWith('"')) {
if (line.endsWith("(\"")) {
filename = line.substring(0, line.length - 2).trim();
readMode = '\")';
} else {
filename = line.substring(0, line.length - 1).trim();
readMode = '\"';
}
}
}
}

0 comments on commit c7f2ac9

Please sign in to comment.