Skip to content

Instantly share code, notes, and snippets.

@XVilka
Last active July 5, 2021 05:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save XVilka/e9ed959fff2d87a917021ed602766c35 to your computer and use it in GitHub Desktop.
Save XVilka/e9ed959fff2d87a917021ed602766c35 to your computer and use it in GitHub Desktop.
Rizin API use with Go/cgo
all:
go build -v
run:
go run rz-api.go
package main
// #cgo pkg-config: rz_core rz_analysis rz_bin rz_io rz_util
// #include <stdlib.h>
// #include <rz_util.h>
// #include <rz_bin.h>
// #include <rz_io.h>
// #include <rz_core.h>
// #include <rz_analysis.h>
// #include <rz_project.h>
import "C"
import (
"unsafe"
"runtime"
"fmt"
)
type RzAPI struct {
core *C.RzCore
file *C.RzCoreFile
}
// Helper functions
// RzList -> Go slice
// #define rz_list_foreach(list, it, pos)
// if (list) \
// for (it = list->head; it && (pos = it->data, 1); it = it->n)
func RzListToGoSlice(lst *C.RzList) []unsafe.Pointer {
if lst == nil {
return nil
}
var slice []unsafe.Pointer
it := lst.head
var i int
for it != nil {
i = i + 1
slice = append(slice, it.data)
it = it.n
}
return slice
}
// RzVector -> Go slice
func RzVectorToGoSlice(vec *C.RzVector) []unsafe.Pointer {
if C.rz_vector_empty(vec) {
return nil
}
var slice []unsafe.Pointer
var element unsafe.Pointer
var i uint32
length := uint32(C.rz_vector_len(vec))
for i = 0; i < length; i++ {
element = C.rz_vector_index_ptr(vec, C.ulong(i))
slice = append(slice, element)
}
return slice
}
// RzPVector -> Go slice
// Note that RzPVector is the same as RzVector but contains pointers
func RzPVectorToGoSlice(vec *C.RzPVector) []unsafe.Pointer {
if C.rz_pvector_empty(vec) {
return nil
}
var slice []unsafe.Pointer
var element unsafe.Pointer
var i uint32
length := uint32(C.rz_pvector_len(vec))
for i = 0; i < length; i++ {
element = *(*unsafe.Pointer)(C.rz_pvector_index_ptr(vec, C.ulong(i)))
if (element == nil) {
continue
}
slice = append(slice, element)
}
return slice
}
// API initialization
func APIInit(path string) (*RzAPI, error) {
// RzCore *core = rz_core_new();
core := C.rz_core_new()
// RzCoreFile *file = rz_core_file_open(core, path, RZ_PERM_R, loadaddr);
fpath := C.CString(path)
defer C.free(unsafe.Pointer(fpath))
file := C.rz_core_file_open(core, fpath, C.RZ_PERM_R, 0)
// void rz_core_bin_load(core, fpath, loadaddr)
C.rz_core_bin_load(core, fpath, 0)
api := &RzAPI{core, file}
runtime.SetFinalizer(api, APIRelease)
return api, nil
}
func APIRelease(api *RzAPI) {
// rz_core_file_free(file);
C.rz_core_file_free(api.file)
api.file = nil
// rz_core_free(core);
C.rz_core_free(api.core)
api.core = nil
}
func RizinAnalysis(api *RzAPI) {
// rz_core_analysis_all(core);
C.rz_core_analysis_all(api.core)
// rz_core_analysis_everything(core, false, "esil")
C.rz_core_analysis_everything(api.core, false, C.CString("esil"))
}
func RizinSaveProject(api *RzAPI, path string) {
// rz_project_save_file(core, path);
C.rz_project_save_file(api.core, C.CString(path))
}
func RizinOpenProject(api *RzAPI, path string) bool {
var res *C.RzSerializeResultInfo
res = C.rz_serialize_result_info_new()
// rz_project_save_file(core, path);
err := C.rz_project_load_file(api.core, C.CString(path), true, res)
return err == C.RZ_PROJECT_ERR_SUCCESS
}
type RzBinString struct {
s string
vaddr uint64
paddr uint64
ordinal uint32
size uint32
length uint32
typ int8
}
// FIXME: This C API is deprecated, we should switch to the new RzBinFile-based API when available
// https://github.com/rizinorg/rizin/issues/1027
func RizinFileStrings(api *RzAPI) []RzBinString {
// RzList *rz_bin_get_strings(RzBin *bin)
strings := RzListToGoSlice(C.rz_bin_get_strings(api.core.bin))
var binstrings []RzBinString
for _, s := range strings {
var bs RzBinString
// unsafe.Pointer to *C.RzBinString
rs := (*C.RzBinString)(s)
bs.s = C.GoString(rs.string)
bs.vaddr = uint64(rs.vaddr)
bs.paddr = uint64(rs.paddr)
bs.ordinal = uint32(rs.ordinal)
bs.size = uint32(rs.size)
bs.length = uint32(rs.length)
bs.typ = int8(rs._type)
binstrings = append(binstrings, bs)
}
return binstrings
}
func printBinString(s RzBinString) {
fmt.Printf("String [%d] %q (%d/%d) [0x%x | 0x%x]\n", s.ordinal, s.s, s.size, s.length, s.vaddr, s.paddr)
}
type RzIOMap struct {
id int32
addr uint64
size uint64
delta uint64
perm int
name string
}
func RizinMemoryMaps(api *RzAPI) []RzIOMap {
// RzPVector *rz_io_maps(RzIO *io)
maps := RzPVectorToGoSlice(C.rz_io_maps(api.core.io))
var iomaps []RzIOMap
for _, m := range maps {
var iomap RzIOMap
// unsafe.Pointer to *C.RzIOMap
rzm := (*C.RzIOMap)(m)
iomap.id = int32(rzm.id)
iomap.addr = uint64(rzm.itv.addr)
iomap.size = uint64(rzm.itv.size)
iomap.delta = uint64(rzm.delta)
iomap.perm = int(rzm.perm)
iomap.name = C.GoString(rzm.name)
iomaps = append(iomaps, iomap)
}
return iomaps
}
func printMemoryMap(m RzIOMap) {
fmt.Printf("Memory Map [%d] %q [0x%x - 0x%x + 0x%x]\n", m.id, m.name, m.addr, m.addr, m.size)
}
func main() {
path := "/bin/ls"
project := "bin_ls.rzdb"
fmt.Println("RzCore: opening ", path)
api, _ := APIInit(path)
fmt.Println("RzCore: analyse everything")
RizinAnalysis(api)
fmt.Println("RzCore: save project ", project)
RizinSaveProject(api, project)
fmt.Println("RzIO: maps:")
maps := RizinMemoryMaps(api)
for _, m := range maps {
printMemoryMap(m)
}
fmt.Println("RzBin: strings:")
strings := RizinFileStrings(api)
for _, s := range strings {
printBinString(s)
}
fmt.Println("RzCore: closing ", path)
APIRelease(api)
fmt.Println("RzCore: opening again", path)
api, _ = APIInit(path)
fmt.Println("RzCore: open previous saved project ", project)
RizinOpenProject(api, project)
fmt.Println("RzCore: closing again", path)
APIRelease(api)
}
@XVilka
Copy link
Author

XVilka commented Apr 28, 2021

~/rizin/rz-api-go 
[i] ℤ make                                                                                                                                                                                                                        17:25:42 
go build -v
~/rizin/rz-api-go 
[i] ℤ make run                                                                                                                                                                                                                    17:28:11 
go run rz-api.go
RzCore: opening  /bin/ls
RzCore: analyse everything
[x] Analyze function calls (aac)
[x] find and analyze function preludes (aap)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for classes
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
RzCore: save project  bin_ls.rzdb
RzCore: closing  /bin/ls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment