Skip to content

Instantly share code, notes, and snippets.

@twitchyliquid64
Last active June 18, 2018 07:22
Show Gist options
  • Save twitchyliquid64/c0b36f9c0787292a8cfac74a96013994 to your computer and use it in GitHub Desktop.
Save twitchyliquid64/c0b36f9c0787292a8cfac74a96013994 to your computer and use it in GitHub Desktop.
Hacky program to test if Unicorn can successfully emulate one of my firmware blobs
package main
// NOTE: You need to install 'unicorn' library from https://github.com/unicorn-engine/unicorn first.
import (
"encoding/binary"
"fmt"
"io/ioutil"
uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
)
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 mapPeripherals(mu uc.Unicorn) {
if err := mu.MemMap(0x40052000, 1024); err != nil { //MKE04Z Watchdog timer
panic(err)
}
if err := mu.MemMap(0x40064000, 1024); err != nil { //MKE04Z ICS registers
panic(err)
}
if err := mu.MemMap(0x40048000, 1024); err != nil { //MKE04Z SIM registers
panic(err)
}
if err := mu.MemMap(0x40037000, 1024); err != nil { //MKE04Z Programmable Interrupt Timer registers
panic(err)
}
if err := mu.MemMap(0x4003B000, 1024); err != nil { //MKE04Z ADC registers
panic(err)
}
if err := mu.MemMap(0x40038000, 1024*2); err != nil { //MKE04Z FlexTimer registers
panic(err)
}
if err := mu.MemMap(0x4006A000, 1024); err != nil { //MKE04Z UART0 registers
panic(err)
}
if err := mu.MemMap(0x400ff000, 1024*4); err != nil { //MKE04Z GPIO registers
panic(err)
}
if err := mu.MemMap(0xe0000000, 1024*1024*0xF); err != nil { //ARM Private Peripheral Bus registers
panic(err)
}
}
func main() {
code, err := ioutil.ReadFile("testdata/cortex-m0-plus-crap.bin")
if err != nil {
panic(err)
}
mu, err := uc.NewUnicorn(uc.ARCH_ARM, uc.MODE_ARM)
if err != nil {
panic(err)
}
defer mu.Close()
pgeSize, err := mu.Query(uc.QUERY_PAGE_SIZE)
if err != nil {
panic(err)
}
fmt.Printf("Page size = 0x%x\n", pgeSize)
addHooks(mu)
mapPeripherals(mu)
// map and write blob to memory - 0x0 is 8kb of flash
if err := mu.MemMap(0, 1024*8); err != nil {
panic(err)
}
if err := mu.MemWrite(0, code); err != nil {
panic(err)
}
// map SRAM
if err := mu.MemMap(0x1ffff000, 1024*8); err != nil {
panic(err)
}
stackPointerRaw, err := mu.MemRead(0, 4)
if err != nil {
panic(err)
}
stackPtr := uint64(binary.LittleEndian.Uint32(stackPointerRaw))
fmt.Printf("Stack pointer at 0x%x\n", stackPtr)
if err := mu.RegWrite(uc.ARM_REG_R13, stackPtr); err != nil { //set stack pointer
panic(err)
}
resetAddressRaw, err := mu.MemRead(4, 4)
if err != nil {
panic(err)
}
resetAddr := uint64(binary.LittleEndian.Uint32(resetAddressRaw))
fmt.Printf("Blob starts at 0x%x\n", resetAddr)
fmt.Printf("Simulation error: %v\n", mu.StartWithOptions(resetAddr, resetAddr+1024*8, &uc.UcOptions{Count: 1024 * 8}))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment