#1 23-08-2011 00:13

BritishColonist
Registered: 30-09-2009
Posts: 72

DLL Loader

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

p.s. как всегда, интересует не конкретный код, а "отправная точка".

Last edited by BritishColonist (23-08-2011 08:38)

Offline

#2 23-08-2011 12:43

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

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

Этот метод может не пройти, если dll уже загружена в память. В этом случае, есть вероятность что будут использована dll из памяти, а не с диска. В этом случае, в списке импортов оригинальной программы находим имя заменяемой .dll и заменяем каким-нибудь другим.

Вариант с user32 - плох тем, что нужно оборачивать все несколько сотен экспортируемых функций, т.к. даже если они не используются самой программой, они будут использованы остальными загружаемыми модулями.

Всякие фокусы с остановкой потоков и прочим - не нужны: на момент загрузки exe и подгрузки .dll из таблицы импорта, ни один поток еще не запущен.

В случае с SA используется перехват vorbisFile.dll (посмотреть исходники любого asi-loader для SA). В случае с IV я использую xlive.dll (которую все равно нужно менять на свою). Если, для IV, нужна загрузка asi - то используется перехват dsound.dll  - не уверен, что есть исходники, но там все тривиально - укладывается в 20 строчек.

Offline

#3 23-08-2011 17:16

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

а что ты подразумеваешь под обёрткой? типа такого?
создать в своей библиотеке функции (а точнее прототипы. нужно же?), затем сделать примерно такое:
MyProcedure1 = GetProcAddress(hOriginalDLL,"MyProcedure1");
а потом нагло экспортировать их?

ещё вопрос. да, я смотрел исходники твоего xliveless, мне понравилась эта функция:

XLIVELESS_API void injectFunction (DWORD dwAddress, DWORD pfnReplacement) {
	dwAddress += dwLoadOffset;
	BYTE * patch = (BYTE *)dwAddress;
	*patch = 0xE9;	// JMP
	*(DWORD *)(patch+1) = (pfnReplacement-(dwAddress+5));	
}

объясни, пожалуйста, что здесь происходит.
dwAddress, как я понимаю, это оффсет от Image Base процесса?
pfnReplacement - указатель на свою функцию?
вот тут я собственно не понимаю:

*(DWORD *)(patch+1) = (pfnReplacement-(dwAddress+5));

(DWORD*) - меняем размер (чтобы писать 4 байта), это понятно. а что за рассчёты такие? что за +5?

в общем, как я понимаю, просто вставляется джамп на свой адрес. а как потом нормально вернуть управление (джамп на свою функцию, там нужные нам действия, затем продолжение с того джампа) ?
прокатит, если сперва сделать джамп к себе, там первым делом вернуть оригинальный код (вместо джампа), выполнить свой код, затем в конце джампнуться на тот оригинальный код?


кстати, ещё вопрос. как вообще делаются плагины? так, чтобы правильно работали. не то, чтобы прям официально, но чтобы это было действительно расширение возможностей программы (например, QIP). в смысле, плагины это библиотеки DLL. они делаются с использованием специальных API или разработчик сам копает память и добавляет новенькое?

Last edited by BritishColonist (24-08-2011 00:57)

Offline

#4 24-08-2011 04:18

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

(Адрес функции) - (Заменяемый адрес)+1
Получаем нормальное смещение для прыжка (JMP)

Offline

#5 24-08-2011 22:37

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

если JMP требует лишь адрес, куда нужно прыгнуть, то почему нельзя просто указать адрес функции?
вот так:

*patch = 0xE9;  // JMP
*(DWORD *)(patch+1) = pfnReplacement;  // первый байт - опкод, следующие 4 байта - операнд.

и ещё, если мы меняем код, разве не нужно юзать VirtualProtect?

Offline

#6 25-08-2011 01:27

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

BritishColonist wrote:

а что ты подразумеваешь под обёрткой? типа такого?
создать в своей библиотеке функции (а точнее прототипы. нужно же?), затем сделать примерно такое:
MyProcedure1 = GetProcAddress(hOriginalDLL,"MyProcedure1");
а потом нагло экспортировать их?

Можно нагло, можно скромно, но принцип именно такой.

BritishColonist wrote:

ещё вопрос. да, я смотрел исходники твоего xliveless, мне понравилась эта функция:
...
объясни, пожалуйста, что здесь происходит.
dwAddress, как я понимаю, это оффсет от Image Base процесса?
pfnReplacement - указатель на свою функцию?
вот тут я собственно не понимаю:

*(DWORD *)(patch+1) = (pfnReplacement-(dwAddress+5));

(DWORD*) - меняем размер (чтобы писать 4 байта), это понятно. а что за рассчёты такие? что за +5?

BritishColonist wrote:

если JMP требует лишь адрес, куда нужно прыгнуть, то почему нельзя просто указать адрес функции?

Указать, разумеется, можно. Только результат будет далекий от ожидаемого.
<Устало вздыхая/> На сайте интеля, в разделе с документацией, валяется интересная книжка. Называется IA-32 Architecture Handbook. Заглядывание во второй том, сразу снимает много вопросов.

В частности, про JMP imm32, там написано, что параметром является смещение относительно начала следующей команды.  Длина этого JMP - пять байт, отсюда +5.

BritishColonist wrote:

в общем, как я понимаю, просто вставляется джамп на свой адрес. а как потом нормально вернуть управление (джамп на свою функцию, там нужные нам действия, затем продолжение с того джампа) ?
прокатит, если сперва сделать джамп к себе, там первым делом вернуть оригинальный код (вместо джампа), выполнить свой код, затем в конце джампнуться на тот оригинальный код?

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

BritishColonist wrote:

и ещё, если мы меняем код, разве не нужно юзать VirtualProtect?

Нужно. Но какой смысл вызывать ее каждый раз? Гораздо проще вызывать ее один раз при загрузке (вернее, два раза - для .text и для .rdata)

BritishColonist wrote:

кстати, ещё вопрос. как вообще делаются плагины? так, чтобы правильно работали. не то, чтобы прям официально, но чтобы это было действительно расширение возможностей программы (например, QIP). в смысле, плагины это библиотеки DLL. они делаются с использованием специальных API или разработчик сам копает память и добавляет новенькое?

Если специальный API предусмотрен - то используется он, если не предусмотрен, или его не хватает - приходится копать память.

Offline

#7 25-08-2011 08:50

RDH
From: Энгельс
Registered: 09-01-2010
Posts: 65

Re: DLL Loader

В частности, для QIP есть SDK. Вообще, для более-менее серьёзных программ имеется SDK, а ковырять память для таких программ невыгодно - адреса памяти будут меняться быстрее, чем ты напишешь плагин, т.к. постоянно выходят обновления.


programmer.png
modder.jpg

Offline

#8 25-08-2011 16:14

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

интересно.
ещё несколько вопросов ;D

1. как правильно выполнить "обёртку" функции?
так пойдёт?

extern "C" __declspec(dllexport) void ProcessSuicide() { ... }

2. в чём разница между dllexport и dllimport? вопрос, вроде как глупый, однако следующий код демонстрирует, словно пофиг, что из этого использовать:

#ifdef XLIVELESS_EXPORTS
#define XLIVELESS_API extern "C" __declspec(dllexport)
#else
#define XLIVELESS_API extern "C" __declspec(dllimport)
#endif

3. что такое __declspec(naked) void Function() {} ?
честно, я гуглил и читал это, но не понял, зачем делать функцию "без обрамления функции" (и, как это вообще понимать, я тоже не понял).

4. можно ли программно экспортировать динамический набор функций?
план таков: просматриваем секцию экспорта оригинальной DLL на предмет имён функций, дальше подставляем имя в цикле с префиксом __declspec и бла-бла-бла.
ведь вместо самой функции можно подставить указатель на неё?

while(int i=0; i<functionsCount; i++)
{
    ... // тут копаем структуру экспорта DLL на предмет имён
    name = ... ; // сюда запихиваем очередное имя функции
    extern "C" __declspec (dllexport) void* GetProcAddress(hOriginalDLL, name);
}

хотя, сомневаюсь, что так можно. а если сделать программку, которая загрузит в себя DLL, запишет все адреса и имена функций и, в соответствии с полученными данными, сгенерирует мне код, в котором будет обёртка всех функций, который уже я откомпилирую, это будет нормальным ленивым решением задачи?

5. предположим, что мне нужно сделать поддержку нескольких версий (скажем, трёх разных версий одного приложения), как различить версии? наверняка есть программка, которая вернёт первый адрес памяти (одинаковый адрес для всех приложений), по которому лежат разные значения? так их можно было бы различить.

Last edited by BritishColonist (25-08-2011 16:38)

Offline

#9 25-08-2011 16:42

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

1. Да, вполне подойдет (возможно, если функции передаются параметры, нужно добавить __stdcall)

2. dllexport нужен, если функция экспортируется. dllimport - если подключается из библиотеки, ссылающейся на внешнюю dll. В случае xliveless, один и тот же хэдер используется для компиляции .dll и для ее подключения к внешним плагинам. В зависимости от того, в ккакой роли он используется, функции объявляются либо как dllexport, либо как dllimport.

3. Нормально. парметры функции передаются на стеке, в ecx для __thiscall, либо в двух регистрах (не вспомню сейчас, каких) для __fastcall. Плюс к этому, действует соглашение, какие из регистров сохранять, а какие нет.
Иногда, нужно вызвать функцию, параметры которой находятся в произвольных регистрах, не попадающих ни под одну из конвенций. Для этого и используется naked. В этом случае, компилятор считает, что все регистры значимы и не делает с ними никаких действий. Просто добавляет CALL на эту функцию. Все остальные действия остаются на совести разработчика.

4. Список экспортов, к сожалению, можно делать только статически. Он должен быть доступен весь на этапе компиляции. Если это делать очень сильно влом, можно либо поизвращаться с  препроцессором, либо использовать внешний генерирующий скрипт.
Программа, которая грузит dll, получает список функций, находит их прототипы в SDK\Include и генерирует обертки - достаточно типичный пример такого скрипта.

Offline

#10 25-08-2011 18:28

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

а что, обязательно описывать их полные прототипы?
предположим, что в оригинальной библиотеке есть функция с параметрами:

void Function (int i);

у себя я её описываю вот так:

extern "C" __declspec(dllexport) void Function ();

а приложение у себя вновь описывает, как положено изначально:

void Function (int i);

разве так не будет работать?

Last edited by BritishColonist (25-08-2011 18:29)

Offline

#11 25-08-2011 20:49

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

Конечно, нет. Это разные функции.
Та, что у тебя, называется _Function. Та, что в приложении - ?Function@@@AXH@Z (если я ничего не путаю)

Если же ты про несовпадение параметров - то, для __cdecl,  это не особо критично. Контроль параметров там лежит на вызывающей стороне, т.е. можно описывать только те параметры, которые используются.

Offline

#12 25-08-2011 20:54

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

можешь продемонстрировать наглядный пример, как сделать подмену стандартной библиотечной функции на функцию из своей библиотеки?

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

прям на примере одной функции.

Last edited by BritishColonist (25-08-2011 20:58)

Offline

#13 28-08-2011 15:37

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

int (*__ov_time_seek)(void *vf, double pos) ;
extern "C"  __declspec(dllexport) int ov_time_seek(void *vf, double pos) 
{ return __ov_time_seek (vf, pos); }

// остальные прототипы не показаны

HMODULE vorbisHooked = NULL;

// подключение оригинальной vorbisFile.dll
void vorbisAttach () { // вызывается из DllMain, если передан DLL_PROCESS_ATTACH
	vorbisHooked = LoadLibrary ("vorbisHooked.dll");
	if (!vorbisHooked)
		return;

	__ov_open_callbacks = (int (__cdecl *)(void *, void *, char *, long, ov_callbacks))GetProcAddress (vorbisHooked, "ov_open_callbacks");
	__ov_clear = (int (__cdecl *)(void *))GetProcAddress (vorbisHooked, "ov_clear");
	__ov_time_total = (double (__cdecl *)(void *, int))GetProcAddress (vorbisHooked, "ov_time_total");
	__ov_time_tell = (double (__cdecl *)(void *))GetProcAddress (vorbisHooked, "ov_time_tell");
	__ov_read = (long (__cdecl *)(void *, char *, int, int, int, int, int *))GetProcAddress (vorbisHooked, "ov_read");
	__ov_info = (void *(_cdecl *)(void *, int))GetProcAddress (vorbisHooked, "ov_info");
	__ov_time_seek = (int (__cdecl *)(void *, double))GetProcAddress (vorbisHooked, "ov_time_seek");
}

void vorbisDetach () { // вызывается из DllMain, если передан DLL_PROCESS_DETACH
	if (vorbisHooked)        
		FreeLibrary (vorbisHooked);
}

Offline

#14 29-08-2011 10:59

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

хм. вроде всё довольно легко. спасибо.

а можно сделать так?
это:
IDirect3D9 * WINAPI Direct3DCreate9(UINT SDKVersion);
описать у себя так:
void* WINAPI Direct3DCreate9(UINT SDKVersion);

я не собираюсь использовать устройство, а указатель вроде как всегда одного размера.

Offline

#15 30-08-2011 18:31

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

Да, можно указывать любые типы, если размер совпадает.

Offline

#16 01-09-2011 04:15

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

IDirect3D9 * = void*
Это идентично...

Offline

#17 01-09-2011 07:20

Alien
Registered: 12-10-2008
Posts: 564

Re: DLL Loader

@VintProg_Pro - нифига не идентично.

Кстати, если импортируемый и экспортируемый символ совпадают, то можно обойтись и без GetProcAddress. По крайней мере мелкософтный компилятор это собирает:
dlmain.cpp

#include <cstdio>
#include <list>
#include <Windows.h>
#include <boost/foreach.hpp>

typedef __int64 ogg_int64_t;
typedef void OggVorbis_File;

typedef struct {
  size_t (*read_func)  (void *ptr, size_t size, size_t nmemb, void *datasource);
  int    (*seek_func)  (void *datasource, ogg_int64_t offset, int whence);
  int    (*close_func) (void *datasource);
  long   (*tell_func)  (void *datasource);
} ov_callbacks;

typedef struct vorbis_info{
  int version;
  int channels;
  long rate;
  long bitrate_upper;
  long bitrate_nominal;
  long bitrate_lower;
  long bitrate_window;

  void *codec_setup;
} vorbis_info;

typedef struct vorbis_comment{
  char **user_comments;
  int   *comment_lengths;
  int    comments;
  char  *vendor;

} vorbis_comment;

extern "C"
{
    int __cdecl ov_clear(OggVorbis_File *vf);
    int __cdecl ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
    int __cdecl ov_open_callbacks(void *datasource, OggVorbis_File *vf,
    char *initial, long ibytes, ov_callbacks callbacks);
    
    int __cdecl ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
    int __cdecl ov_test_callbacks(void *datasource, OggVorbis_File *vf,
    char *initial, long ibytes, ov_callbacks callbacks);
    int __cdecl ov_test_open(OggVorbis_File *vf);
    
    long __cdecl ov_bitrate(OggVorbis_File *vf,int i);
    long __cdecl ov_bitrate_instant(OggVorbis_File *vf);
    long __cdecl ov_streams(OggVorbis_File *vf);
    long __cdecl ov_seekable(OggVorbis_File *vf);
    long __cdecl ov_serialnumber(OggVorbis_File *vf,int i);
    
    ogg_int64_t __cdecl ov_raw_total(OggVorbis_File *vf,int i);
    ogg_int64_t __cdecl ov_pcm_total(OggVorbis_File *vf,int i);
    double __cdecl ov_time_total(OggVorbis_File *vf,int i);
    
    int __cdecl ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
    int __cdecl ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
    int __cdecl ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
    int __cdecl ov_time_seek(OggVorbis_File *vf,double pos);
    int __cdecl ov_time_seek_page(OggVorbis_File *vf,double pos);
    
    ogg_int64_t __cdecl ov_raw_tell(OggVorbis_File *vf);
    ogg_int64_t __cdecl ov_pcm_tell(OggVorbis_File *vf);
    double __cdecl ov_time_tell(OggVorbis_File *vf);
    
    vorbis_info * __cdecl ov_info(OggVorbis_File *vf,int link);
    vorbis_comment * __cdecl ov_comment(OggVorbis_File *vf,int link);
    
    long __cdecl ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples,
        int *bitstream);
    long __cdecl ov_read(OggVorbis_File *vf,char *buffer,int length,
            int bigendianp,int word,int sgned,int *bitstream);    
}

// RAII loading of libraries
class AsiLoader
{
    std::list<HMODULE> loadedLibs;
public:
    AsiLoader()
    {
        HANDLE hSearch = NULL;
        WIN32_FIND_DATA wfd;
        if ((hSearch = FindFirstFile("*.asi", &wfd)) == INVALID_HANDLE_VALUE) 
            return;
        do
        {
            if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
            {
                const char *p;
                for (p = wfd.cFileName; *p; ++p) ;
                // lowercase littleEndian ".asi"
                if ((*reinterpret_cast<const DWORD *>(p - 4) | 0x20202000)  == 'isa.')
                {
                    HMODULE hModule = LoadLibrary(wfd.cFileName);
                    if (!hModule) 
                    {
                        char message[0x100];
                        strcpy(message, "Error loading plugin ");
                        strcat(message, wfd.cFileName);
                        MessageBox(0, message, "Asi loader error", MB_ICONERROR);
                    }
                    else
                        loadedLibs.push_back(hModule);
                }
            }
        }
        while (FindNextFile(hSearch, &wfd));
        FindClose (hSearch);
    }

    virtual ~AsiLoader()
    {
        BOOST_FOREACH(HMODULE hModule, loadedLibs)
            FreeLibrary(hModule);
    }
};

// load *.asi's
AsiLoader asiLoader;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    return TRUE;
}

exports.def

LIBRARY

EXPORTS 
    ov_bitrate                @1
    ov_bitrate_instant        @2
    ov_clear                @3
    ov_comment                @4
    ov_crosslap                @5
    ov_halfrate                @6
    ov_halfrate_p            @7
    ov_info                    @8
    ov_open                    @9
    ov_open_callbacks        @10
    ov_pcm_seek                @11
    ov_pcm_seek_lap            @12
    ov_pcm_seek_page        @13
    ov_pcm_seek_page_lap    @14
    ov_pcm_tell                @15
    ov_pcm_total            @16
    ov_raw_seek                @17
    ov_raw_seek_lap            @18
    ov_raw_tell                @19
    ov_raw_total            @20
    ov_read                    @21
    ov_read_float            @22
    ov_seekable                @23
    ov_serialnumber            @24
    ov_streams                @25
    ov_test                    @26
    ov_test_callbacks        @27
    ov_test_open            @28
    ov_time_seek            @29
    ov_time_seek_lap        @30
    ov_time_seek_page        @31
    ov_time_seek_page_lap    @32
    ov_time_tell            @33
    ov_time_total            @34

Ну и естественно, линковщику нужно еще скормить .lib-файл от vorbisHooked.dll.

Низкоуровнево экспортированные символы выглядят следующим образом:

.text:100011DA     ; Exported entry   1. ov_bitrate
.text:100011DA
.text:100011DA     ; =============== S U B R O U T I N E =======================================
.text:100011DA
.text:100011DA
.text:100011DA                     public ov_bitrate
.text:100011DA     ov_bitrate      proc near               ; DATA XREF: .text:off_10001468o
.text:100011DA 000                 jmp     vorbisHooked_1
.text:100011DA     ov_bitrate      endp

Last edited by Alien (01-09-2011 07:29)

Offline

#18 02-09-2011 02:29

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

IDirect3D9 * = void* - если для языка высокого уровня, то разные веши.
Для ассемблера же это все одинаково!!!

Offline

#19 03-09-2011 17:25

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

спасибо, ребята.
решил-таки заняться хуком D3D9.
так что реквестирую больше подсказок и примеров ;D

пробил экспорт из стандартной d3d9.dll (с помощью своей программки):

There are 14 functions in d3d9.dll: 

CheckFullscreen
D3DPERF_BeginEvent
D3DPERF_EndEvent
D3DPERF_GetStatus
D3DPERF_QueryRepeatFrame
D3DPERF_SetMarker
D3DPERF_SetOptions
D3DPERF_SetRegion
DebugSetLevel
DebugSetMute
Direct3DCreate9
Direct3DShaderValidatorCreate9
PSGPError
PSGPSampleTexture

скомпилил свой вариант, написанный на базе кода из поста #13 (listener), пробил в той же программке экспорт:

There are 10 functions in d3d9.dll: 

_D3DPERF_BeginEvent
_D3DPERF_EndEvent
_D3DPERF_GetStatus
_D3DPERF_QueryRepeatFrame
_D3DPERF_SetMarker
_D3DPERF_SetOptions
_D3DPERF_SetRegion
_Direct3DCreate9
_Direct3DShaderValidatorCreate9
___CPPdebugHook

в связи с этим вопросы:
1) что за подчёркивания? как экспортировать нормальные имена (в исходниках у них оригинальные названия, а не эти)?
2) что за ___CPPdebugHook? моя либа явно этого не экспортирует, но использую я C++ Builder (мало ли, чего там напридумали?).
3) я нигде не нашёл следующие функции: CheckFullscreen, DebugSetLevel, DebugSetMute, PSGPError, PSGPSampleTexture. что это такое и как бы его у себя описать?
4) (главный вопрос) нужно ли экспортировать что-либо кроме Direct3DCreate9? видел в каких-то исходниках, что экспортируют только одну её, правда через .def-файл, как в посте #17 (Alien).
5) может, где-то уже были все эти вопросы? проще конечно же дать мне ссылку, если были. гугл не помогает: пара иностранных сайтов с минимумом комментариев по коду, половина из которых естественно непонятна. прям как-то неловко изучать что-то в сетях.. grin

Last edited by BritishColonist (03-09-2011 17:29)

Offline

#20 04-09-2011 02:44

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

По поводу Хука смотри пример на моем сайте:
http://gtaexe.3dn.ru/load/gta_vc/iskhod … od/3-1-0-2

Offline

#21 04-09-2011 08:08

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

ты не поверишь, но именно этот исходник я упомянул, он содержит один экспорт Direct3DCreate9.
: D

Offline

#22 04-09-2011 13:45

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

я по работал не много над ним что-бы он компилировался)))

Offline

#23 04-09-2011 20:42

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

@BritishColonist - ___CPPdebugHook - борландовая функция для подключения борландового же отладчика. Функции D3DPERF_xxx - недокументированные функции для микрософтовского отладчика или профайлера. Они могут быть описаны в DDK, но на них можно просто забить.

Подчеркивание добавляется, из-за того, что функции описаны как __cdecl. Они должны быть описаны как __stdcall, в этом случае, будет добавляться не подчеркивание в начале, а размер параметров в конце через '@'. Правильные имена описываются в .def-файле.

Offline

#24 05-09-2011 04:20

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

Имейте введу, что Интерфейс DX уже выделин, его только надо перехватить...

Offline

#25 22-09-2011 16:39

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

хм.
есть где-нибудь годный гайд с примерами на тему инжекта кода?
хочу повторить код, который есть в стандартном exe (естественно вызывать его в нужное мне время и с нужными мне параметрами), но я не знаю, как найденный код перенести на C++ (сложность в том, чтобы обозначить границы действительно нужного ассемблерного кода).
найти нужные байты и адреса я смогу (Cheat Engine + Olly Dbg), но нужна мне не замена, а просто повтор.
в итоге должнен получиться "инжект кусков кода".

если нет гайдов, не мог бы кто-нибудь привести пример описания у себя функции с параметрами (здесь уже речь об описании прототипа функции, без использования ассемблерных вставок)?
и ещё. когда копаю эти функции, нередко натыкаюсь на "ненужные" параметры перед собственно вызовом функции по адресу (наряду с важными для функции значениями (передаваемыми параметрами) в стек пихаются какие-нибудь нули или единицы (независимо от параметров)). как у себя описывать такие функции (тут уже не куски кода, а описание функции на C++ с указанием её адреса в пространстве)? в смысле, есть функция void FUNCTION (int, float). я точно уверен, что важны два параметра и могу определить их в отладчике, однако в коде зачем-то в стек пихается больше значений, чем два. в общем, я даже не знаю как сформулировать вопрос grin как приложение понимает, что функция, вызываемая как FUNCTION (10, 234.55) на самом деле принимает только 2 параметра и как мне описать такую FUNCTION, если я наткнусь на непонятные "лишние" параметры в стеке?

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

Last edited by BritishColonist (22-09-2011 16:44)

Offline

Board footer

Powered by FluxBB