usercorn - docs

code is here

development happens against the "unstable" branch before master. the NDH stream uses the "lua" branch.

to add passable NDH support, I will need to make:

hierarchy

UsercornCmd
    Usercorn
        Loader
        Arch
            (register definitions)
            CpuBuilder
            AsmBuilder
            DisBuilder
        OS
            (stack setup)
            (syscall dispatcher)
        Task
            Cpu
            (emulator implementation, hook/memory/register management/api)
            (either of the following)
            | UnicornCpu
            | (custom)Cpu
                Hooks
                Mem
                Regs
        Kernel
            

codebase docs

  • cmd/cmd.go - type UsercornCmd

    • common code shared between all usercorn cli tools
    • parses command line flags and sets up a models.Config object
    • main `usercorn` command lives in cmd/usercorn/main.go
    • creates a Usercorn object using specified binary path, then calls usercorn.Run(argv, envp)
  • usercorn.go - type models.Usercorn

    • contains emulator setup, run loop, and many debugging/hooking helpers
    • calls Load() from loader/load.go to detect binary type and create a loader for it
    • takes arch and os name from the loader and calls GetArch() from arch/arch.go to return Arch and OS backends
    • creates a Cpu as provided by the arch, and wraps in a Task type found in task.go to provide limited memory and debugging helper methods
  • loader/*.go - type models.Loader

    • binary type detection and binary parsing for ELF, MachO, and others
    • to add a binary loader, create a new loader type modeled after the example in null.go, then add it to LoadArch() in load.go
  • arch/{x86,arm,etc}/arch.go - type models.Arch

    • contains CPU description, register names, and points at the cpu emulator, assembler, and disassembler setup functions for this architecture
  • arch/{x86,arm,etc}/linux.go - type models.OS, kernel/common.Kernel

    • os-specific files such as linux.go contain the setup and kernel code for that specific operating system and architecture pair
      • linux.go will have a LinuxKernel struct, with the generic kernels/linux/kernel.go kernel embedded inside
      • this allows providing extra syscalls, or custom syscall behavior per kernel
      • linux.go hooks CPU interrupts, as well as CPU-specific syscall instructions
      • and manages the syscall ABI and syscall number -> name mapping
      • then dispatches syscalls to the Usercorn.Syscall() function
  • kernel/linux.go - type kernel/common.Kernel

    • provides syscall implementations for Linux
    • reflection is used (found in kernel/common) to dynamically dispatch syscalls
    • it is sufficient to declare a syscall on a kernel struct and it will be called from Usercorn.Syscall() if the name matches
  • cpu/unicorn/cpu.go - type models/cpu.Cpu

    • primary CPU emulator implementation
    • thin wrapper around the Unicorn engine
  • cpu/capstone.go - type models/cpu.Dis

    • primary disassembler implementation
    • thin wrapper around the Capstone engine
  • models/cpu/ - type models/cpu.Cpu, cpu.Hooks, cpu.Regs, cpu.Mem

    • contains an interface definition for the CPU
    • and an example MMU, register, and debug hooking implementation
    • you can embed them into custom CPU definitions to get most of the interface required by Usercorn for free
    • (just bring your own implementations of cpu.Start(), cpu.Stop(), and cpu.Close())