Доступ к неэкспортируемым функциям DLL

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Я как-то кодировал звук в AAC-формат с помощью DLL, которая шла плагином для WinAmp-а (нажеюсь, ничего не перепутал :) ).
Так там кодировщих был в виде C++ - класса с несколькими методами (причем, помнится, один из которых виртуальный). А далее, вроде как, из DLL вызывалась предназначенная для этого функция, котораявозвращала указатель на экземпляр этого класса. И вызывающая программа делала то, что ей требуется, через методы класса.

Как это все делалось, я нашел примеры в интернете. И на основе этого "руководства к действию" сам сделал. Если кого-то заинтересовало, могу найти свой исходник.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Yes!!! У меня получилось.
Я передаю массив с адресами функций через основную кучу процесса.
Вот код DLL, в которой нет ни одной экспортируемой функции...

Код: Выделить всё

// HeapLib.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <tchar.h>

BOOL PrintText(LPCTSTR szText)
{
    static HANDLE hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
    //
    DWORD dw(0);
    return ::WriteConsole(hConsole, szText, ::lstrlen(szText), &dw, NULL);
}

BOOL SayHello()
{
    return PrintText(_T("Привет всем программерам!\r\n"));
}

BOOL SayGoodBye()
{
    return PrintText(_T("Всем пока! :-)\r\n"));
}

class Global
{
public:
    Global()
    {
        HANDLE hHeap = ::GetProcessHeap();
        m_lpData = (LPBYTE)::HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 80);
        if (m_lpData != NULL)
        {
            char Signature[] = "HEAP :D LL";
            memcpy((LPSTR)m_lpData, Signature, sizeof(Signature));
            FARPROC* lpFarProc = (FARPROC*)(m_lpData+16);
            lpFarProc[0] = (FARPROC)SayHello;
            lpFarProc[1] = (FARPROC)SayGoodBye;
        }
    }
    ~Global()
    {
        if (m_lpData != NULL)
        {
            HANDLE hHeap = ::GetProcessHeap();
            ::HeapFree(hHeap, 0, m_lpData);
        }
    }
private:
    LPBYTE m_lpData;
} _global;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved )
{
    return TRUE;
}
А вот код, который вызывает из неё функции...

Код: Выделить всё

#include "stdafx.h"

typedef BOOL (*SAYHELLO)(void);
typedef BOOL (*SAYGOODBYE)(void);

int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE hModule = ::LoadLibrary(_T("HeapLib.dll"));
    if (hModule != NULL)
    {
        FARPROC* lpFarProc(NULL);
        HANDLE hHeap = ::GetProcessHeap();
        PROCESS_HEAP_ENTRY phe = {NULL};
        BOOL bNext = ::HeapWalk(hHeap, &phe);
        while (bNext != FALSE)
        {
            bNext = ::HeapWalk(hHeap, &phe);
            if (phe.cbOverhead > 0)
            {
                LPCSTR lps = (LPCSTR)phe.lpData;
                if (strcmp(lps, "HEAP :D LL") != 0)
                    continue;
                lpFarProc = (FARPROC*)((LPBYTE)phe.lpData+16);
                break;
            }
        }
        if (lpFarProc != NULL)
        {
           SAYHELLO fhSayHello = (SAYHELLO)lpFarProc[0];
           SAYGOODBYE fhSayGoodBye = (SAYGOODBYE)lpFarProc[1];
           // вызов полученных функций...
           fhSayHello();
           fhSayGoodBye();
        }
        //
        ::FreeLibrary(hModule);
    }
    getc(stdin);
    return 0;
}
При выполнении программы на экране появляются строки:
Привет всем программерам!
Всем пока! :-)

WinMain
, спасибо за прекрасную идею!
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Decoder писал(а):Yes!!! У меня получилось.
Я передаю массив с адресами функций через основную кучу процесса.
...............
WinMain, спасибо за прекрасную идею!
Хм. Лихо закручено.
Т.е. получился этакий "lib-файл", расположенный в памяти (в Heap-е). Вызывающая программа находит его, "линкует" к себе - т.е. получает адреса "экспортируемых" функций и использует их.
maxrfon
Сообщения: 6
Зарегистрирован: 24 июл 2009, 17:29

А вот такую задачу как решить? Нужно вызвать GeNeRator функцию, но со своими параметрами. Есть мысли (если можно практичные) как это можно сделать?

Код: Выделить всё

.text:0526CCA0 CheckMEproc near               ; CODE XREF: LoadGenFiles+85p
.text:0526CCA0
.text:0526CCA0 var_20          = dword ptr -20h
.text:0526CCA0 arg_0           = dword ptr  4
.text:0526CCA0 arg_4           = dword ptr  8
.text:0526CCA0
.text:0526CCA0                 mov     ecx, [ecx+8]
.text:0526CCA3                 sub     esp, 20h
.text:0526CCA6                 test    ecx, ecx
.text:0526CCA8                 jnz     short loc_526CCCB
.text:0526CCAA                 lea     eax, [esp+20h+var_20]
.text:0526CCAE                 push    (offset unk_534B3FF+0AF456B1h) ; Format
.text:0526CCB3                 push    eax             ; int
.text:0526CCB4                 call    sub_526C360
.text:0526CCB9                 add     esp, 8
.text:0526CCBC                 lea     ecx, [esp+20h+var_20]
.text:0526CCC0                 push    (offset unk_5322BFF+0AF4C241h)
.text:0526CCC5                 push    ecx
.text:0526CCC6                 call    __CxxThrowException@8
.text:0526CCCB
.text:0526CCCB loc_526CCCB:                            ; CODE XREF: CheckME+8j
.text:0526CCCB                 mov     eax, [esp+20h+arg_4]
.text:0526CCCF                 mov     edx, [ecx]      ; Pointer to offset of cryptoroutines
.text:0526CCD1                 push    eax             ; EAX = 0x0F
.text:0526CCD2                 mov     eax, [esp+24h+arg_0]
.text:0526CCD6                 push    eax             ; Входные данные
[b].text:0526CCD7                 call    dword ptr [edx+20h] ; GeNeRaTor <- Вот эту функцию мне нужно вызвать... Но как?? [/b]
.text:0526CCDA                 add     esp, 20h
.text:0526CCDD                 retn    8
Головоломка
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Зная текущий адрес вызываемой функции, нужно найти её RVA (Relative Virtual Address). Для этого нужно из текущего адреса функции вычесть значение HMODULE (или HINSTANCE) этой DLL.
Значение RVA является постоянным и не меняется с момента последней сборки модуля. А значение HMODULE при каждой новой загрузке DLL может каждый раз отличаться. При следующей загрузке DLL нужно значение RVA прибавить к значению HMODULE загруженной DLL. Получившееся значение и есть адрес вызываемой функции.
Если функция является экспортируемой, то её RVA можно посмотреть с помощью утилиты Dependency Walker.
Ответить