Подключение - hotpatching
Я пытаюсь подключить функцию Windows API FindWindowA(). Я успешно сделал это с помощью приведенного ниже кода без "горячей" установки: я переписал байты в начале функции. myHook() вызывается, и появляется окно сообщения, когда вызывается FindWindowA().
В user32.dll включена горячая установка, и я хотел бы перезаписать NOP перед самой функцией, а не перезаписывать саму функцию. Однако приведенный ниже код не будет работать, когда я установлю горячее исправление на TRUE. Это ничего не делает, когда FindWindowA () выполняется.
#include <stdio.h>
#include <windows.h>
void myHook()
{
MessageBoxA(NULL, "Hooked", "Hook", MB_ICONINFORMATION);
}
int main(int argc, char *argv[])
{
BOOLEAN hotpatching = FALSE;
LPVOID fwAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "FindWindowA");
LPVOID fwHotpatchingAddress = (LPVOID)((DWORD)fwAddress - 5);
LPVOID myHookAddress = &myHook;
DWORD jmpOffset = (DWORD)&myHook - (DWORD)(!hotpatching ? fwAddress : fwHotpatchingAddress) - 5; // -5 because "JMP offset" = 5 bytes (1 + 4)
printf("fwAddress: %X\n", fwAddress);
printf("fwHotpatchingAddress: %X\n", fwHotpatchingAddress);
printf("myHookAddress: %X\n", myHookAddress);
printf("jmpOffset: %X\n", jmpOffset);
printf("Ready?\n\n");
getchar();
char JMP[1] = {0xE9};
char RETN[1] = {0xC3};
LPVOID offset0 = NULL;
LPVOID offset1 = NULL;
LPVOID offset2 = NULL;
if (!hotpatching)
offset0 = fwAddress;
else
offset0 = fwHotpatchingAddress;
offset1 = (LPVOID)((DWORD)offset0 + 1);
offset2 = (LPVOID)((DWORD)offset1 + 4);
DWORD oldProtect = 0;
VirtualProtect(offset0, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(fwAddress, JMP, 1);
memcpy(offset1, &jmpOffset, 4);
memcpy(offset2, RETN, 1);
VirtualProtect(offset0, 6, oldProtect, &oldProtect);
printf("FindWindowA() Patched");
getchar();
FindWindowA(NULL, "Test");
getchar();
return 0;
}
Не могли бы вы сказать мне, что не так?
Спасибо.
1 ответ
Компилятор и компоновщик готовят исполняемые образы с поддержкой "горячей" установки, чтобы можно было заменить изображение во время использования. Применяются следующие два изменения (x86):
- Точка входа в функцию настроена на 2-байтовое бездействие
mov edi, edi
( / hotpatch). - Пять последовательных nop'ов добавляются к каждой точке входа функции ( / FUNCTIONPADMIN).
Чтобы проиллюстрировать это, вот типичный список разборки функции с поддержкой горячего кэширования:
(2) 768C8D66 90 nop
768C8D67 90 nop
768C8D68 90 nop
768C8D69 90 nop
768C8D6A 90 nop
(1) 768C8D6B 8B FF mov edi,edi
(3) 768C8D6D 55 push ebp
768C8D6E 8B EC mov ebp,esp
(1)
обозначает точку входа в функцию с 2-байтовым запретом на операцию. (2)
является дополнением, предоставленным компоновщиком, и (3)
где начинается реализация нетривиальной функции.
Чтобы подключиться к функции, вы должны переписать (2)
с прыжком к вашей функции крючка jmp myHook
и сделать этот код доступным, заменив (1)
с относительным прыжком jmp $-5
,
Функция ловушки должна оставлять стек в согласованном состоянии. Должен быть объявлен как __declspec(naked)
чтобы компилятор не генерировал пролог функции и код эпилога. Последняя инструкция должна либо выполнить очистку стека в соответствии с соглашением о вызовах перехваченной функции, либо вернуться к перехваченной функции по адресу, указанному (3)
,