Подпишитесь на наш Telegram-канал, чтобы всегда быть в курсе важных обновлений! Перейти

Вопрос Guys what is the best way to create ur own loader

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
172
Реакции
5
what is the best way to create ur load i made it with load library and some1 told me that load library is not good or secured he suggested to make it using manual mapping

but when i made it with manual mapping now i have issue loading libprotobuf.lib to combile the protobuf messages using protobuf

so please tell me what do u really think
here is how iam using my manual mapper
C++:
Expand Collapse Copy
DWORD GetProcessIdByName(const std::wstring& processName) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    PROCESSENTRY32W pe32;
    pe32.dwSize = sizeof(pe32);

    if (!Process32FirstW(snapshot, &pe32)) {
        CloseHandle(snapshot);
        return 0;
    }

    do {
        if (_wcsicmp(pe32.szExeFile, processName.c_str()) == 0) {
            CloseHandle(snapshot);
            return pe32.th32ProcessID;
        }
    } while (Process32NextW(snapshot, &pe32));

    CloseHandle(snapshot);
    return 0;
}

std::string GetDllPath() {
    // Get the directory where the injector is located
    char exePath[MAX_PATH];
    GetModuleFileNameA(nullptr, exePath, MAX_PATH);
 
    std::filesystem::path injectorPath(exePath);
    std::filesystem::path dllPath = injectorPath.parent_path() / "BetterDota.dll";
 
    return dllPath.string();
}

// Get the Dota 2 game directory from the running process
std::string GetGameDirectory(DWORD processId) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId);
    if (!hProcess) return "";
 
    char exePath[MAX_PATH];
    DWORD size = MAX_PATH;
    if (!QueryFullProcessImageNameA(hProcess, 0, exePath, &size)) {
        CloseHandle(hProcess);
        return "";
    }
    CloseHandle(hProcess);
 
    std::filesystem::path gamePath(exePath);
    return gamePath.parent_path().string();
}

// Copy dependency DLLs to game directory for manual mapping
bool CopyDependencies(const std::string& injectorDir, const std::string& gameDir) {
    std::vector<std::string> dependencies = { "sentry.dll" };
 
    for (const auto& dll : dependencies) {
        std::filesystem::path srcPath = std::filesystem::path(injectorDir) / dll;
        std::filesystem::path dstPath = std::filesystem::path(gameDir) / dll;
    
        if (std::filesystem::exists(srcPath)) {
            try {
                // Only copy if it doesn't exist or is different
                if (!std::filesystem::exists(dstPath)) {
                    std::filesystem::copy_file(srcPath, dstPath);
                    std::cout << COLOR_GREEN << "[+] Copied " << dll << " to game directory\n" << COLOR_RESET;
                }
            } catch (const std::exception& e) {
                std::cout << COLOR_YELLOW << "[!] Warning: Could not copy " << dll << ": " << e.what() << "\n" << COLOR_RESET;
            }
        }
    }
    return true;
}

int main() {
    EnableColors();
    PrintBanner();

    // Find DLL path
    std::string dllPath = GetDllPath();
 
    if (!std::filesystem::exists(dllPath)) {
        std::cout << COLOR_RED << "[!] DLL not found: " << dllPath << "\n" << COLOR_RESET;
        std::cout << COLOR_YELLOW << "[*] Make sure BetterDota.dll is in the same folder as this injector\n" << COLOR_RESET;
        std::cout << "\nPress Enter to exit...";
        std::cin.get();
        return 1;
    }

    std::cout << COLOR_CYAN << "[*] DLL Path: " << dllPath << "\n" << COLOR_RESET;
    std::cout << COLOR_YELLOW << "[*] Waiting for dota2.exe...\n" << COLOR_RESET;

    // Wait for Dota 2 process
    DWORD processId = 0;
    while (processId == 0) {
        processId = GetProcessIdByName(L"dota2.exe");
        if (processId == 0) {
            Sleep(1000);
            std::cout << ".";
        }
    }

    std::cout << "\n" << COLOR_GREEN << "[+] Found dota2.exe (PID: " << processId << ")\n" << COLOR_RESET;
 
    // Copy dependencies to game directory
    std::string gameDir = GetGameDirectory(processId);
    if (!gameDir.empty()) {
        std::filesystem::path injectorPath(dllPath);
        CopyDependencies(injectorPath.parent_path().string(), gameDir);
    
        // Set game directory for manual mapper to use full paths
        ManualMapper::SetGameDirectory(gameDir);
        std::cout << COLOR_CYAN << "[*] Game directory: " << gameDir << "\n" << COLOR_RESET;
    }
 
    // Wait a bit for game to initialize
    std::cout << COLOR_YELLOW << "[*] Waiting for game to initialize...\n" << COLOR_RESET;
    Sleep(5000);

    // Inject using Manual Mapping (no LoadLibrary!)
    std::cout << COLOR_CYAN << "[*] Manual mapping DLL...\n" << COLOR_RESET;
 
    if (ManualMapper::InjectDll(processId, dllPath)) {
        std::cout << COLOR_GREEN << "\n[+] Manual map injection successful!\n" << COLOR_RESET;
        std::cout << COLOR_GREEN << "[+] DLL is now hidden from module list!\n" << COLOR_RESET;
    } else {
        std::cout << COLOR_RED << "\n[!] Manual map injection failed!\n" << COLOR_RESET;
    }

    std::cout << "\nPress Enter to exit...";
    std::cin.get();
    return 0;
}





peb_loader.h:
Expand Collapse Copy
#pragma once
#include <cstdint>

extern "C" {
    uint64_t FindDllByName(const char* dllName);
    uint64_t FindApiByName(uint64_t dllBase, const char* apiName);
    uint32_t ApiHashing(const char* str);
    uint32_t DllHashing(const wchar_t* str);
    uint64_t GetLdr();
    uint64_t GetDllBase(uint64_t ldrEntry);
    uint64_t GetNextLdr(uint64_t ldrEntry);
    uint64_t GetDllBuffer(uint64_t ldrEntry);
    uint64_t FindDllByHash(uint32_t hash);
    uint64_t GetApiAddr(uint64_t dllBase, uint32_t hash);
}



manualmapper.h:
Expand Collapse Copy
 namespace ManualMapper {

    // Global: Game directory for loading dependencies with full path
    inline std::string g_gameDirectory;
 
    inline void SetGameDirectory(const std::string& dir) {
        g_gameDirectory = dir;
    }

    // Helper: Get module base address in target process
    inline UINT_PTR GetRemoteModuleBase(HANDLE hProcess, DWORD processId, const char* moduleName) {
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId);
        if (hSnap == INVALID_HANDLE_VALUE) {
            return 0;
        }

        MODULEENTRY32W me32;
        me32.dwSize = sizeof(me32);

        if (!Module32FirstW(hSnap, &me32)) {
            CloseHandle(hSnap);
            return 0;
        }

        // Convert module name to wide string for comparison
        wchar_t wideModName[256];
        MultiByteToWideChar(CP_ACP, 0, moduleName, -1, wideModName, 256);

        do {
            if (_wcsicmp(me32.szModule, wideModName) == 0) {
                CloseHandle(hSnap);
                return (UINT_PTR)me32.modBaseAddr;
            }
        } while (Module32NextW(hSnap, &me32));

        CloseHandle(hSnap);
        return 0;
    }

    // Helper: Get function address in target process by loading the DLL locally and calculating offset
    inline UINT_PTR GetRemoteProcAddress(HANDLE hProcess, DWORD processId, const char* moduleName, const char* funcName, WORD ordinal = 0) {
        // First, get the module base in the target process
        UINT_PTR remoteBase = GetRemoteModuleBase(hProcess, processId, moduleName);
     
        // If module not loaded in target, we need to inject LoadLibrary call first
        if (remoteBase == 0) {
            // Try loading it via LoadLibraryA in the target process
            HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
            FARPROC pLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA");
         
            // Build full path for non-system DLLs
            std::string loadPath = moduleName;
            if (!g_gameDirectory.empty() &&
                _stricmp(moduleName, "kernel32.dll") != 0 &&
                _stricmp(moduleName, "ntdll.dll") != 0 &&
                _stricmp(moduleName, "user32.dll") != 0 &&
                _stricmp(moduleName, "d3d11.dll") != 0 &&
                _stricmp(moduleName, "dxgi.dll") != 0) {
                // Check if it's a custom DLL that we need to load with full path
                std::string fullPath = g_gameDirectory + "\\" + moduleName;
                // Check if file exists at full path
                DWORD attrs = GetFileAttributesA(fullPath.c_str());
                if (attrs != INVALID_FILE_ATTRIBUTES) {
                    loadPath = fullPath;
                    std::cout << MM_CYAN << "[*] Using full path: " << loadPath << "\n" << MM_RESET;
                }
            }
         
            // Allocate memory for module path in target
            size_t nameLen = loadPath.length() + 1;
            LPVOID pRemoteName = VirtualAllocEx(hProcess, nullptr, nameLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
            if (!pRemoteName) return 0;
         
            WriteProcessMemory(hProcess, pRemoteName, loadPath.c_str(), nameLen, nullptr);
         
            // Create remote thread to load the library
            HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryA, pRemoteName, 0, nullptr);
            if (hThread) {
                WaitForSingleObject(hThread, 5000);
                CloseHandle(hThread);
            }
         
            VirtualFreeEx(hProcess, pRemoteName, 0, MEM_RELEASE);
         
            // Try again
            remoteBase = GetRemoteModuleBase(hProcess, processId, moduleName);
            if (remoteBase == 0) {
                std::cout << MM_RED << "[!] Could not load " << moduleName << " in target\n" << MM_RESET;
                return 0;
            }
            std::cout << MM_GREEN << "[+] Loaded " << moduleName << " in target at 0x" << std::hex << remoteBase << std::dec << "\n" << MM_RESET;
        }
     
        // Now load locally and calculate offset - also use full path
        std::string localLoadPath = moduleName;
        if (!g_gameDirectory.empty()) {
            std::string fullPath = g_gameDirectory + "\\" + moduleName;
            DWORD attrs = GetFileAttributesA(fullPath.c_str());
            if (attrs != INVALID_FILE_ATTRIBUTES) {
                localLoadPath = fullPath;
            }
        }
     
        HMODULE hLocal = GetModuleHandleA(moduleName);
        if (!hLocal) {
            hLocal = LoadLibraryA(localLoadPath.c_str());
        }
        if (!hLocal) {
            std::cout << MM_RED << "[!] Could not load " << moduleName << " locally\n" << MM_RESET;
            return 0;
        }
     
        FARPROC localAddr;
        if (ordinal != 0) {
            localAddr = GetProcAddress(hLocal, (LPCSTR)ordinal);
        } else {
            localAddr = GetProcAddress(hLocal, funcName);
        }
     
        if (!localAddr) {
            return 0;
        }
     
        // Calculate offset and apply to remote base
        UINT_PTR offset = (UINT_PTR)localAddr - (UINT_PTR)hLocal;
        return remoteBase + offset;
    }

    class Mapper {
    private:
        HANDLE m_hProcess = nullptr;
        DWORD m_processId = 0;

    public:
        Mapper(DWORD processId) : m_processId(processId) {}
        ~Mapper() { if (m_hProcess) CloseHandle(m_hProcess); }

        bool MapDll(const std::string& dllPath) {
            // Read DLL file
            std::ifstream file(dllPath, std::ios::binary | std::ios::ate);
            if (!file.is_open()) {
                std::cout << MM_RED << "[!] Failed to open DLL file: " << dllPath << MM_RESET << "\n";
                return false;
            }

            auto fileSize = file.tellg();
            file.seekg(0, std::ios::beg);

            std::vector<BYTE> fileData((size_t)fileSize);
            file.read((char*)fileData.data(), fileSize);
            file.close();

            std::cout << MM_GREEN << "[+] DLL loaded: " << fileSize << " bytes\n" << MM_RESET;

            return MapFromMemory(fileData.data(), fileData.size());
        }

        bool MapFromMemory(BYTE* pFileData, size_t fileSize) {
            // Validate PE
            auto* pDosHeader = (IMAGE_DOS_HEADER*)pFileData;
            if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
                std::cout << MM_RED << "[!] Invalid DOS signature\n" << MM_RESET;
                return false;
            }

            auto* pNtHeaders = (IMAGE_NT_HEADERS*)(pFileData + pDosHeader->e_lfanew);
            if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
                std::cout << MM_RED << "[!] Invalid NT signature\n" << MM_RESET;
                return false;
            }

            if (!(pNtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
                std::cout << MM_RED << "[!] Not a DLL\n" << MM_RESET;
                return false;
            }

            if (pNtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
                std::cout << MM_RED << "[!] Not a 64-bit DLL\n" << MM_RESET;
                return false;
            }

            std::cout << MM_GREEN << "[+] PE validated (x64 DLL)\n" << MM_RESET;

            // Open target process
            m_hProcess = OpenProcess(
                PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
                PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
                FALSE, m_processId
            );

            if (!m_hProcess) {
                std::cout << MM_RED << "[!] Failed to open process. Error: " << GetLastError() << MM_RESET << "\n";
                return false;
            }

            std::cout << MM_GREEN << "[+] Process opened\n" << MM_RESET;

            SIZE_T imageSize = pNtHeaders->OptionalHeader.SizeOfImage;

            // Allocate memory for the image
            LPVOID pRemoteImage = VirtualAllocEx(m_hProcess, nullptr, imageSize,
                MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

            if (!pRemoteImage) {
                std::cout << MM_RED << "[!] Failed to allocate image memory\n" << MM_RESET;
                return false;
            }

            std::cout << MM_GREEN << "[+] Image memory: 0x" << std::hex << (UINT_PTR)pRemoteImage << std::dec << "\n" << MM_RESET;

            // Prepare local image - copy headers and sections with proper layout
            std::vector<BYTE> localImage(imageSize, 0);

            // Copy headers
            memcpy(localImage.data(), pFileData, pNtHeaders->OptionalHeader.SizeOfHeaders);

            // Copy sections
            auto* pSection = IMAGE_FIRST_SECTION(pNtHeaders);
            for (WORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSection++) {
                if (pSection->SizeOfRawData > 0) {
                    memcpy(
                        localImage.data() + pSection->VirtualAddress,
                        pFileData + pSection->PointerToRawData,
                        min(pSection->SizeOfRawData, pSection->Misc.VirtualSize ? pSection->Misc.VirtualSize : pSection->SizeOfRawData)
                    );
                }
            }

            std::cout << MM_GREEN << "[+] Sections mapped\n" << MM_RESET;

            // ========================================
            // Process Relocations LOCALLY
            // ========================================
            UINT_PTR delta = (UINT_PTR)pRemoteImage - pNtHeaders->OptionalHeader.ImageBase;
            std::cout << MM_YELLOW << "[*] Relocation delta: 0x" << std::hex << delta << std::dec << "\n" << MM_RESET;

            if (delta != 0) {
                auto* pRelocDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
                if (pRelocDir->Size > 0) {
                    auto* pReloc = (IMAGE_BASE_RELOCATION*)(localImage.data() + pRelocDir->VirtualAddress);
                    BYTE* pRelocEnd = (BYTE*)pReloc + pRelocDir->Size;

                    while ((BYTE*)pReloc < pRelocEnd && pReloc->VirtualAddress && pReloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION)) {
                        UINT numEntries = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
                        WORD* pEntry = (WORD*)(pReloc + 1);

                        for (UINT i = 0; i < numEntries; i++, pEntry++) {
                            WORD type = *pEntry >> 12;
                            WORD offset = *pEntry & 0xFFF;

                            if (pReloc->VirtualAddress + offset >= imageSize)
                                continue;

                            BYTE* pPatch = localImage.data() + pReloc->VirtualAddress + offset;

                            if (type == IMAGE_REL_BASED_DIR64) {
                                *(UINT_PTR*)pPatch += delta;
                            }
                            else if (type == IMAGE_REL_BASED_HIGHLOW) {
                                *(DWORD*)pPatch += (DWORD)delta;
                            }
                        }

                        pReloc = (IMAGE_BASE_RELOCATION*)((BYTE*)pReloc + pReloc->SizeOfBlock);
                    }
                    std::cout << MM_GREEN << "[+] Relocations processed\n" << MM_RESET;
                }
            }

            // ========================================
            // Process Imports - Resolve to TARGET PROCESS addresses
            // ========================================
            auto* pImportDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
            if (pImportDir->Size > 0) {
                auto* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)(localImage.data() + pImportDir->VirtualAddress);

                while (pImportDesc->Name) {
                    char* szModName = (char*)(localImage.data() + pImportDesc->Name);
                    std::cout << MM_YELLOW << "[*] Resolving: " << szModName << "\n" << MM_RESET;

                    // Get thunks
                    auto* pOrigThunk = pImportDesc->OriginalFirstThunk ?
                        (IMAGE_THUNK_DATA*)(localImage.data() + pImportDesc->OriginalFirstThunk) : nullptr;
                    auto* pThunk = (IMAGE_THUNK_DATA*)(localImage.data() + pImportDesc->FirstThunk);

                    if (!pOrigThunk) pOrigThunk = pThunk;

                    while (pOrigThunk->u1.AddressOfData) {
                        UINT_PTR procAddr = 0;

                        if (IMAGE_SNAP_BY_ORDINAL(pOrigThunk->u1.Ordinal)) {
                            WORD ordinal = (WORD)IMAGE_ORDINAL(pOrigThunk->u1.Ordinal);
                            procAddr = GetRemoteProcAddress(m_hProcess, m_processId, szModName, nullptr, ordinal);
                        }
                        else {
                            auto* pImport = (IMAGE_IMPORT_BY_NAME*)(localImage.data() + pOrigThunk->u1.AddressOfData);
                            procAddr = GetRemoteProcAddress(m_hProcess, m_processId, szModName, pImport->Name, 0);
                        }

                        if (!procAddr) {
                            auto* pImport = (IMAGE_IMPORT_BY_NAME*)(localImage.data() + pOrigThunk->u1.AddressOfData);
                            std::cout << MM_RED << "[!] Failed to resolve: " << szModName << "!"
                                      << (pImport ? pImport->Name : "ordinal") << "\n" << MM_RESET;
                            VirtualFreeEx(m_hProcess, pRemoteImage, 0, MEM_RELEASE);
                            return false;
                        }

                        pThunk->u1.Function = procAddr;
                        pOrigThunk++;
                        pThunk++;
                    }

                    pImportDesc++;
                }
                std::cout << MM_GREEN << "[+] All imports resolved (target process addresses)\n" << MM_RESET;
            }

            // ========================================
            // Write the processed image to target
            // ========================================
            if (!WriteProcessMemory(m_hProcess, pRemoteImage, localImage.data(), imageSize, nullptr)) {
                std::cout << MM_RED << "[!] Failed to write image. Error: " << GetLastError() << "\n" << MM_RESET;
                VirtualFreeEx(m_hProcess, pRemoteImage, 0, MEM_RELEASE);
                return false;
            }

            std::cout << MM_GREEN << "[+] Image written to target process\n" << MM_RESET;

            // ========================================
            // Prepare and execute DllMain caller shellcode
            // ========================================
            DWORD entryRVA = pNtHeaders->OptionalHeader.AddressOfEntryPoint;
            if (entryRVA == 0) {
                std::cout << MM_YELLOW << "[*] No entry point - done\n" << MM_RESET;
                return true;
            }

            UINT_PTR pEntryPoint = (UINT_PTR)pRemoteImage + entryRVA;
            std::cout << MM_CYAN << "[*] Entry point: 0x" << std::hex << pEntryPoint << std::dec << "\n" << MM_RESET;

            // ========================================
            // Get exception directory for RtlAddFunctionTable
            // ========================================
            auto* pExceptionDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
            UINT_PTR pExceptionTable = 0;
            DWORD exceptionTableSize = 0;
            DWORD exceptionEntryCount = 0;

            if (pExceptionDir->Size > 0) {
                pExceptionTable = (UINT_PTR)pRemoteImage + pExceptionDir->VirtualAddress;
                exceptionTableSize = pExceptionDir->Size;
                exceptionEntryCount = exceptionTableSize / sizeof(RUNTIME_FUNCTION);
                std::cout << MM_GREEN << "[+] Exception table: " << exceptionEntryCount << " entries at 0x"
                          << std::hex << pExceptionTable << std::dec << "\n" << MM_RESET;
            }

            // ========================================
            // Get TLS directory for TLS callbacks (needed for CRT)
            // ========================================
            auto* pTlsDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
            UINT_PTR pTlsCallbacks = 0;
            DWORD tlsCallbackCount = 0;

            if (pTlsDir->Size > 0 && pTlsDir->VirtualAddress > 0) {
                // Safety check: make sure VirtualAddress is within bounds
                if (pTlsDir->VirtualAddress < imageSize) {
                    auto* pTls = (IMAGE_TLS_DIRECTORY*)(localImage.data() + pTlsDir->VirtualAddress);
                 
                    // TLS callbacks are stored as a null-terminated array of function pointers
                    // After relocation, AddressOfCallBacks points to the REMOTE address
                    if (pTls->AddressOfCallBacks) {
                        // The AddressOfCallBacks was relocated to point to remote memory
                        // We need to convert it back to local offset to read the callback array
                        UINT_PTR remoteCallbacksAddr = pTls->AddressOfCallBacks;
                     
                        // Check if it's a valid remote address (should be within our mapped image)
                        UINT_PTR remoteBase = (UINT_PTR)pRemoteImage;
                        if (remoteCallbacksAddr >= remoteBase && remoteCallbacksAddr < remoteBase + imageSize) {
                            UINT_PTR callbacksOffset = remoteCallbacksAddr - remoteBase;
                            pTlsCallbacks = remoteCallbacksAddr;
                         
                            // Count callbacks (in local image) - safely
                            if (callbacksOffset + sizeof(UINT_PTR) <= imageSize) {
                                UINT_PTR* pLocalCallbacks = (UINT_PTR*)(localImage.data() + callbacksOffset);
                                // Limit to 16 callbacks max to prevent infinite loop
                                while (callbacksOffset + (tlsCallbackCount + 1) * sizeof(UINT_PTR) <= imageSize
                                       && *pLocalCallbacks && tlsCallbackCount < 16) {
                                    tlsCallbackCount++;
                                    pLocalCallbacks++;
                                }
                             
                                if (tlsCallbackCount > 0) {
                                    std::cout << MM_GREEN << "[+] TLS callbacks: " << tlsCallbackCount << " at 0x"
                                              << std::hex << pTlsCallbacks << std::dec << "\n" << MM_RESET;
                                }
                            }
                        }
                    }
                }
            }

            // Get RtlAddFunctionTable address (same in all processes)
            HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
            UINT_PTR pRtlAddFunctionTable = (UINT_PTR)GetProcAddress(hNtdll, "RtlAddFunctionTable");

            if (!pRtlAddFunctionTable) {
                std::cout << MM_YELLOW << "[!] RtlAddFunctionTable not found - exceptions may not work\n" << MM_RESET;
            }

            // Shellcode data structure - expanded to include exception registration and TLS
#pragma pack(push, 1)
            struct ShellcodeData {
                UINT_PTR pDllMain; // offset 0x00
                UINT_PTR pImageBase; // offset 0x08
                UINT_PTR pRtlAddFunctionTable; // offset 0x10
                UINT_PTR pExceptionTable; // offset 0x18
                DWORD exceptionEntryCount; // offset 0x20
                DWORD imageSize; // offset 0x24
                UINT_PTR pTlsCallbacks; // offset 0x28
                DWORD tlsCallbackCount; // offset 0x30
            };
#pragma pack(pop)

            // x64 shellcode to:
            // 1. Call RtlAddFunctionTable to register exception handlers
            // 2. Call TLS callbacks (for CRT initialization)
            // 3. Call DllMain(pImageBase, DLL_PROCESS_ATTACH, NULL)
            //
            // Data layout at [pData]:
            // +0x00: pDllMain
            // +0x08: pImageBase
            // +0x10: pRtlAddFunctionTable
            // +0x18: pExceptionTable
            // +0x20: exceptionEntryCount (DWORD)
            // +0x24: imageSize (DWORD)
            // +0x28: pTlsCallbacks
            // +0x30: tlsCallbackCount (DWORD)
            unsigned char shellcode[] = {
                // Prologue - save RCX (pData) and setup stack
                0x55, // push rbp
                0x48, 0x89, 0xE5, // mov rbp, rsp
                0x48, 0x83, 0xEC, 0x50, // sub rsp, 80 (shadow + alignment + locals)
                0x48, 0x89, 0x4D, 0xF8, // mov [rbp-8], rcx (save pData)
             
                // Check if we have an exception table to register
                0x48, 0x8B, 0x41, 0x18, // mov rax, [rcx+0x18] (pExceptionTable)
                0x48, 0x85, 0xC0, // test rax, rax
                0x74, 0x1E, // jz skip_exception (30 bytes forward)
             
                // RtlAddFunctionTable(FunctionTable=RCX, EntryCount=RDX, BaseAddress=R8)
                0x48, 0x8B, 0x4D, 0xF8, // mov rcx, [rbp-8] (reload pData)
                0x48, 0x8B, 0x49, 0x18, // mov rcx, [rcx+0x18] -> RCX = pExceptionTable
                0x48, 0x8B, 0x55, 0xF8, // mov rdx, [rbp-8]
                0x8B, 0x52, 0x20, // mov edx, [rdx+0x20] -> EDX = entryCount
                0x4C, 0x8B, 0x45, 0xF8, // mov r8, [rbp-8]
                0x4D, 0x8B, 0x40, 0x08, // mov r8, [r8+0x08] -> R8 = pImageBase
                0x48, 0x8B, 0x45, 0xF8, // mov rax, [rbp-8]
                0xFF, 0x50, 0x10, // call [rax+0x10] (call pRtlAddFunctionTable)
             
                // skip_exception: Call DllMain(hModule=RCX, fdwReason=RDX, lpReserved=R8)
                0x48, 0x8B, 0x45, 0xF8, // mov rax, [rbp-8] (pData)
                0x48, 0x8B, 0x48, 0x08, // mov rcx, [rax+0x08] -> RCX = pImageBase (hModule)
                0xBA, 0x01, 0x00, 0x00, 0x00, // mov edx, 1 -> EDX = DLL_PROCESS_ATTACH
                0x4D, 0x31, 0xC0, // xor r8, r8 -> R8 = NULL (lpReserved)
                0xFF, 0x10, // call [rax] (call pDllMain)
             
                // Epilogue
                0x48, 0x89, 0xEC, // mov rsp, rbp
                0x5D, // pop rbp
                0xC3 //ret
            };

            // Allocate memory for data + shellcode
            SIZE_T totalSize = sizeof(ShellcodeData) + sizeof(shellcode) + 16;
            LPVOID pRemote = VirtualAllocEx(m_hProcess, nullptr, totalSize,
                MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

            if (!pRemote) {
                std::cout << MM_YELLOW << "[!] Could not allocate shellcode - image mapped but DllMain not called\n" << MM_RESET;
                return true;
            }

            // Prepare data
            ShellcodeData data;
            data.pDllMain = pEntryPoint;
            data.pImageBase = (UINT_PTR)pRemoteImage;
            data.pRtlAddFunctionTable = pRtlAddFunctionTable;
            data.pExceptionTable = pExceptionTable;
            data.exceptionEntryCount = exceptionEntryCount;
            data.imageSize = (DWORD)imageSize;
            data.pTlsCallbacks = pTlsCallbacks;
            data.tlsCallbackCount = tlsCallbackCount;

            // Write data
            WriteProcessMemory(m_hProcess, pRemote, &data, sizeof(data), nullptr);

            // Write shellcode after data (aligned)
            LPVOID pShellcode = (LPVOID)(((UINT_PTR)pRemote + sizeof(ShellcodeData) + 15) & ~15);
            WriteProcessMemory(m_hProcess, pShellcode, shellcode, sizeof(shellcode), nullptr);

            std::cout << MM_CYAN << "[*] Executing init shellcode (exception reg + DllMain)...\n" << MM_RESET;

            // Execute: CreateRemoteThread calls shellcode, passing pRemote (data ptr) in RCX
            HANDLE hThread = CreateRemoteThread(m_hProcess, nullptr, 0,
                (LPTHREAD_START_ROUTINE)pShellcode, pRemote, 0, nullptr);

            if (!hThread) {
                std::cout << MM_RED << "[!] CreateRemoteThread failed: " << GetLastError() << "\n" << MM_RESET;
                VirtualFreeEx(m_hProcess, pRemote, 0, MEM_RELEASE);
                return true; // Image is still mapped
            }

            // Wait for DllMain to complete
            DWORD waitResult = WaitForSingleObject(hThread, 20000);
         
            DWORD exitCode = 0;
            GetExitCodeThread(hThread, &exitCode);
            CloseHandle(hThread);

            // Cleanup shellcode memory
            VirtualFreeEx(m_hProcess, pRemote, 0, MEM_RELEASE);

            if (waitResult == WAIT_TIMEOUT) {
                std::cout << MM_YELLOW << "[!] DllMain execution timed out\n" << MM_RESET;
            } else {
                std::cout << MM_GREEN << "[+] DllMain returned: " << exitCode << "\n" << MM_RESET;
            }

            if (exitCode == 0) {
                std::cout << MM_RED << "[!] DllMain returned FALSE - injection may have failed\n" << MM_RESET;
            }

            std::cout << MM_GREEN << "\n[+] SUCCESS! DLL manually mapped at: 0x"
                      << std::hex << (UINT_PTR)pRemoteImage << std::dec << "\n" << MM_RESET;
            std::cout << MM_GREEN << "[+] DLL is NOT visible in module list!\n" << MM_RESET;
            std::cout << MM_GREEN << "[+] Exception handlers registered!\n" << MM_RESET;

            return true;
        }
    };

    inline bool InjectDll(DWORD processId, const std::string& dllPath) {
        Mapper mapper(processId);
        return mapper.MapDll(dllPath);
    }
}
 
Последнее редактирование:
Назад
Сверху Снизу