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

参考