Процесс хуков функций C++

Рейтинг: 2Ответов: 1Опубликовано: 19.01.2023

По мере изучения хуков C++, у меня произошел некий диссонанс с механикой этих самых хуков. Хотя у меня и есть чувство что это очень глупый вопрос, однако...

Ниже необходимый код перехвата функции CreateFileA.


#pragma pack(push, 1)
struct jump_near {
    BYTE opcode;
    DWORD relativeAddress;
};
#pragma pack(pop)

int main() {
    HMODULE hMod = GetModuleHandleA("kernel32.dll");
    if(!hMod) return 1;

    jump_near* lpFunc = reinterpret_cast<jump_near*>(GetProcAddress(hMod, "CreateFileA"));

    DWORD dwProtect = PAGE_READWRITE;
    VirtualProtect(lpFunc, sizeof(jump_near), dwProtect, &dwProtect);

    lpFunc->opcode = 0xE9;
    lpFunc->relativeAddress = _CalculateDispacement(lpFunc, &_My_CreateFileA);

    VirtualProtect(lpFunc, sizeof(jump_near), dwProtect, &dwProtect);

    HANDLE hFile = CreateFileA("C:\\test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    CloseHandle(hFile);

    return 0;
}

Некоторые уточнения по функциям, чтобы не вставлять полный код в целях чистоты.
* CalculateDispacement - вычисляет относительный адрес посредством secondAddress - (firstAddress+5)
*_My_CreateFileA - выполняет MessageBox


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

  1. Но когда именно происходит этот прыжок, в какой момент?
  2. Как я читал "#pragma pack(push,1) 'some code here' #pragma pack(pop)" производит некое выравнивание структур, тоже непонятное для меня действие.
  3. Почему производится каст lpFunc в jump_near*?

Я находил ответы на некоторые свои вопросы, но они были неполными. На MSDN достаточно абстрактные определения и объяснения, поэтому ищу помощи тут.

Ответы

▲ 3Принят

#pragma pack убирает отступы (padding) между полями внутри структуры. Без него размер структуры был бы 8, а не 5 - три неиспользованных байта между opcode и relativeAddress.

Компилятор старается ставить целочисленные переменные на адреса, кратные их размеру. На каких-то архитектурах это жесткое требование, а на каких-то нарушение только замедляет доступ к переменным. x86 (которые стоят в обычных ПК) относятся к последним.


Почему производится каст lpFunc в jump_near*?

По адресу функции лежат некоторые процессорные инструкции.

Чтобы ее хукнуть, надо заменить их на свои. Не обязательно копировать по этому адресу всю свою функцию, если можно просто воткнуть туда команду "продолжить выполнение с такого-то адреса". Видмио E9 - она и есть, а сразу за ней (поэтому pragma pack) должен идти относительный адрес.


когда именно происходит этот прыжок, в какой момент?

Когда вызываются ваши свежевставленные инструкции, т.е. когда кто-то вызывает хукнутую функцию, что заставляет выполнение перейти на адрес, куда вы их записали.