mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-18 15:07:16 +00:00
add Go README and sample.go
This commit is contained in:
parent
b1d41d414b
commit
1bb4d6685c
29
bindings/go/README.md
Normal file
29
bindings/go/README.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
To download/update the Unicorn Go bindings, run:
|
||||||
|
|
||||||
|
go get -u github.com/unicorn-engine/unicorn/bindings/go
|
||||||
|
|
||||||
|
A very basic usage example follows
|
||||||
|
|
||||||
|
_(Does not handle most errors for brevity. Please see sample.go for a more hygenic example):_
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mu, _ := uc.NewUnicorn(uc.ARCH_X86, uc.MODE_32)
|
||||||
|
// mov eax, 1234
|
||||||
|
code := []byte{184, 210, 4, 0, 0}
|
||||||
|
mu.MemMap(0x1000, 0x1000)
|
||||||
|
mu.MemWrite(0x1000, code)
|
||||||
|
if err := mu.Start(0x1000, 0x1000+uint64(len(code))); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
eax, _ := mu.RegRead(uc.X86_REG_EAX)
|
||||||
|
fmt.Printf("EAX is now: %d\n", eax)
|
||||||
|
}
|
||||||
|
|
||||||
|
An example program exercising far more Unicorn functionality and error handling can be found in sample.go.
|
105
bindings/go/sample.go
Normal file
105
bindings/go/sample.go
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var asm = strings.Join([]string{
|
||||||
|
"48c7c003000000", // mov rax, 3
|
||||||
|
"0f05", // syscall
|
||||||
|
"48c7c700400000", // mov rdi, 0x4000
|
||||||
|
"488907", // mov [rdi], rdx
|
||||||
|
"488b07", // mov rdx, [rdi]
|
||||||
|
"4883c201", // add rdx, 1
|
||||||
|
}, "")
|
||||||
|
|
||||||
|
func addHooks(mu uc.Unicorn) {
|
||||||
|
mu.HookAdd(uc.HOOK_BLOCK, func(mu uc.Unicorn, addr uint64, size uint32) {
|
||||||
|
fmt.Printf("Block: 0x%x, 0x%x\n", addr, size)
|
||||||
|
})
|
||||||
|
mu.HookAdd(uc.HOOK_CODE, func(mu uc.Unicorn, addr uint64, size uint32) {
|
||||||
|
fmt.Printf("Code: 0x%x, 0x%x\n", addr, size)
|
||||||
|
})
|
||||||
|
mu.HookAdd(uc.HOOK_MEM_READ|uc.HOOK_MEM_WRITE, func(mu uc.Unicorn, access int, addr uint64, size int, value int64) {
|
||||||
|
if access == uc.MEM_WRITE {
|
||||||
|
fmt.Printf("Mem write")
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Mem read")
|
||||||
|
}
|
||||||
|
fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value)
|
||||||
|
})
|
||||||
|
invalid := uc.HOOK_MEM_READ_INVALID | uc.HOOK_MEM_WRITE_INVALID | uc.HOOK_MEM_FETCH_INVALID
|
||||||
|
mu.HookAdd(invalid, func(mu uc.Unicorn, access int, addr uint64, size int, value int64) bool {
|
||||||
|
switch access {
|
||||||
|
case uc.MEM_WRITE_INVALID:
|
||||||
|
fmt.Printf("invalid write")
|
||||||
|
case uc.MEM_READ_INVALID:
|
||||||
|
fmt.Printf("invalid read")
|
||||||
|
case uc.MEM_FETCH_INVALID:
|
||||||
|
fmt.Printf("invalid fetch")
|
||||||
|
default:
|
||||||
|
fmt.Printf("unknown memory error")
|
||||||
|
}
|
||||||
|
fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
mu.HookAdd(uc.HOOK_INSN, func(mu uc.Unicorn) {
|
||||||
|
rax, _ := mu.RegRead(uc.X86_REG_RAX)
|
||||||
|
fmt.Printf("Syscall: %d\n", rax)
|
||||||
|
}, uc.X86_INS_SYSCALL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
code, err := hex.DecodeString(asm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// set up unicorn instance and add hooks
|
||||||
|
mu, err := uc.NewUnicorn(uc.ARCH_X86, uc.MODE_64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addHooks(mu)
|
||||||
|
// map and write code to memory
|
||||||
|
if err := mu.MemMap(0x1000, 0x1000); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := mu.MemWrite(0x1000, code); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// map scratch space
|
||||||
|
if err := mu.MemMap(0x4000, 0x1000); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// set example register
|
||||||
|
if err := mu.RegWrite(uc.X86_REG_RDX, 1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rdx, err := mu.RegRead(uc.X86_REG_RDX)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("RDX is: %d\n", rdx)
|
||||||
|
|
||||||
|
// start emulation
|
||||||
|
if err := mu.Start(0x1000, 0x1000+uint64(len(code))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// read back example register
|
||||||
|
rdx, err = mu.RegRead(uc.X86_REG_RDX)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("RDX is now: %d\n", rdx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue