Golang实现沙箱识别

Golang实现沙箱识别

在线沙箱通过记录程序运行情况进行判定,下面介绍一些小技巧来检测程序是否在沙箱里运行。

1.延迟运行

在各类检测沙箱中,检测运行的时间往往是比较短的,因为其没有过多资源可以供程序长时间运行,所以我们可以延迟等待一会儿后再进行真实的操作。

func timeSleep() (int, error) {
	startTime := time.Now()
	time.Sleep(10 * time.Second)
	endTime := time.Now()
	sleepTime := endTime.Sub(startTime)
	if sleepTime >= time.Duration(10*time.Second) {
		fmt.Println("睡眠时间为:", sleepTime)
		return 1, nil
	} else {
		return 0, nil
	}
}

2.检测开机时间

许多沙箱检测完毕后会重置系统,我们可以检测开机时间来判断是否为真实的运行状况。

func bootTime() (int, error) {
	var kernel = syscall.NewLazyDLL("Kernel32.dll")
	GetTickCount := kernel.NewProc("GetTickCount")
	r, _, _ := GetTickCount.Call()
	if r == 0 {
		return 0, nil
	}
	ms := time.Duration(r * 1000 * 1000)
	fmt.Println("开机时常为:", ms)
	tm := time.Duration(30 * time.Minute)
	if ms < tm {
		return 0, nil
	} else {
		return 1, nil
	}

}

3.检测物理内存

当今大多数pc具有4GB以上的RAM,我们可以检测RAM是否大于4GB来判断是否是真实的运行机器。

func physicalMemory() (int, error) {
	var mod = syscall.NewLazyDLL("kernel32.dll")
	var proc = mod.NewProc("GetPhysicallyInstalledSystemMemory")
	var mem uint64
	proc.Call(uintptr(unsafe.Pointer(&mem))) // ret, _, err := proc.Call(uintptr(unsafe.Pointer(&mem)))
	mem = mem / 1048576                      
	if mem < 4 {
		fmt.Printf("物理内存为%dG\n", mem)
		return 0, nil // 小于4GB返回0
	}
	fmt.Printf("物理内存为%dG\n", mem)
	return 1, nil // 大于4GB返回1
}

该值以千字节为单位给出,因此除以 1048576 (1024*1024) 以获得以千兆字节为单位的值。

4.检测CPU核心数

大多数pc拥有4核心cpu,许多在线检测的虚拟机沙盘是2核心,我们可以通过核心数来判断是否为真实机器或检测用的虚拟沙箱。

func numberOfCPU() (int, error) {
	a := runtime.NumCPU()
	fmt.Println("CPU核心数为:", a)
	if a < 4 {
		return 0, nil // 小于4核心数,返回0
	} else {
		return 1, nil // 大于4核心数,返回1
	}
}

5.检测临时文件数

正常使用的系统,其中用户的临时文件夹中有一定数量的临时文件,可以通过判断临时文件夹内的文件数量来检测是否在沙箱中运行。

func numberOfTempFiles() (int, error) {
	conn := os.Getenv("temp") // 通过环境变量读取temp文件夹路径
	var k int
	if conn == "" {
		fmt.Println("未找到temp文件夹,或temp文件夹不存在")
		return 0, nil
	} else {
		local_dir := conn
		err := filepath.Walk(local_dir, func(filename string, fi os.FileInfo, err error) error {
			if fi.IsDir() {
				return nil
			}
			k++
			// fmt.Println("filename:", filename)  // 输出文件名字
			return nil
		})
		fmt.Println("Temp总共文件数量:", k)
		if err != nil {
			// fmt.Println("路径获取错误")
			return 0, nil
		}
	}
	if k < 30 {
		return 0, nil
	}
	return 1, nil

}

全部代码:

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"syscall"
	"time"
	"unsafe"
)

func See_through() {
	// 1. 延时运行
	timeSleep1, _ := timeSleep()
	// 2. 检测开机时间
	bootTime1, _ := bootTime()
	// 3. 检测物理内存
	physicalMemory1, _ := physicalMemory()
	// 4. 检测CPU核心数
	numberOfCPU1, _ := numberOfCPU()
	// 5. 检测临时文件数
	numberOfTempFiles1, _ := numberOfTempFiles()
	level := timeSleep1 + bootTime1 + physicalMemory1 + numberOfCPU1 + numberOfTempFiles1 // 有五个等级,等级越趋向于5,越像真机
	fmt.Println("level:", level)
	if level < 4 {
		fmt.Println("可能是沙箱!")
	} else {
		fmt.Println("可能是真机!")
	}
}

// 1. 延时运行
func timeSleep() (int, error) {
	startTime := time.Now()
	time.Sleep(10 * time.Second)
	endTime := time.Now()
	sleepTime := endTime.Sub(startTime)
	if sleepTime >= time.Duration(10*time.Second) {
		fmt.Println("睡眠时间为:", sleepTime)
		return 1, nil
	} else {
		return 0, nil
	}
}

// 2. 检测开机时间
// 许多沙箱检测完毕后会重置系统,我们可以检测开机时间来判断是否为真实的运行状况。
func bootTime() (int, error) {
	var kernel = syscall.NewLazyDLL("Kernel32.dll")
	GetTickCount := kernel.NewProc("GetTickCount")
	r, _, _ := GetTickCount.Call()
	if r == 0 {
		return 0, nil
	}
	ms := time.Duration(r * 1000 * 1000)
	fmt.Println("开机时常为:", ms)
	tm := time.Duration(30 * time.Minute)
	if ms < tm {
		return 0, nil
	} else {
		return 1, nil
	}

}

// 3. 检测物理内存
// 当今大多数pc具有4GB以上的RAM,我们可以检测RAM是否大于4GB来判断是否是真实的运行机器。
func physicalMemory() (int, error) {
	var mod = syscall.NewLazyDLL("kernel32.dll")
	var proc = mod.NewProc("GetPhysicallyInstalledSystemMemory")
	var mem uint64
	proc.Call(uintptr(unsafe.Pointer(&mem))) // ret, _, err := proc.Call(uintptr(unsafe.Pointer(&mem)))
	mem = mem / 1048576                      // 该值以千字节为单位给出,因此除以 1048576 (1024*1024) 以获得以千兆字节为单位的值。
	if mem < 4 {
		fmt.Printf("物理内存为%dG\n", mem)
		return 0, nil // 小于4GB返回0
	}
	fmt.Printf("物理内存为%dG\n", mem)
	return 1, nil // 大于4GB返回1
}

// 4. 检测CPU核心数
// 大多数pc拥有4核心cpu,许多在线检测的虚拟机沙盘是2核心,我们可以通过核心数来判断是否为真实机器或检测用的虚拟沙箱。
func numberOfCPU() (int, error) {
	a := runtime.NumCPU()
	fmt.Println("CPU核心数为:", a)
	if a < 4 {
		return 0, nil // 小于4核心数,返回0
	} else {
		return 1, nil // 大于4核心数,返回1
	}
}

// 5. 检测临时文件数
// 正常使用的系统,其中用户的临时文件夹中有一定数量的临时文件,可以通过判断临时文件夹内的文件数量来检测是否在沙箱中运行。
func numberOfTempFiles() (int, error) {
	conn := os.Getenv("temp") // 通过环境变量读取temp文件夹路径
	var k int
	if conn == "" {
		fmt.Println("未找到temp文件夹,或temp文件夹不存在")
		return 0, nil
	} else {
		local_dir := conn
		err := filepath.Walk(local_dir, func(filename string, fi os.FileInfo, err error) error {
			if fi.IsDir() {
				return nil
			}
			k++
			// fmt.Println("filename:", filename)  // 输出文件名字
			return nil
		})
		fmt.Println("Temp总共文件数量:", k)
		if err != nil {
			// fmt.Println("路径获取错误")
			return 0, nil
		}
	}
	if k < 30 {
		return 0, nil
	}
	return 1, nil

}

func main() {
	See_through()
}

总结

当前有部分检测沙箱使用了Intel Processor Tracing技术,可以高效追踪程序的分支,在实际使用过程中,需要对if分支进行一定程度的代码混淆,防止分支模拟技术。并且现代检测沙箱正在不断提高拟真度,单独使用几个判断方法可能无法得出正确的判断,要多种方法结合使用,才能发挥出良好的效果。

参考:

https://www.freebuf.com/articles/system/202717.html

上一篇:js点击出现二级菜单,点击二级菜单主菜单换成二级菜单


下一篇:golang 下载和上传,处理多文件上传