File: sample.go

package info (click to toggle)
unicorn-engine 2.1.4-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 23,912 kB
  • sloc: ansic: 379,830; python: 9,213; sh: 9,011; java: 8,609; ruby: 4,241; pascal: 1,805; haskell: 1,379; xml: 490; cs: 424; makefile: 348; cpp: 298; asm: 64
file content (105 lines) | stat: -rw-r--r-- 2,703 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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)
	}, 1, 0)
	mu.HookAdd(uc.HOOK_CODE, func(mu uc.Unicorn, addr uint64, size uint32) {
		fmt.Printf("Code: 0x%x, 0x%x\n", addr, size)
	}, 1, 0)
	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)
	}, 1, 0)
	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_UNMAPPED | uc.MEM_WRITE_PROT:
			fmt.Printf("invalid write")
		case uc.MEM_READ_UNMAPPED | uc.MEM_READ_PROT:
			fmt.Printf("invalid read")
		case uc.MEM_FETCH_UNMAPPED | uc.MEM_FETCH_PROT:
			fmt.Printf("invalid fetch")
		default:
			fmt.Printf("unknown memory error")
		}
		fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value)
		return false
	}, 1, 0)
	mu.HookAdd(uc.HOOK_INSN, func(mu uc.Unicorn) {
		rax, _ := mu.RegRead(uc.X86_REG_RAX)
		fmt.Printf("Syscall: %d\n", rax)
	}, 1, 0, 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)
	}
}