Last active
June 18, 2018 07:22
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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