Замена функции в декомпилированной DLL

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

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

Может ли моя пользовательская функция находиться в отдельной dll или ее нужно включать в ту же dll?

Как я могу заменить вызов функции на мой новый?

Спасибо


person Lukesmith    schedule 26.04.2013    source источник
comment
Может быть проще просто пропатчить DLL. Добавьте новый код в конец текстового сегмента и поместите переход к добавленному коду в начало старой функции.   -  person Captain Obvlious    schedule 27.04.2013
comment
На самом деле я только что понял, что это не вариант. Ему нужно перейти или вызвать функцию из другой dll. Это возможно?   -  person Lukesmith    schedule 27.04.2013
comment
Если вы можете обновить свой вопрос, указав более подробности о том, как вы хотите вызывать функцию из внешней DLL, я обновлю свой ответ, чтобы отразить изменения.   -  person Captain Obvlious    schedule 27.04.2013
comment
Рассматривали ли вы прокси-dll вместо исправления или замены функции? Здесь есть инструменты для автоматического создания прокси-сервера codeproject.com/Articles. /16541/   -  person Rich    schedule 27.04.2013


Ответы (1)


Может быть проще просто пропатчить исполняемый модуль. Добавьте новый код в конец текстового сегмента и поместите переход к добавленному коду в начало старой функции. Таким образом, вам не придется иметь дело с проблемами, которые может вызвать декомпилированная версия DLL.

Например, вот начало существующей функции, которую вы хотите заменить:

000D0880  push        ebp  
000D0881  mov         ebp,esp  
000D0883  sub         esp,0E0h  
000D0889  push        ebx  
000D088A  push        esi  
000D088B  push        edi  
000D088C  lea         edi,[ebp-0E0h]  
000D0892  mov         ecx,38h  
000D0897  mov         eax,0CCCCCCCCh

Чтобы перенаправить вызов, просто добавьте инструкцию JMP в D0880. Мы добавляем инструкции NOP после перехода, чтобы сделать дизассемблированный вывод более чистым во время сеансов отладки. Это не обязательно, но это может пригодиться.

000D0880  jmp         NewFunction
000D0885  nop
000D0886  nop
000D0887  nop
000D0888  nop
000D0889  push        ebx  
000D088A  push        esi  
000D088B  push        edi  

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

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

typedef void (*EXTPROC)(int a, int b);

// Windows loads the dll at 0xC0000
HMODULE hMod = LoadLibrary("some.dll"); 
// The function is at offset 0x10880 (from start of text segment)
EXTPROC proc = CalculateAddress(hMod, 0x00010880);
// Call proc at 0xd0880
proc(0, 1);

Функция CalculateAddress извлекает базовый адрес DLL, вычисляет фактический адрес функции и возвращает указатель на него. Результат такой же, как и в предыдущем примере — 0xD0880. Теперь, когда у вас есть адрес, вы можете вызвать его через указатель функции. Вы можете применить ту же технику для вызова новой функции, которую вы добавляете, поскольку вы также знаете смещение этой функции.

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

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

person Captain Obvlious    schedule 26.04.2013
comment
Хороший ответ, но я только что понял, что мне действительно нужно, чтобы другая функция находилась в другой dll. Можно ли как-нибудь исправить вызов функции в другой dll? - person Lukesmith; 27.04.2013
comment
Я расширил ответ для вызова функций из внешней DLL, а также использования прокси-библиотеки DLL для вызова функции во внешнем модуле (спасибо, Рич, за предложение!) - person Captain Obvlious; 27.04.2013
comment
Чувак классный ответ. Не могли бы вы объяснить, как я могу редактировать таблицу экспорта? Кажется, это может быть хороший простой способ, так как я могу добавить интересующую меня функцию в таблицу экспорта, а затем получить к ней доступ извне. - person Lukesmith; 27.04.2013
comment
Таблица экспорта — это просто данные, хранящиеся в другом разделе PE-файла. Формат очень прост, и его можно найти в любой хорошей документации для PE-файлов. Если вы работаете с DLL (и модифицируете их), вам следует с этим ознакомиться. - person Captain Obvlious; 27.04.2013
comment
Потрясающе большое спасибо. Я так многому научился из ваших ответов. - person Lukesmith; 27.04.2013
comment
Извините, я не знал, как это работает раньше, я вернулся и принял ответы. - person Lukesmith; 28.04.2013