func StackArgs(u models.Usercorn) func(n int) ([]uint64, error) { return func(n int) ([]uint64, error) { sp, _ := u.RegRead(u.Arch().SP) // starts with an empty slot s := u.StrucAt(sp + uint64(u.Bits()/8)) ret := make([]uint64, n) for i := 0; i < n; i++ { var arg uint64 var err error // TODO: simplify this when struc issue #47 is fixed if u.Bits() == 64 { err = s.Unpack(&arg) } else { var arg32 uint32 err = s.Unpack(&arg32) arg = uint64(arg32) } if err != nil { return nil, err } ret[i] = arg } return ret, nil } }
func DarwinInit(u models.Usercorn, args, env []string) error { if err := darwin.StackInit(u, args, env); err != nil { return err } // FIXME: lib43 crashes if 32-bit darwin gets mach header. maybe I need to align the stack. u.Pop() return nil }
func LinuxInterrupt(u models.Usercorn, intno uint32) { if intno == 2 { num, _ := u.RegRead(uc.ARM64_REG_X8) LinuxSyscall(u, int(num)) return } panic(fmt.Sprintf("unhandled ARM interrupt: %d", intno)) }
func LinuxInterrupt(u models.Usercorn, intno uint32) { if intno == 0 { u.Exit(errors.New("division by zero")) } if intno == 0x80 { LinuxSyscall(u) } }
func LinuxSyscall(u models.Usercorn, num int) { // TODO: EABI has a different syscall base (OABI is 0x900000) // TODO: does the generator handle this? it needs to. if num > 0x900000 { num -= 0x900000 } name, _ := sysnum.Linux_arm[int(num)] ret, _ := u.Syscall(int(num), name, common.RegArgs(u, LinuxRegs)) u.RegWrite(uc.ARM_REG_R0, ret) }
func pushAddrs(u models.Usercorn, addrs []uint64) error { if _, err := u.Push(0); err != nil { return err } for i, _ := range addrs { if _, err := u.Push(addrs[len(addrs)-i-1]); err != nil { return err } } return nil }
func pushStrings(u models.Usercorn, args ...string) ([]uint64, error) { addrs := make([]uint64, 0, len(args)+1) for _, arg := range args { if addr, err := u.PushBytes([]byte(arg + "\x00")); err != nil { return nil, err } else { addrs = append(addrs, addr) } } return addrs, nil }
func Wrmsr(u models.Usercorn, msr, value uint64) { wrmsr := []byte{0x0F, 0x30} u.RunShellcode( 0, wrmsr, map[int]uint64{ uc.X86_REG_RAX: value & 0xFFFFFFFF, uc.X86_REG_RDX: value >> 32 & 0xFFFFFFFF, uc.X86_REG_RCX: msr & 0xFFFFFFFF, }, nil, ) }
func AbiInit(u models.Usercorn, syscall func(models.Usercorn)) error { _, err := u.HookAdd(uc.HOOK_INSN, func(_ uc.Unicorn) { syscall(u) }, 1, 0, uc.X86_INS_SYSCALL) if err == nil { _, err = u.HookAdd(uc.HOOK_INSN, func(_ uc.Unicorn) { syscall(u) }, 1, 0, uc.X86_INS_SYSENTER) } return err }
func (p *memImage) traceMem(u models.Usercorn, addr uint64, data []byte) { if len(data) > p.blockSize { firstLen := (addr+uint64(p.blockSize)-1) & ^uint64(p.blockSize-1) - addr if firstLen > 0 { p.traceMem(u, addr, data[:firstLen]) } for i := firstLen; i < uint64(len(data)); i += uint64(p.blockSize) { p.traceMem(u, addr+uint64(i), data[i:i+uint64(p.blockSize)]) } return } i, m, had := p.find(addr) if !had { aligned := addr & ^uint64(p.blockSize-1) r := ®ion{ Addr: aligned, Size: uint64(p.blockSize), Data: make([]byte, p.blockSize), } for _, v := range u.Mappings() { if v.Contains(addr) { r.Desc = v.Desc r.Prot = v.Prot if v.File != nil { r.Filename = v.File.Name } break } } p.maps = append(p.maps, r) sort.Sort(RegionAddrSort(p.maps)) i, m, _ = p.find(addr) p.resize() } off := (addr - m.Addr) dst := m.Data[off:] for i, v := range data { if (dst[i] == 0) != (v == 0) { if v != 0 { m.ByteCount++ } else { m.ByteCount-- } } dst[i] = v } if m.ByteCount == 0 { p.maps = append(p.maps[:i], p.maps[i+1:]...) p.resize() } }
func packAddrs(u models.Usercorn, addrs []uint64) ([]byte, error) { buf := make([]byte, int(u.Bits())/8*(len(addrs)+1)) pos := buf for _, v := range addrs { x, err := u.PackAddr(pos, v) if err != nil { return nil, err } pos = pos[len(x):] } return buf, nil }
func SetupElfAuxv(u models.Usercorn) ([]byte, error) { var buf bytes.Buffer auxv, err := setupElfAuxv(u) if err != nil { return nil, err } options := &struc.Options{ PtrSize: int(u.Bits()), Order: u.ByteOrder(), } for _, a := range auxv { if err := struc.PackWithOptions(&buf, &a, options); err != nil { return nil, err } } return buf.Bytes(), err }
func StackArgs(u models.Usercorn) func(n int) ([]uint64, error) { return func(n int) ([]uint64, error) { _, err := u.Pop() if err != nil { return nil, err } ret := make([]uint64, n) for i := 0; i < n; i++ { v, err := u.Pop() if err != nil { return nil, err } ret[i] = v } return ret, nil } }
func DarwinSyscall(u models.Usercorn, class int) { // TODO: read args from stack without modifying reg so we don't need to restore esp esp, _ := u.RegRead(uc.X86_REG_ESP) getArgs := common.StackArgs(u) eax, _ := u.RegRead(uc.X86_REG_EAX) nr := class<<24 | int(eax) name, _ := num.Darwin_x86_mach[nr] ret, _ := u.Syscall(nr, name, getArgs) u.RegWrite(uc.X86_REG_EAX, ret) u.RegWrite(uc.X86_REG_ESP, esp) }
func LinuxSyscall(u models.Usercorn) { // TODO: handle errors or something eax, _ := u.RegRead(uc.X86_REG_EAX) name, _ := num.Linux_x86[int(eax)] ret, _ := u.Syscall(int(eax), name, co.RegArgs(u, LinuxRegs)) u.RegWrite(uc.X86_REG_EAX, ret) }
func Rdmsr(u models.Usercorn, msr uint64) uint64 { rcx, _ := u.RegRead(uc.X86_REG_RCX) rdx, _ := u.RegRead(uc.X86_REG_RDX) rdmsr := []byte{0x0F, 0x30} regs := map[int]uint64{uc.X86_REG_RAX: msr} u.RunShellcode(0, rdmsr, regs, nil) ecx, _ := u.RegRead(uc.X86_REG_ECX) edx, _ := u.RegRead(uc.X86_REG_EDX) u.RegWrite(uc.X86_REG_RCX, rcx) u.RegWrite(uc.X86_REG_RDX, rdx) return (edx << 32) | (ecx & 0xFFFFFFFF) }
func LinuxSyscall(u models.Usercorn) { // TODO: handle errors or something num, _ := u.RegRead(uc.MIPS_REG_V0) name, _ := sysnum.Linux_mips[int(num)] ret, _ := u.Syscall(int(num), name, common.RegArgs(u, LinuxRegs)) u.RegWrite(uc.MIPS_REG_V0, ret) }
func LinuxSyscall(u models.Usercorn) { // TODO: handle errors or something g1, _ := u.RegRead(uc.SPARC_REG_G1) // TODO: add sparc x86 syscall numbers to ghostrace name, _ := num.Linux_x86[int(g1)] ret, _ := u.Syscall(int(g1), name, co.RegArgs(u, LinuxRegs)) u.RegWrite(uc.SPARC_REG_O0, ret) }
func DarwinSyscall(u models.Usercorn, class int) { getArgs := common.StackArgs(u) eax, _ := u.RegRead(uc.X86_REG_EAX) nr := class<<24 | int(eax) name, _ := num.Darwin_x86_mach[nr] ret, _ := u.Syscall(nr, name, getArgs) u.RegWrite(uc.X86_REG_EAX, ret) }
func LinuxInterrupt(u models.Usercorn, intno uint32) { if intno == 2 { // TODO: thumb? issue #121 pc, _ := u.RegRead(uc.ARM_REG_PC) var tmp [4]byte if err := u.MemReadInto(tmp[:], pc-4); err != nil { panic(err) } n := u.UnpackAddr(tmp[:]) & 0xffff if n > 0 { LinuxSyscall(u, int(n)) return } // TODO: handle errors or something num, _ := u.RegRead(uc.ARM_REG_R7) LinuxSyscall(u, int(num)) return } panic(fmt.Sprintf("unhandled ARM interrupt: %d", intno)) }
func enterUsermode(u models.Usercorn) error { // move CPU from System to User mode modeSwitch := []byte{ 0x00, 0x00, 0x0f, 0xe1, // mrs r0, cpsr 0x1f, 0x00, 0xc0, 0xe3, // bic r0, r0, $0x1f 0x10, 0x00, 0x80, 0xe3, // orr r0, r0, $0x10 0x00, 0xf0, 0x21, 0xe1, // msr cpsr_c, r0 } mmap, err := u.Mmap(0, uint64(len(modeSwitch))) if err != nil { return err } defer u.MemUnmap(mmap.Addr, mmap.Size) end := mmap.Addr + uint64(len(modeSwitch)) err = u.RunShellcodeMapped(mmap, modeSwitch, map[int]uint64{uc.ARM_REG_LR: end}, []int{uc.ARM_REG_R0, uc.ARM_REG_LR, uc.ARM_REG_SP}, ) return err }
func SetupElfAuxv(u models.Usercorn) ([]byte, error) { var buf bytes.Buffer auxv, err := setupElfAuxv(u) if err != nil { return nil, err } if u.Bits() == 32 { var auxv32 Elf32Auxv for _, a := range auxv { auxv32.Type = uint32(a.Type) auxv32.Val = uint32(a.Val) if err := struc.PackWithOrder(&buf, &auxv32, u.ByteOrder()); err != nil { return nil, err } } } else { for _, a := range auxv { if err := struc.PackWithOrder(&buf, &a, u.ByteOrder()); err != nil { return nil, err } } } return buf.Bytes(), err }
func setupElfAuxv(u models.Usercorn) ([]Elf64Auxv, error) { // set up AT_RANDOM var tmp [16]byte if _, err := rand.Read(tmp[:]); err != nil { return nil, err } randAddr, err := u.PushBytes(tmp[:]) if err != nil { return nil, err } // insert platform string platformAddr, err := u.PushBytes([]byte(u.Loader().Arch() + "\x00")) if err != nil { return nil, err } // main auxv table auxv := []Elf64Auxv{ // TODO: set/track a page size somewhere - on Arch.OS? {ELF_AT_PAGESZ, 4096}, {ELF_AT_BASE, u.InterpBase()}, {ELF_AT_FLAGS, 0}, {ELF_AT_ENTRY, uint64(u.BinEntry())}, {ELF_AT_UID, uint64(os.Getuid())}, {ELF_AT_EUID, uint64(os.Geteuid())}, {ELF_AT_GID, uint64(os.Getgid())}, {ELF_AT_EGID, uint64(os.Getegid())}, {ELF_AT_PLATFORM, platformAddr}, {ELF_AT_CLKTCK, 100}, // 100hz, totally fake {ELF_AT_RANDOM, randAddr}, {ELF_AT_NULL, 0}, } // add phdr information if present in binary phdrOff, _, phdrCount := u.Loader().Header() segments, _ := u.Loader().Segments() for _, s := range segments { if s.ContainsPhys(phdrOff) { phdrOff += s.Addr break } } phdrEnt := 56 if u.Bits() == 32 { phdrEnt = 56 // FIXME } if phdrOff > 0 { auxv = append(auxv, []Elf64Auxv{ {ELF_AT_PHDR, phdrOff}, {ELF_AT_PHENT, uint64(phdrEnt)}, {ELF_AT_PHNUM, uint64(phdrCount)}, }...) } return auxv, nil }
func StackInit(u models.Usercorn, args, env []string) error { exe := u.Exe() addr, err := u.PushBytes([]byte(exe + "\x00")) if err != nil { return err } var tmp [8]byte auxv, err := u.PackAddr(tmp[:], addr) if err != nil { return err } err = posix.StackInit(u, args, env, auxv) if err != nil { return err } // offset to mach_header at exe[0:] in guest memory textOffset, _, _ := u.Loader().Header() offset := u.Base() + textOffset _, err = u.Push(offset) return err }
func DarwinSyscall(u models.Usercorn) { rax, _ := u.RegRead(uc.X86_REG_RAX) name, _ := num.Darwin_x86_mach[int(rax)] ret, _ := u.Syscall(int(rax), name, common.RegArgs(u, AbiRegs)) u.RegWrite(uc.X86_REG_RAX, ret) }
func AbiInit(u models.Usercorn, args, env []string, auxv []byte, syscall func(models.Usercorn)) error { u.HookAdd(uc.HOOK_INSN, func(_ uc.Unicorn) { syscall(u) }, uc.X86_INS_SYSCALL) return u.PosixInit(args, env, auxv) }
func LinuxSyscall(u models.Usercorn, num int) { name, _ := sysnum.Linux_arm[int(num)] ret, _ := u.Syscall(int(num), name, common.RegArgs(u, LinuxRegs)) u.RegWrite(uc.ARM64_REG_X0, ret) }
func CgcInit(u models.Usercorn, args, env []string) error { return u.PosixInit(args, env, nil) }
func LinuxSyscall(u models.Usercorn) { rax, _ := u.RegRead(uc.X86_REG_RAX) name, _ := num.Linux_x86_64[int(rax)] ret, _ := u.Syscall(int(rax), name, common.RegArgs(u, AbiRegs)) u.RegWrite(uc.X86_REG_RAX, ret) }
func CgcSyscall(u models.Usercorn) { // TODO: handle errors or something args, _ := u.ReadRegs(LinuxRegs) eax, _ := u.RegRead(uc.X86_REG_EAX) var ret uint64 switch eax { case 1: // _terminate syscall.Exit(int(args[0])) case 2: // transmit mem, _ := u.MemRead(args[1], args[2]) n, _ := syscall.Write(int(args[0]), mem) writeAddr(u, args[3], uint64(n)) case 3: // receive tmp := make([]byte, args[2]) n, _ := syscall.Read(int(args[0]), tmp) u.MemWrite(args[1], tmp[:n]) writeAddr(u, args[3], uint64(n)) case 5: // allocate addr, _ := u.Mmap(0, args[0]) // args[1] == is executable writeAddr(u, args[2], addr) case 6: // fdwait nfds := int(args[0]) var readSet, writeSet *fdset32 var timeout posix.Timespec u.StrucAt(args[1]).Unpack(&readSet) u.StrucAt(args[2]).Unpack(&writeSet) u.StrucAt(args[3]).Unpack(&timeout) readyFds := args[4] readNative := readSet.Native() writeNative := writeSet.Native() n, err := cgcNativeSelect(nfds, readNative, writeNative, &timeout) if err != nil { ret = UINT32_MAX // FIXME? } else { numReady := int32(n) if readyFds != 0 { u.StrucAt(readyFds).Pack(numReady) } } case 7: // random tmp := make([]byte, args[1]) rand.Read(tmp) u.MemWrite(args[0], tmp) writeAddr(u, args[2], args[1]) } u.RegWrite(uc.X86_REG_EAX, ret) }