Может быть проще просто пропатчить исполняемый модуль. Добавьте новый код в конец текстового сегмента и поместите переход к добавленному коду в начало старой функции. Таким образом, вам не придется иметь дело с проблемами, которые может вызвать декомпилированная версия 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