[C++] Внешнее хранение Api на основе маппинга

Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
Шалом, давно не писал статеек, много проблем и работы навалилось.
К всеобщему обозрению, предоставляю концепцию хранения апи (функций чего угодно) за пределами программы.
(в C# это называется динамическая сборка с поздним связыванием)
Конечному потребителю кода стоит учесть: это лишь наброски, не претендующие на абсолютно идеальную финальную версию.
Для чего это нужно?

  1. Хранение важного кода за пределами программы. (в отдельной длл)
    За пределами программы - это где угодно, в ресурсах, в памяти, на веб-сайте.

  2. Определение условий, при которых ваша программа получит этот самый важный код остается на ваше усмотрение.
    (самый распространенный пример: проверка лицензии) Прописываете в скрипте сайта, чтобы не выдавал сборку с функциями для инжекта и тп, пока нет лицензии, зачастую это используют для схемы: чтобы крякнуть - сначала купи, или ищи того у кого уже есть.

  3. Вся аллокация может быть записана в контейнер при желании.
    То есть, вы можете скачать с вебчасти и выполнить важный код и удалить все его следы из памяти (если захотите с этим возится), и все это на ЛЕТУ.
Сам код (Dll)

Library.h:
Код:
#pragma once
#include <windows.h>

#define EXPORT_API __declspec( dllexport )
//тупо экспортируем все в дллке что нам нужно использовать:
extern "C"
{
    EXPORT_API int WINAPI getVersion()
    {
        return 10;
    }
};
Library.cpp:
Код:
#include "Library.h"
BOOL WINAPI DllMain(HMODULE hDll, DWORD dwReason, LPVOID lpReserved) {
    switch (dwReason)
    {
    case DLL_PROCESS_ATTACH:
        //Чтобы проверить, загрузилось ли все как надо.
        MessageBoxA(0, "tested", "texted", 0);
        break;
    case DLL_PROCESS_DETACH:
        break;
    }

    return TRUE;
}
Как это использовать: (за основу как сказано, в заголовке, взял обычный маппинг)
API.h (для вашей программы)
Код:
#pragma once
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;


struct _EXPOTR_FUNC
{
    FARPROC Func;
    char* Name;
    _EXPOTR_FUNC(FARPROC _a, char* _b)
    {
        Func = _a;
        Name = _b;
    }
};

vector<_EXPOTR_FUNC*> _query_export_list(HMODULE Mod)
{
    vector<_EXPOTR_FUNC*> t3Vector;

    ULONG Portable_Executable;
    PIMAGE_EXPORT_DIRECTORY EXPORT_DIRECTORY;

    PULONG  RVAPointer;
    PUSHORT oTb_RVA;
    PULONG  dwTbRVA;
    ULONG  uReturn = 0;
    USHORT tmpINDEX;
    char * tmpName;
    ULONG Adress;
    ULONG size_CNT;

    if (Mod)
    {
        Portable_Executable =
            *(ULONG*)((ULONG)Mod + 0x3C) + (ULONG)Mod;
        EXPORT_DIRECTORY =
            (PIMAGE_EXPORT_DIRECTORY)(*(ULONG*)((ULONG)Portable_Executable + 0x78) + (ULONG)Mod);

        RVAPointer =
            (ULONG*)(EXPORT_DIRECTORY->AddressOfNames + (ULONG)Mod);
        oTb_RVA =
            (USHORT*)(EXPORT_DIRECTORY->AddressOfNameOrdinals + (ULONG)Mod);
        dwTbRVA =
            (ULONG*)(EXPORT_DIRECTORY->AddressOfFunctions + (ULONG)Mod);

        if (EXPORT_DIRECTORY->NumberOfNames > EXPORT_DIRECTORY->NumberOfFunctions)
            size_CNT = EXPORT_DIRECTORY->NumberOfNames;
        else
            size_CNT = EXPORT_DIRECTORY->NumberOfFunctions;


        for (USHORT i = 0; i < size_CNT; i++)
        {
            if (i < EXPORT_DIRECTORY->NumberOfFunctions)
            {
                tmpName = (char*)(RVAPointer[i] + (ULONG)Mod);
                tmpINDEX = oTb_RVA[i];
            }
            else
            {
                tmpName = 0;
                tmpINDEX = i;
            }
            Adress = dwTbRVA[tmpINDEX] + (ULONG)Mod;
            t3Vector.push_back(new _EXPOTR_FUNC((FARPROC)Adress, tmpName));
        }
    }
    return t3Vector;
}

using LoadLibraryFn = HMODULE(WINAPI*)(LPCSTR);
using GetProcAddressFn = FARPROC(WINAPI*)(HMODULE, LPCSTR);
using DllMainFn = BOOL(WINAPI*)(HMODULE, DWORD, PVOID);

typedef struct _INJECT
{
    PVOID                    ImageBase;
    PIMAGE_NT_HEADERS        NtHeaders;
    PIMAGE_BASE_RELOCATION   BaseRelocation;
    PIMAGE_IMPORT_DESCRIPTOR ImportDirectory;
    LoadLibraryFn            pLoadLibraryA;
    GetProcAddressFn         pGetProcAddress;
}INJECT, *P_INJECT;

DWORD WINAPI LoadDll(P_INJECT p)
{
    P_INJECT m_pInject = (P_INJECT)p;


    DWORD i = 0,
        Function = 0,
        count = 0;


    PDWORD ptr = nullptr;
    PWORD  list = nullptr;



    PIMAGE_IMPORT_BY_NAME    pIBN = { 0 };
    PIMAGE_THUNK_DATA        FirstThunk = { 0 };
    PIMAGE_THUNK_DATA        OrigFirstThunk = { 0 };
    DllMainFn                EntryPoint = nullptr;



    PIMAGE_BASE_RELOCATION pIBR = m_pInject->BaseRelocation;
    DWORD delta = (DWORD)((LPBYTE)m_pInject->ImageBase - m_pInject->NtHeaders->OptionalHeader.ImageBase);

    while (pIBR->VirtualAddress)
    {
        if (pIBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))
        {
            count = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
            list = (PWORD)(pIBR + 1);

            for (i = 0; i<count; i++)
            {
                if (list[i])
                {
                    ptr = (PDWORD)((LPBYTE)m_pInject->ImageBase + (pIBR->VirtualAddress + (list[i] & 0xFFF)));
                    *ptr += delta;
                }
            }
        }
        pIBR = (PIMAGE_BASE_RELOCATION)((LPBYTE)pIBR + pIBR->SizeOfBlock);
    }
    PIMAGE_IMPORT_DESCRIPTOR pIID = m_pInject->ImportDirectory;
    HMODULE  hModule = NULL;
    while (pIID->Characteristics)
    {
        OrigFirstThunk = (PIMAGE_THUNK_DATA)((LPBYTE)m_pInject->ImageBase + pIID->OriginalFirstThunk);
        FirstThunk = (PIMAGE_THUNK_DATA)((LPBYTE)m_pInject->ImageBase + pIID->FirstThunk);
        hModule = m_pInject->pLoadLibraryA((LPCSTR)m_pInject->ImageBase + pIID->Name);

        if (!hModule)
            return FALSE;

        while (OrigFirstThunk->u1.AddressOfData)
        {
            if (OrigFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
            {
                Function = (DWORD)m_pInject->pGetProcAddress(hModule, (LPCSTR)(OrigFirstThunk->u1.Ordinal & 0xFFFF));

                if (!Function)
                    return FALSE;
                FirstThunk->u1.Function = Function;
            }
            else
            {
                pIBN = (PIMAGE_IMPORT_BY_NAME)((LPBYTE)m_pInject->ImageBase + OrigFirstThunk->u1.AddressOfData);
                Function = (DWORD)m_pInject->pGetProcAddress(hModule, (LPCSTR)pIBN->Name);

                if (!Function)
                    return FALSE;

                FirstThunk->u1.Function = Function;
            }
            OrigFirstThunk++;
            FirstThunk++;
        }
        pIID++;
    }

    if (m_pInject->NtHeaders->OptionalHeader.AddressOfEntryPoint)
    {
        EntryPoint = (DllMainFn)((LPBYTE)m_pInject->ImageBase + m_pInject->NtHeaders->OptionalHeader.AddressOfEntryPoint);
        return EntryPoint((HMODULE)m_pInject->ImageBase, DLL_PROCESS_ATTACH, nullptr);
    }
    return TRUE;
}

BOOL HideLoadLibrary(PVOID  pBuffer, P_INJECT & inject)
{
    PIMAGE_DOS_HEADER     pIDH = { 0 };
    PIMAGE_NT_HEADERS     pINH = { 0 };
    PIMAGE_SECTION_HEADER pISH = { 0 };

    pIDH = (PIMAGE_DOS_HEADER)pBuffer;
    if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
    {
        std::cout << "Error:: Invalid executable image" << std::endl;
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }

    pINH = (PIMAGE_NT_HEADERS)((LPBYTE)pBuffer + pIDH->e_lfanew);
    if (pINH->Signature != IMAGE_NT_SIGNATURE)
    {
        std::cout << "Error:: Invalid PE header" << std::endl;
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }

    if (!(pINH->FileHeader.Characteristics & IMAGE_FILE_DLL))
    {
        std::cout << "Error:: The image is not DLL" << std::endl;
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }

    PVOID  image = VirtualAlloc(NULL, pINH->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!image)
    {
        std::cout << "Error::  Allocate memory for the DLL::" << GetLastError() << std::endl;
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }

    if (!memcpy(image, pBuffer, pINH->OptionalHeader.SizeOfHeaders))
    {
        std::cout << "Error::  Copy headers to process::" << GetLastError() << std::endl;
        VirtualFree(image, 0, MEM_RELEASE);
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }

    pISH = (PIMAGE_SECTION_HEADER)(pINH + 1);
    for (DWORD i = 0; i<pINH->FileHeader.NumberOfSections; i++)
    {
        memcpy((PVOID)((LPBYTE)image + pISH[i].VirtualAddress), (PVOID)((LPBYTE)pBuffer + pISH[i].PointerToRawData), pISH[i].SizeOfRawData);
    }

    PVOID mem = VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!mem)
    {
        std::cout << "Error::  Allocate memory for the loader code::" << GetLastError() << std::endl;
        VirtualFree(image, 0, MEM_RELEASE);
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }
    INJECT* m_pInject = new INJECT;
    //memset(&m_pInject, 0, sizeof(INJECT));
    m_pInject->ImageBase = image;
    m_pInject->NtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)image + pIDH->e_lfanew);
    m_pInject->BaseRelocation = (PIMAGE_BASE_RELOCATION)((LPBYTE)image + pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
    m_pInject->ImportDirectory = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)image + pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    m_pInject->pLoadLibraryA = LoadLibraryA;
    m_pInject->pGetProcAddress = GetProcAddress;

    if (!LoadDll(m_pInject))
    {
        std::cout << "Error::  Unable to execute loader code::" << GetLastError() << std::endl;
        VirtualFree(mem, 0, MEM_RELEASE);
        VirtualFree(image, 0, MEM_RELEASE);
        VirtualFree(pBuffer, 0, MEM_RELEASE);
        return FALSE;
    }

    VirtualFree( mem, 0, MEM_RELEASE);

    if (pINH->OptionalHeader.AddressOfEntryPoint)
    {
        printf_s("DLL entry point: %#x\n", (PVOID)((LPBYTE)image + pINH->OptionalHeader.AddressOfEntryPoint));
    }
    VirtualFree(pBuffer, 0, MEM_RELEASE);
    std::cout << "DLL injected!" << std::endl;
    inject = m_pInject;
    return TRUE;
API.cpp:
Код:
#include "API.h"
//я догружал длл из шелкода, вы можете откуда угодно
#include "code_file.h"

int main()
{
    P_INJECT inject;
    //rawData - мой мосив байт из которого я грузил длл
    //вы можете получить его прямо с сайта, или с ресурсов, или откуда хотите.
    if (HideLoadLibrary((PVOID)rawData, inject))
    {
        //Прототип нашего експорта:
        using _getVersion = int(WINAPI*)();

        std::cin.get();
        //извлекаем из нашей длл каталог наших експортов:
        vector<_EXPOTR_FUNC*> exports = _query_export_list((HMODULE)inject->ImageBase);
        //выводим для проверки
        for (_EXPOTR_FUNC* func : exports)
        {
            printf("Name: %s, Address: 0x%X\n", func->Name, func->Func);
        }
        //обращаемся к функции по адресу
        int version = reinterpret_cast<_getVersion>(exports[0]->Func)();
        //выводим результат выполнения:
        printf("Version: %d", version);
    }
    std::cin.get();
    return 0;
}
На последок скажу, что это лишь идея. Пастить именно в таком виде не обязательно, можно доделать/переделать, улучшить и тп или взять основной принцип как идейный генератор, и обернуть вокруг него свою концепцию. Ибо это 10 минутный тяп ляп код, лишь бы работало. (и к стати работает. проверено)
 
Пользователь
Статус
Оффлайн
Регистрация
26 Окт 2017
Сообщения
519
Реакции[?]
95
Поинты[?]
2K
Удобная тема, но всё же я считаю минусом то что код в том же shell никак не зашифрован, и совместимость с протектором такого шелкода не гарантируется...
А еще минус в том что это мало кому будет нужно на данном форуме ибо те кому надо и так знают, а другие еще не доросли если вообще дорастут.
 
Я лучше тебя
Пользователь
Статус
Оффлайн
Регистрация
9 Окт 2017
Сообщения
184
Реакции[?]
75
Поинты[?]
1K
Удобная тема, но всё же я считаю минусом то что код в том же shell никак не зашифрован, и совместимость с протектором такого шелкода не гарантируется...
А еще минус в том что это мало кому будет нужно на данном форуме ибо те кому надо и так знают, а другие еще не доросли если вообще дорастут.
Урок не плох. Кому надо дорастет.

Как бы написано:
"Ибо это 10 минутный тяп ляп код, лишь бы работало. (и к стати работает. проверено) "
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
Удобная тема, но всё же я считаю минусом то что код в том же shell никак не зашифрован, и совместимость с протектором такого шелкода не гарантируется...
в конце темы указано, что можно доработать на свое усмотрение, включая шифрование шелкода.

А еще минус в том что это мало кому будет нужно на данном форуме ибо те кому надо и так знают, а другие еще не доросли если вообще дорастут.
мое дело предоставить экземпляр, а кому понадобится/не понадобится, дело уже не мое.
 
Сверху Снизу