前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >规避检测(共五章):第五章

规避检测(共五章):第五章

作者头像
Creaper
发布2023-11-20 12:50:14
2450
发布2023-11-20 12:50:14
举报
文章被收录于专栏:锦鲤安全锦鲤安全

一、基于时间的沙盒规避技术

沙盒模拟通常持续很短的时间,因为沙盒加载了数千个样本。仿真 时间很少超过3-5分钟。因此,恶意软件可以利用这一事实来避免检测:它可能会执行 在开始任何恶意活动之前长时间延迟。

为了抵消这种情况,沙盒可以实现操纵时间和执行延迟的功能。沙箱具有睡眠跳过功能,可将延迟替换为非常短的值。这应该强制恶意软件启动 它在分析超时之前的恶意活动。

但是,这也可用于检测沙盒。

一些指令和API函数的执行时间也存在一些差异, 可用于检测虚拟环境。

1.延迟执行

执行延迟用于避免在模拟期间检测到恶意活动。

1.1简单的延迟操作

代码语言:javascript
复制
int iResult;
DWORD timeout = delay;
DWORD OK = TRUE;

SOCKADDR_IN sa = { 0 };
SOCKET sock = INVALID_SOCKET;


do {
    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr("8.8.8.8");    
    sa.sin_port = htons(80);

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        OK = FALSE;
        break;
    }

    // setting socket timeout
    unsigned long iMode = 1;
    iResult = ioctlsocket(sock, FIONBIO, &iMode);

    iResult = connect(sock, (SOCKADDR*)&sa, sizeof(sa));
    if (iResult == false) {
        OK = FALSE;
        break;
    }

    iMode = 0;
    iResult = ioctlsocket(sock, FIONBIO, &iMode);
    if (iResult != NO_ERROR) {
        OK = FALSE;
        break;
    }

    // fd set data
    fd_set Write, Err;
    FD_ZERO(&Write);
    FD_ZERO(&Err);
    FD_SET(sock, &Write);
    FD_SET(sock, &Err);
    timeval tv = { 0 };
    tv.tv_usec = timeout * 1000;

    // 检查套接字是否准备就绪,此调用应占用超时毫秒
    select(0, NULL, &Write, &Err, &tv);
    
    if (FD_ISSET(sock, &Err)) {
        OK = FALSE;
        break;
    }

} while (false);

if (sock != INVALID_SOCKET)
    closesocket(sock);
代码语言:javascript
复制
VOID CALLBACK TimerFunction(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
    bProcessed = TRUE;
}

VOID timing_timeSetEvent(UINT delayInSeconds)
{
    
    UINT uResolution;
    TIMECAPS tc;
    MMRESULT idEvent;

   
    timeGetDevCaps(&tc, sizeof(TIMECAPS));
    uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);

    
    idEvent = timeSetEvent(
        delayInSeconds,
        uResolution,
        TimerFunction,
        0,
        TIME_ONESHOT);

    while (!bProcessed){
        
        Sleep(0);
    }

    
    timeKillEvent(idEvent);

    
    timeEndPeriod(uResolution);
}

1.2 使用任务调度程序延迟执行

此方法既可用于延迟执行,也可用于逃避沙盒跟踪:

代码语言:javascript
复制
$tm = (get-date).AddMinutes(10).ToString("HH:mm")
$action = New-ScheduledTaskAction -Execute "some_malicious_app.exe"
$trigger = New-ScheduledTaskTrigger -Once -At $tm
Register-ScheduledTask TaskName -Action $action -Trigger $trigger

1.3 仅在特定日期运行

恶意软件样本可能会检查当前日期,并仅在特定日期执行恶意操作。例如 这种技术被用于Sazoora恶意软件, 检查当前日期并验证该日期是 16 日、17 日还是 18 日 给定月份。

2.睡眠跳过检测

这种类型的技术通常针对监视器睡眠跳过功能和其他时间操纵 可在沙盒中使用的技术,以跳过恶意软件执行的长时间延迟。

2.1 使用不同方法的并行延迟

这些技术背后的想法是并行执行不同类型的延迟并测量经过的时间。

代码语言:javascript
复制
DWORD StartingTick, TimeElapsedMs;
LARGE_INTEGER DueTime;
HANDLE hTimer = NULL;
TIMER_BASIC_INFORMATION TimerInformation;
ULONG ReturnLength;

hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
DueTime.QuadPart = Timeout * (-10000LL);

StartingTick = GetTickCount();
SetWaitableTimer(hTimer, &DueTime, 0, NULL, NULL, 0);
do
{
    Sleep(Timeout/10);
    NtQueryTimer(hTimer, TimerBasicInformation, &TimerInformation, sizeof(TIMER_BASIC_INFORMATION), &ReturnLength);
} while (!TimerInformation.TimerState);

CloseHandle(hTimer);

TimeElapsedMs = GetTickCount() - StartingTick;
printf("Requested delay: %d, elapsed time: %d\n", Timeout, TimeElapsedMs);

if (abs((LONG)(TimeElapsedMs - Timeout)) > Timeout / 2)
    printf("Sleep-skipping DETECTED!\n");

2.2 使用不同的方法测量时间间隔

我们需要执行将在沙盒中跳过的延迟,并使用不同的方法测量经过的时间。 而 Cuckoo 监视器则钩住了 GetTickCount()、GetLocalTime()、GetSystemTime() 和 让他们返回跳过的时间,我们仍然可以找到没有处理的时间测量方法监控:

代码语言:javascript
复制
LARGE_INTEGER StartingTime, EndingTime;
LARGE_INTEGER Frequency;
DWORD TimeElapsedMs;

QueryPerformanceFrequency(&Frequency);
QueryPerformanceCounter(&StartingTime);

Sleep(Timeout);

QueryPerformanceCounter(&EndingTime);
TimeElapsedMs = (DWORD)(1000ll * (EndingTime.QuadPart - StartingTime.QuadPart) / Frequency.QuadPart);

printf("Requested delay: %d, elapsed time: %d\n", Timeout, TimeElapsedMs);

if (abs((LONG)(TimeElapsedMs - Timeout)) > Timeout / 2)
    printf("Sleep-skipping DETECTED!\n");
代码语言:javascript
复制
ULONGLONG tick;
DWORD TimeElapsedMs;

tick = GetTickCount64();
Sleep(Timeout);
TimeElapsedMs = GetTickCount64() - tick;

printf("Requested delay: %d, elapsed time: %d\n", Timeout, TimeElapsedMs);

if (abs((LONG)(TimeElapsedMs - Timeout)) > Timeout / 2)
    printf("Sleep-skipping DETECTED!\n");

我们还可以使用我们自己的GetTickCount实现来检测睡眠跳过。在下一个代码示例中,我们将直接从 KUSER_SHARED_DATA 结构获取即时报价计数。这样,即使 GetTickCount()函数被挂接,我们也可以获得原始的即时报价计数值:

代码语言:javascript
复制
#define KI_USER_SHARED_DATA         0x7FFE0000
#define SharedUserData  ((KUSER_SHARED_DATA * const) KI_USER_SHARED_DATA)
#define MyGetTickCount() ((DWORD)((SharedUserData->TickCountMultiplier * (ULONGLONG)SharedUserData->TickCount.LowPart) >> 24))

// ...
StartingTick = MyGetTickCount();
Sleep(Timeout);
TimeElapsedMs = MyGetTickCount() - StartingTick;

printf("Requested delay: %d, elapsed time: %d\n", Timeout, TimeElapsedMs);

if (abs((LONG)(TimeElapsedMs - Timeout)) > Timeout / 2)
    printf("Sleep-skipping DETECTED!\n");

2.3 使用不同的方法获取系统时间

此方法与前一种方法类似。我们尝试获取当前系统,而不是测量间隔,使用不同方法的时间:

代码语言:javascript
复制
SYSTEM_TIME_OF_DAY_INFORMATION  SysTimeInfo;
ULONGLONG time;
LONGLONG diff;

Sleep(60000);
GetSystemTimeAsFileTime((LPFILETIME)&time);

NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0);
diff = time - SysTimeInfo.CurrentTime.QuadPart;
if (abs(diff) > 10000000)
    printf("Sleep-skipping DETECTED!\n);

2.4 调用延时函数后检查延时值是否发生变化

睡眠跳过通常以较小的间隔替换延迟值来实现。 让我们看一下 NtDelayExecution 函数。延迟值使用指针传递给此函数:

代码语言:javascript
复制
NTSYSAPI NTSTATUS NTAPI
NtDelayExecution(
    IN BOOLEAN              Alertable,
    IN PLARGE_INTEGER       DelayInterval );

因此,我们可以检查函数执行后延迟间隔的值是否发生变化。 如果该值与初始值不同,则跳过延迟。

代码语言:javascript
复制
LONGLONG SavedTimeout = Timeout * (-10000LL);
DelayInterval->QuadPart = SavedTimeout;
status = NtDelayExecution(TRUE, DelayInterval);
if (DelayInterval->QuadPart != SavedTimeout)
    printf("Sleep-skipping DETECTED!\n");

2.5 使用绝对超时

对于执行延迟的 Nt-函数,我们可以使用相对延迟间隔或绝对超时时间。延迟间隔的负值表示相对超时,正值表示绝对超时。高级 API 函数(如 WaitForSingleObject()或 Sleep())以相对间隔运行。因此,沙盒开发人员可能不关心绝对超时并错误地处理它们。在沙盒中,这种延迟被跳过,但跳过的时间和刻度被错误地计算。这可以使用检测睡眠跳过。

代码语言:javascript
复制
void SleepAbs(DWORD ms)
{
    LARGE_INTEGER SleepUntil;

    GetSystemTimeAsFileTime((LPFILETIME)&SleepUntil);
    SleepTo.QuadPart += (ms * 10000);
    NtDelayExecution(TRUE, &SleepTo);
}

2.6 从另一个进程中获取时间

沙盒中的睡眠跳过不是系统范围的。因此,如果存在执行延迟,时间就会移动 在不同的过程中具有不同的速度。延迟后,我们应该同步进程并进行比较 两个进程中的当前时间。测量时间值的巨大差异表明进行了睡眠跳过。

3.虚拟机和主机中的时间测量差异

某些 API 函数和指令的执行在 VM 和通常的 主机系统。这些特性可用于检测虚拟环境。

3.1 RDTSC(使用 CPUID 强制虚拟机退出)

代码语言:javascript
复制
BOOL rdtsc_diff_vmexit()
{
    ULONGLONG tsc1 = 0;
    ULONGLONG tsc2 = 0;
    ULONGLONG avg = 0;
    INT cpuInfo[4] = {};

    //浅试10秒
    for (INT i = 0; i < 10; i++)
    {
        tsc1 = __rdtsc();
        __cpuid(cpuInfo, 0);
        tsc2 = __rdtsc();

        // Get the delta of the two RDTSC
        avg += (tsc2 - tsc1);
    }

    //我们重复了这个过程10次,以确保我们的检查尽可能可靠
    avg = avg / 10;
    return (avg < 1000 && avg > 0) ? FALSE : TRUE;
}

3.2 RDTSC(带有 GetProcessHeap 和 CloseHandle 的锁定版本)

代码语言:javascript
复制
#define LODWORD(_qw)    ((DWORD)(_qw))
BOOL rdtsc_diff_locky()
{
    ULONGLONG tsc1;
    ULONGLONG tsc2;
    ULONGLONG tsc3;
    DWORD i = 0;

   
    for (i = 0; i < 10; i++)
    {
        tsc1 = __rdtsc();

        
        GetProcessHeap();

        tsc2 = __rdtsc();

        
        CloseHandle(0);

        tsc3 = __rdtsc();

    
        if ((LODWORD(tsc3) - LODWORD(tsc2)) / (LODWORD(tsc2) - LODWORD(tsc1)) >= 10)
            return FALSE;
    }

    
    return TRUE;
}

4.使用不同的方法检查系统上次启动时间

此技术是通用操作系统查询:检查系统正常运行时间是否短和 WMI:检查上次启动时间部分中所述的技术的组合。根据用于获取系统上次启动时间的方法,测量的沙盒操作系统正常运行时间也可能 小(几分钟),或者相反,太大(几个月甚至几年),因为系统通常会恢复 从分析开始后的快照。

我们可以通过比较上次启动时间的两个值来检测沙箱,这两个值是通过 WMI 和 NtQuerySystemInformation(SystemTimeOfDayInformation 获取的:

代码语言:javascript
复制
bool check_last_boot_time()
{
    SYSTEM_TIME_OF_DAY_INFORMATION  SysTimeInfo;
    LARGE_INTEGER LastBootTime;
    
    NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0);
    LastBootTime = wmi_Get_LastBootTime();
    return (wmi_LastBootTime.QuadPart - SysTimeInfo.BootTime.QuadPart) / 10000000 != 0; // 0 seconds
}

5.使用无效参数调用可能挂钩的延迟函数

NtDelayExecution 函数的第二个参数是指向延迟间隔值的指针。在内核模式下, NtDelayExecution 函数验证此指针,还可以返回以下值:

  • STATUS_ACCESS_VIOLATION - 如果该值不是有效的用户模式地址
  • STATUS_DATATYPE_MISALIGNMENT - 如果地址未对齐(DelayInterval & 3 != 0)

在沙盒中,可能无法正确处理 NtDelayExecution 和类似函数的输入参数。如果我们使用 DelayInterval 的未对齐指针调用 NtDelayExecution,通常它会返回STATUS_DATATYPE_MISALIGNMENT。但是,在沙盒中,延迟间隔的值可能会复制到新变量,没有适当的检查。在这种情况下,将执行延迟,返回值将被STATUS_SUCCESS。这可用于检测沙盒。

代码语言:javascript
复制
__declspec(align(4)) BYTE aligned_bytes[sizeof(LARGE_INTEGER) * 2];
DWORD tick_start, time_elapsed_ms;
DWORD Timeout = 10000; //10 seconds
PLARGE_INTEGER DelayInterval = (PLARGE_INTEGER)(aligned_bytes + 1); //unaligned
NTSTATUS status;

DelayInterval->QuadPart = Timeout * (-10000LL);
tick_start = GetTickCount();
status = NtDelayExecution(FALSE, DelayInterval);
time_elapsed_ms = GetTickCount() - tick_start;
// 如果指针未对齐,则不应执行延迟
if (time_elapsed_ms > 500 || status != STATUS_DATATYPE_MISALIGNMENT )
    printf("Sandbox detected\n");

另一方面,如果为延迟间隔设置了无法访问的地址,则应STATUS_ACCESS_VIOLATION返回代码。这也可用于检测沙盒。

代码语言:javascript
复制
if (NtDelayExecution(FALSE, (PLARGE_INTEGER)0) != STATUS_ACCESS_VIOLATION)
    printf("Sandbox detected");

二、WMI 检测方法

Windows 管理界面 (WMI) 查询是获取操作系统和硬件信息的另一种方法。WMI 使用 COM 接口及其方法。

标准 COM 函数用于处理查询。它们按下面描述的顺序调用,可以分为 6 个步骤。

1. COM初始化:

  • CoInitialize/CoInitializeEx

2. 创建所需的接口实例:

  • CoCreateInstance/CoCreateInstanceEx

3. 通过具有以下功能的接口实例连接到特定服务:

  • ConnectServer

4. 获取服务的方法并使用以下函数设置它们的参数:

  • Method (获取方法)
  • Put (设置参数)

5. 从服务中检索信息,并使用以下功能执行服务的方法。左边的函数是右边函数的代理 - 在内部调用:

  • ExecQuery -> IWbemServices_ExecQuery (检索信息)
  • ExecMethod -> IWbemServices_ExecMethod (执行方法)

ExecMethodAsync -> IWbemServices_ExecMethodAsync (execute method)

6. 使用以下函数检查查询结果:

  • [enumerator]->Next
  • [object]->Get

1.通用 WMI 查询

由于 WMI 提供了另一种收集系统信息的方法,因此它可用于执行其他文章中描述的规避技术:

BOOL number_cores_wmi() { IWbemServices *pSvc = NULL; IWbemLocator *pLoc = NULL; IEnumWbemClassObject *pEnumerator = NULL; BOOL bStatus = FALSE; HRESULT hRes; BOOL bFound = FALSE; // Init WMI bStatus = InitWMI(&pSvc, &pLoc); if (bStatus) { // 如果成功,则执行所需的查询 bStatus = ExecWMIQuery(&pSvc, &pLoc, &pEnumerator, _T("SELECT * FROM Win32_Processor")); if (bStatus) { // 从查询中获取数据 IWbemClassObject *pclsObj = NULL; ULONG uReturn = 0; VARIANT vtProp; // 迭代我们的枚举器 while (pEnumerator) { hRes = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) break; // 获取 Name 属性的值 hRes = pclsObj->Get(_T("NumberOfCores"), 0, &vtProp, 0, 0); if (V_VT(&vtProp) != VT_NULL) { // 做我们的比较 if (vtProp.uintVal < 2) { bFound = TRUE; break; } // 释放当前结果对象 VariantClear(&vtProp); pclsObj->Release(); } } // Cleanup pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); } } return bFound; } BOOL disk_size_wmi() { IWbemServices *pSvc = NULL; IWbemLocator *pLoc = NULL; IEnumWbemClassObject *pEnumerator = NULL; BOOL bStatus = FALSE; HRESULT hRes; BOOL bFound = FALSE; INT64 minHardDiskSize = (80LL * (1024LL * (1024LL * (1024LL)))); // Init WMI bStatus = InitWMI(&pSvc, &pLoc); if (bStatus) { // 如果成功,则执行所需的查询 bStatus = ExecWMIQuery(&pSvc, &pLoc, &pEnumerator, _T("SELECT * FROM Win32_LogicalDisk")); if (bStatus) { // Get the data from the query IWbemClassObject *pclsObj = NULL; ULONG uReturn = 0; VARIANT vtProp; // 迭代我们的枚举器 while (pEnumerator) { hRes = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) break; // 获取 Name 属性的值 hRes = pclsObj->Get(_T("Size"), 0, &vtProp, 0, 0); if (V_VT(&vtProp) != VT_NULL) { if (vtProp.llVal < minHardDiskSize) { // Less than 80GB bFound = TRUE; break; } VariantClear(&vtProp); pclsObj->Release(); } } // Cleanup pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); } } return bFound; }

2. 使用 WMI 从跟踪中转义

WMI 提供了一种创建新进程和计划任务的方法。沙盒通常使用 CreateProcessInternalW 函数挂钩来跟踪子进程。但是,当您使用 WMI 创建进程时,函数 CreateProcessInternalW 不会在父进程中调用。因此,沙盒可能不会跟踪使用 WMI 创建的进程,并且不会记录其行为。

2.1 使用 WMI 启动进程

可以使用带“Create” 方法的“Win32_Process” 类使用 WMI 创建新进程:

代码语言:javascript
复制
CoInitializeEx(NULL, COINIT_MULTITHREADED);

// 设置常规 COM 安全级别
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(hres) && hres != RPC_E_TOO_LATE)
    break;

// 创建 WbemLocator 的实例
CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbemLocator);
wbemLocator->ConnectServer(CComBSTR("ROOT\\CIMV2"), NULL, NULL, NULL, 0, NULL, NULL, &wbemServices);

// 获取对象Win32_Process
wbemServices->GetObject(CComBSTR("Win32_Process"), 0, NULL, &oWin32Process, &callResult);
wbemServices->GetObject(CComBSTR("Win32_ProcessStartup"), 0, NULL, &oWin32ProcessStartup, &callResult);
oWin32Process->GetMethod(CComBSTR("Create"), 0, &oMethCreate, &oMethCreateSignature);
oMethCreate->SpawnInstance(0, &instWin32Process);
oWin32ProcessStartup->SpawnInstance(0, &instWin32ProcessStartup);
// 设置进程的启动信息
instWin32ProcessStartup->Put(CComBSTR("CreateFlags"), 0, &varCreateFlags, 0);
instWin32Process->Put(CComBSTR("CommandLine"), 0, &varCmdLine, 0);
instWin32Process->Put(CComBSTR("CurrentDirectory"), 0, &varCurDir, 0);
CComVariant varStartupInfo(instWin32ProcessStartup);
instWin32Process->Put(CComBSTR("ProcessStartupInformation"), 0, &varStartupInfo, 0);
wbemServices->ExecMethod(CComBSTR("Win32_Process"), CComBSTR("Create"), 0, NULL, instWin32Process, &pOutParams, &callResult);

2.2 通过 WMI 使用任务计划程序启动进程 (Windows 7)

该技术与“时间”中“使用任务计划程序延迟执行”一节中所述的基本上相同。WMI 只是提供了另一种计划任务的方法。

可以使用带有“Create”方法的“Win32_ScheduledJob”类使用 WMI 创建新任务。

但是,“Win32_ScheduledJob” WMI 类旨在与 AT 命令一起使用,该命令自 Windows 8 起已弃用。

在 Windows 8 及更高版本中,仅当注册表项“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\Configuration”具有类型为 REG_DWORD 的值“EnableAt”=“1”时,才能使用 WMI 创建计划作业。因此,这种技术不太可能在野外找到。

代码语言:javascript
复制
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=Impersonate}!\\" & strComputer & "\root\cimv2")
Set objSWbemDateTime = CreateObject("WbemScripting.SWbemDateTime")
objSWbemDateTime.SetVarDate(DateAdd("n", 1, Now()))
Set objNewJob = objWMIService.Get("Win32_ScheduledJob")
errJobCreate = objNewJob.Create("malware.exe", objSWbemDateTime.Value, False, , , True, "MaliciousJob")

3.检查上次启动时间

如果在从快照还原 VM 后立即查询上次启动时间,则 WMI 数据库可能包含创建 VM 快照时保存的值。如果快照是在一年前创建的,则即使沙盒更新了上次启动时间,计算出的系统正常运行时间也将是一年。

此事实可用于检测从快照还原的虚拟机。此外,上次启动时间中的任何异常都可以用作沙盒指示器:

  • 系统正常运行时间过长(数月甚至数年)
  • 系统正常运行时间很短(不到几分钟)
  • 使用其他方法获取的上次启动时间与使用 WMI 获取的上次启动时间不同
代码语言:javascript
复制
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")
 
For Each objOS in colOperatingSystems
    dtmBootup = objOS.LastBootUpTime
    dtmLastBootUpTime = WMIDateStringToDate(dtmBootup)
    dtmSystemUptime = DateDiff("n", dtmLastBootUpTime, Now)
    Wscript.Echo "System uptime minutes: " & dtmSystemUptime
Next
 
Function WMIDateStringToDate(dtm)
    WMIDateStringToDate =  CDate(Mid(dtm, 5, 2) & "/" & _
        Mid(dtm, 7, 2) & "/" & Left(dtm, 4) & " " & Mid (dtm, 9, 2) & ":" & _
        Mid(dtm, 11, 2) & ":" & Mid(dtm, 13, 2))
End Function

4.检查网络适配器上次重置时间

我们需要检查是否有任何适配器是很久以前最后一次重置的。这可能表示应用程序正在从快照还原的虚拟机中运行:

代码语言:javascript
复制
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_NetworkAdapter")
 
For Each objOS in colNetworkAdapters
    dtmLastReset = objOS.TimeOfLastReset
    dtmLastResetTime = WMIDateStringToDate(dtmLastReset)  'WMIDateStringToDate function from the previous example
    dtmAdapterUptime = DateDiff("n", dtmLastResetTime, Now)
    Wscript.Echo "Adapter uptime minutes: " & dtmAdapterUptime
Next

锦鲤安全

一个安全技术学习与工具分享平台

点分享

点收藏

点点赞

点在看

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 锦鲤安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、基于时间的沙盒规避技术
  • 1.延迟执行
    • 1.1简单的延迟操作
    • 2.睡眠跳过检测
      • 2.1 使用不同方法的并行延迟
      • 3.虚拟机和主机中的时间测量差异
        • 3.1 RDTSC(使用 CPUID 强制虚拟机退出)
          • 二、WMI 检测方法
          • 1.通用 WMI 查询
          • 2. 使用 WMI 从跟踪中转义
            • 2.1 使用 WMI 启动进程
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档