Skip to content

Commit

Permalink
Initial import of r2pipe-ocaml ( https://github.com/fxfactorial/ocaml…
Browse files Browse the repository at this point in the history
  • Loading branch information
fxfactorial authored and radare committed Sep 26, 2016
1 parent f3a38a5 commit 83dfedb
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ocaml/.merlin
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PKG yojson
FLG -w +a-4-40..42-44-45-48
41 changes: 41 additions & 0 deletions ocaml/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# OASIS_START
# DO NOT EDIT (digest: a3c674b4239234cbbe53afe090018954)

SETUP = ocaml setup.ml

build: setup.data
$(SETUP) -build $(BUILDFLAGS)

doc: setup.data build
$(SETUP) -doc $(DOCFLAGS)

test: setup.data build
$(SETUP) -test $(TESTFLAGS)

all:
$(SETUP) -all $(ALLFLAGS)

install: setup.data
$(SETUP) -install $(INSTALLFLAGS)

uninstall: setup.data
$(SETUP) -uninstall $(UNINSTALLFLAGS)

reinstall: setup.data
$(SETUP) -reinstall $(REINSTALLFLAGS)

clean:
$(SETUP) -clean $(CLEANFLAGS)

distclean:
$(SETUP) -distclean $(DISTCLEANFLAGS)

setup.data:
$(SETUP) -configure $(CONFIGUREFLAGS)

configure:
$(SETUP) -configure $(CONFIGUREFLAGS)

.PHONY: build doc test all install uninstall reinstall clean distclean configure

# OASIS_STOP
86 changes: 86 additions & 0 deletions ocaml/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
OCaml interface to radare2
-------------------------------

This is an OCaml interface to radare2, the reverse engineer's dream
tool.

## Installation

You can install it using `opam` the OCaml package manager,
see [here](http://hyegar.com/2015/10/20/so-youre-learning-ocaml/) for
a quick introduction to the OCaml ecosystem and how to get opam.

If not on opam or wanting to use the latest and greatest then do:

```
$ opam pin add radare2 [email protected]:fxfactorial/ocaml-radare2.git -y
```

Otherwise use the one on `opam`

```
$ opam install radare2 -y
```

## Example usage:

Here's a utop session, (`opam install utop`)

```ocaml
#require "radare2";;
let result = R2.with_command_j ~cmd:"/j chown" "/bin/ls";;
val result : Yojson.Basic.json =
`List
[`Assoc
[("offset", `Int 4294987375); ("id:", `Int 0);
("data", `String "ywritesecuritychownfile_inheritdi")]]"
R2.with_command ~cmd:"S=" "/bin/ls" |> print_endline;;
00* 0x100000e94 |###############-----| 0x10000442d mr-x 0.__text 13.4K
01 0x10000442e |--------------##----| 0x1000045f6 mr-x 1.__stubs 0456
02 0x1000045f8 |---------------##---| 0x100004900 mr-x 2.__stub_helper 0776
03 0x100004900 |----------------#---| 0x100004af0 mr-x 3.__const 0496
04 0x100004af0 |----------------###-| 0x100004f69 mr-x 4.__cstring 1.1K
05 0x100004f6c |------------------#-| 0x100005000 mr-x 5.__unwind_info 0148
06 0x100005000 |------------------#-| 0x100005028 mrw- 6.__got 0040
07 0x100005028 |------------------#-| 0x100005038 mrw- 7.__nl_symbol_ptr 0016
08 0x100005038 |------------------#-| 0x100005298 mrw- 8.__la_symbol_ptr 0608
09 0x1000052a0 |------------------##| 0x1000054c8 mrw- 9.__const 0552
10 0x1000054d0 |-------------------#| 0x1000054f8 mrw- 10.__data 0040
11 0x100005500 |-------------------#| 0x1000055c0 mrw- 11.__bss 0192
12 0x1000055c0 |-------------------#| 0x10000564c mrw- 12.__common 0140
=> 0x100001174 |-^------------------| 0x100001274
```

## Documentation

Here is the `mli` with comments, fairly simple and high level.

```ocaml
(** A running instance of r2 *)
type r2
(** Send a command to r2, get back plain string output *)
val command : r2:r2 -> string -> string
(** Send a command to r2, get back Yojson. If output isn't JSON
parsable then raises {Invalid_argument} so make sure command starts
with /j *)
val command_json : r2:r2 -> string -> Yojson.Basic.json
(** Create a r2 instance with a given file, raises {Invalid_argument}
if file doesn't exists *)
val open_file : string -> r2
(** close a r2 instance *)
val close : r2 -> unit
(** Convenience function for opening a r2 instance, sending a command,
getting the result as plain string and closing the r2 instance *)
val with_command : cmd:string -> string -> string
(** Convenience function for opening a r2 instance, sending a command,
getting the result as Yojson and closing the r2 instance *)
val with_command_j : cmd:string -> string -> Yojson.Basic.json
```
39 changes: 39 additions & 0 deletions ocaml/_oasis
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- conf -*-
OASISFormat: 0.4
Name: radare2
Version: 0.0.1
Synopsis: OCaml interface to radare2
Authors: Edgar Aroutiounian <[email protected]>
Maintainers: Edgar Aroutiounian <[email protected]>
Homepage: https://github.com/fxfactorial/ocaml-radare2
License: BSD-3-clause
OCamlVersion: >= 4.03.0
AlphaFeatures: ocamlbuild_more_args
Plugins: META (0.4), DevFiles (0.4)
BuildTools: ocamlbuild

Description:
Interact with radare2 from within OCaml.
See the mli for documentation, example usage in utop
.
"#require \"radare2\";;"
"let result = R2.with_command_j ~cmd:"/j chown" "/bin/ls";;
val result : Yojson.Basic.json =
`List
[`Assoc
[("offset", `Int 4294987375); ("id:", `Int 0);
("data", `String "ywritesecuritychownfile_inheritdi")]]"


Library radare2
Path: src
Modules: R2
install: true
NativeOpt: -g -w +a-4-40..42-44-45-48
ByteOpt: -g -w +a-4-40..42-44-45-48
BuildDepends: yojson (>= 1.3.2), unix

SourceRepository master
Type: git
Location: https://github.com/fxfactorial/ocaml-radare2.git
Browser: https://github.com/fxfactorial/ocaml-radare2
27 changes: 27 additions & 0 deletions ocaml/configure
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh

# OASIS_START
# DO NOT EDIT (digest: dc86c2ad450f91ca10c931b6045d0499)
set -e

FST=true
for i in "$@"; do
if $FST; then
set --
FST=false
fi

case $i in
--*=*)
ARG=${i%%=*}
VAL=${i##*=}
set -- "$@" "$ARG" "$VAL"
;;
*)
set -- "$@" "$i"
;;
esac
done

ocaml setup.ml -configure "$@"
# OASIS_STOP
12 changes: 12 additions & 0 deletions ocaml/opam/descr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
OCaml interface to r2

Interact with radare2,
See the mli for documentation, example usage in utop:

#require "radare2";;
let result = R2.with_command_j ~cmd:"/j chown" "/bin/ls";;
val result : Yojson.Basic.json =
`List
[`Assoc
[("offset", `Int 4294987375); ("id:", `Int 0);
("data", `String "ywritesecuritychownfile_inheritdi")]]"
1 change: 1 addition & 0 deletions ocaml/opam/findlib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
radare2
55 changes: 55 additions & 0 deletions ocaml/opam/opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- conf -*-
opam-version: "1.2"
name: "radare2"
version: "0.0.1"
maintainer: "Edgar Aroutiounian <[email protected]>"
authors: [ "Edgar Aroutiounian <[email protected]>" ]
license: "BSD-3-clause"
homepage: "https://github.com/fxfactorial/ocaml-radare2"
dev-repo: "https://github.com/fxfactorial/ocaml-radare2.git"
bug-reports: "https://github.com/fxfactorial/ocaml-radare2/issues"
build: [
["oasis" "setup"]
["ocaml" "setup.ml" "-configure" "--prefix" prefix]
["ocaml" "setup.ml" "-build"]
]
install: ["ocaml" "setup.ml" "-install"]
remove: [
["ocamlfind" "remove" "radare2"]
]
build-test: [
["oasis" "setup"]
["ocaml" "setup.ml" "-configure" "--enable-tests"]
["ocaml" "setup.ml" "-build"]
["ocaml" "setup.ml" "-test"]
]
depexts: [
[["debian"] ["radare2"]]
[["ubuntu"] ["radare2"]]
[["homebrew" "osx"] ["radare2"]]
]
depends: [
"base-unix"
"oasis" {build & >= "0.4"}
"ocamlbuild" {build}
"ocamlfind" {build}
("yojson" {>= "1.3.2"} | "yojson-android" {>= "1.3.2"})
]
messages:[
"You need to have r2 (radare2) installed and in your path"
"Use `opam depext radare2` to get it installed with your system package manager"
]

post-messages:[
"Play with radare2 interactively from within an OCaml repl like utop"
"Example in utop:"
""
"#require \"radare2\";;"
"let result = R2.with_command_j ~cmd:\"/j chown\" \"/bin/ls\";;
val result : Yojson.Basic.json =
`List
[`Assoc
[(\"offset\", `Int 4294987375); (\"id:\", `Int 0);
(\"data\", `String \"ywritesecuritychownfile_inheritdi\")]]"
{success}]
available: [ ocaml-version >= "4.03.0" ]
39 changes: 39 additions & 0 deletions ocaml/setup.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
(* setup.ml generated for the first time by OASIS v0.4.7 *)

(* OASIS_START *)
(* DO NOT EDIT (digest: a426e2d026defb34183b787d31fbdcff) *)
(******************************************************************************)
(* OASIS: architecture for building OCaml libraries and applications *)
(* *)
(* Copyright (C) 2011-2016, Sylvain Le Gall *)
(* Copyright (C) 2008-2011, OCamlCore SARL *)
(* *)
(* This library is free software; you can redistribute it and/or modify it *)
(* under the terms of the GNU Lesser General Public License as published by *)
(* the Free Software Foundation; either version 2.1 of the License, or (at *)
(* your option) any later version, with the OCaml static compilation *)
(* exception. *)
(* *)
(* This library is distributed in the hope that it will be useful, but *)
(* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *)
(* or FITNESS FOR A PARTICULAR PURPOSE. See the file COPYING for more *)
(* details. *)
(* *)
(* You should have received a copy of the GNU Lesser General Public License *)
(* along with this library; if not, write to the Free Software Foundation, *)
(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)
(******************************************************************************)

let () =
try
Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
with Not_found -> ()
;;
#use "topfind";;
#require "oasis.dynrun";;
open OASISDynRun;;

let setup_t = BaseCompat.Compat_0_4.adapt_setup_t setup_t
open BaseCompat.Compat_0_4
(* OASIS_STOP *)
let () = setup ();;
62 changes: 62 additions & 0 deletions ocaml/src/r2.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
type r2 =
{pid : int; read_from : Unix.file_descr; write_to : Unix.file_descr}

exception Stop_read

let read_result read_from =
let b = Buffer.create 1 in
let buf = Bytes.create 1 in
begin
try
while true do
Unix.read read_from buf 0 1 |> ignore;
if buf = "\x00" then raise Stop_read
else Buffer.add_bytes b buf
done
with Stop_read -> ()
end;
Buffer.to_bytes b

let send_command {write_to; read_from; _} cmd =
let c = Printf.sprintf "%s\n" cmd in
ignore (Unix.write_substring write_to c 0 (String.length c));
read_result read_from |> String.trim

let command ~r2 cmd = send_command r2 cmd

let command_json ~r2 cmd =
try
send_command r2 cmd |> Yojson.Basic.from_string
with
Yojson.Json_error _ ->
raise (Invalid_argument "Output wasn't JSON parsable, \
make sure you used /j")

let open_file f_name =
if not (Sys.file_exists f_name) then
raise (Invalid_argument "Non-existent file")
else
let (ins_r, ins_w),
(out_r, out_w),
(_, err_w) = Unix.(pipe (), pipe (), pipe ())
in
let args = [|"r2"; "-q0"; f_name|] in
let pid = Unix.create_process "r2" args ins_r out_w err_w in
(* Get rid of the beginning \x00 *)
ignore (Unix.read out_r (Bytes.create 1) 0 1);
{pid; read_from = out_r; write_to = ins_w}

(* Heavy handed but we ensure that r2 is killed *)
let close {pid; _} = Unix.kill pid Sys.sigkill

let with_command ~cmd f_name =
let r2 = open_file f_name in
let output = command ~r2 cmd in
close r2;
output

let with_command_j ~cmd f_name =
let r2 = open_file f_name in
let output = command ~r2 cmd in
close r2;
output |> Yojson.Basic.from_string
Loading

0 comments on commit 83dfedb

Please sign in to comment.