From 83dfedbd6ae781c126e986b24f54ea82121c0d21 Mon Sep 17 00:00:00 2001 From: Edgar Aroutiounian Date: Mon, 26 Sep 2016 19:13:52 +0200 Subject: [PATCH] Initial import of r2pipe-ocaml ( https://github.com/fxfactorial/ocaml-radare2 ) --- ocaml/.merlin | 2 ++ ocaml/Makefile | 41 ++++++++++++++++++++++ ocaml/README.md | 86 ++++++++++++++++++++++++++++++++++++++++++++++ ocaml/_oasis | 39 +++++++++++++++++++++ ocaml/configure | 27 +++++++++++++++ ocaml/opam/descr | 12 +++++++ ocaml/opam/findlib | 1 + ocaml/opam/opam | 55 +++++++++++++++++++++++++++++ ocaml/setup.ml | 39 +++++++++++++++++++++ ocaml/src/r2.ml | 62 +++++++++++++++++++++++++++++++++ ocaml/src/r2.mli | 27 +++++++++++++++ 11 files changed, 391 insertions(+) create mode 100644 ocaml/.merlin create mode 100644 ocaml/Makefile create mode 100644 ocaml/README.md create mode 100644 ocaml/_oasis create mode 100755 ocaml/configure create mode 100644 ocaml/opam/descr create mode 100644 ocaml/opam/findlib create mode 100644 ocaml/opam/opam create mode 100644 ocaml/setup.ml create mode 100644 ocaml/src/r2.ml create mode 100644 ocaml/src/r2.mli diff --git a/ocaml/.merlin b/ocaml/.merlin new file mode 100644 index 0000000..fd97a3a --- /dev/null +++ b/ocaml/.merlin @@ -0,0 +1,2 @@ +PKG yojson +FLG -w +a-4-40..42-44-45-48 diff --git a/ocaml/Makefile b/ocaml/Makefile new file mode 100644 index 0000000..3639f14 --- /dev/null +++ b/ocaml/Makefile @@ -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 diff --git a/ocaml/README.md b/ocaml/README.md new file mode 100644 index 0000000..16c2c98 --- /dev/null +++ b/ocaml/README.md @@ -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 git@github.com: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 +``` diff --git a/ocaml/_oasis b/ocaml/_oasis new file mode 100644 index 0000000..594a76f --- /dev/null +++ b/ocaml/_oasis @@ -0,0 +1,39 @@ +# -*- conf -*- +OASISFormat: 0.4 +Name: radare2 +Version: 0.0.1 +Synopsis: OCaml interface to radare2 +Authors: Edgar Aroutiounian +Maintainers: Edgar Aroutiounian +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 diff --git a/ocaml/configure b/ocaml/configure new file mode 100755 index 0000000..6acfaeb --- /dev/null +++ b/ocaml/configure @@ -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 diff --git a/ocaml/opam/descr b/ocaml/opam/descr new file mode 100644 index 0000000..e17d05e --- /dev/null +++ b/ocaml/opam/descr @@ -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")]]" diff --git a/ocaml/opam/findlib b/ocaml/opam/findlib new file mode 100644 index 0000000..61d6386 --- /dev/null +++ b/ocaml/opam/findlib @@ -0,0 +1 @@ +radare2 diff --git a/ocaml/opam/opam b/ocaml/opam/opam new file mode 100644 index 0000000..8322e38 --- /dev/null +++ b/ocaml/opam/opam @@ -0,0 +1,55 @@ +# -*- conf -*- +opam-version: "1.2" +name: "radare2" +version: "0.0.1" +maintainer: "Edgar Aroutiounian " +authors: [ "Edgar Aroutiounian " ] +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" ] diff --git a/ocaml/setup.ml b/ocaml/setup.ml new file mode 100644 index 0000000..0349361 --- /dev/null +++ b/ocaml/setup.ml @@ -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 ();; diff --git a/ocaml/src/r2.ml b/ocaml/src/r2.ml new file mode 100644 index 0000000..7a5bce7 --- /dev/null +++ b/ocaml/src/r2.ml @@ -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 diff --git a/ocaml/src/r2.mli b/ocaml/src/r2.mli new file mode 100644 index 0000000..ad66019 --- /dev/null +++ b/ocaml/src/r2.mli @@ -0,0 +1,27 @@ +(** Interact with radare2, ideal for utop interaction *) + +(** 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