PDA

Просмотр полной версии : Хуки – что это такое и как с ними работать [2]


kin4stat
14.06.2021, 01:43
Хотел продолжить первый гайд, но понял что нужно объяснить что такое хуки


Создание ASI-плагина с нуля (https://www.blast.hk/threads/89122/)

Хуки – что это такое и как с ними работать (https://www.blast.hk/threads/91079/)

Безопасная инициализация и работа с SAMP (https://www.blast.hk/threads/101433/)

Работа с рендером и Directx9 (https://www.blast.hk/threads/113060/)

Обработка событий окна + ImGui (https://www.blast.hk/threads/115851/)


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

При использовании на других ресурсах необходимо указание авторства и ссылки на оригинальную темы!

Перед тем как начать:

Так как этот гайд сделан в целях обучения, здесь не будет показано использование готовых библиотек, а только сырой код.

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

Все действия производились на Visual Studio 2019 с параметром

/std:c++17

, в других версиях интерфейс может отличаться.

Все адреса указаны для SAMP R3-1, на других версиях будете ловить краши

И так, начнем:

Хук(от англ. Hook) - перехват. В нашем случае это перехват внутриигровых функций; Когда игра захочет их вызвать - будут выполняться наши действия (наш код), а затем уже можно продолжить выполнение функции, либо сразу сделать возврат, чтобы функция ничего не сделала.

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

У каждой функции есть свое соглашение о вызове. Соглашение о вызове - "Правило" которое регулирует каким образом аргументы функции будут переданы самой функции и как именно будет произведен возврат значения, а также кто будет очищать стек после вызова функции(это не полный список, но самое основное что стоит знать). Если например вызвать

cdecl

функцию указав соглашение о вызове

stdcall

, то вы получите UB(Undefined behaviour - неопределенное поведение)

В архитектуре x86 исторически сложилось, что разным людям не нравилось что-то в других соглашениях о вызове, и они создавали свои. На x64 такой бардак тоже есть, но уже между разными OC.

Существует много соглашений о вызовах, но описывать все я не буду, ибо они вам вряд ли пригодятся(

pascal

к примеру)

Мы же рассмотрим 4 соглашения о вызовах:

cdecl

,

stdcall

,

fastcall

,

thiscall


У всех соглашений аргументы передаются справа налево через стек.

cdecl является основным соглашением о вызове и используется почти везде. Возврат осуществляется через регистр eax, регистр st0 для x87, и пару регистров eax:edx для значений размером в 5-8 байт. Стек очищает тот кто вызывает функцию, поэтому cdecl поддерживает переменное число аргументов. Установлено по умолчанию в MSVC.

stdcall является основным соглашением о вызовах в Windows, а также во многих библиотеках(например basslib). Возврат осуществляется через регистр eax, очистка стека производится самой функцией. Переменное число аргументов не поддерживает.

thiscall используется для вызова методов класса. В регистр ecx кладется скрытый аргумент this, очистка стека производится самой функцией, возврат значения через регистр eax. Переменное число аргументов не поддерживает.

fastcall используется редко. В хуках зачастую используется для обхода thiscall в msvc(чуть позже расскажу что это). Первые два аргумента кладутся в регистры ecx и edx, остальные в том же порядке через стек. Очистка стека производится самой функцией. Переменное число аргументов не поддерживает. Из-за использования регистров для передачи аргументов его назвали fastcall, т.к. операции с регистрами на старых компьютерах были заметно быстрее операциями со стеком.

Теперь можно перейти к теории о хуках.

Для перехвата используются две техники - подмена вызова(call hook) и уже после вызова(в прологе) прыжок в хук.

Начнем с первого: в основном вызовы происходят по релативному адресу, но бывают и вызовы по абсолютному адресу который находится в регистре.

Релативный адрес(от англ. Relative address) - это адрес, относительно места откуда происходит вызов.

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

Наперед скажу что мы будем работать только с релативными адресами.

Покажу на примере вызова функции в GTA:SA:

C++:






.
text
:
0053E972
00
C E8
89
AE
1
D
00
call _ZN5CFont12InitPerFrameEv
;
CFont
::
InitPerFrame
(
void
)




Вызов происходит по адресу 0x53E972, вызываемая функция находится по адресу 0x719800

Но asm код выше - дизассемблированный код. В самой программе он хранится вот так:


E8 89 AE 1D 00


Как вы уже могли догадаться, размер инструкции вызова - 5 байт

E8 - опкод вызова. В asm мнемонике записывается как call

89 AE 1D 00 - Релативный адрес вызова, записанный в порядке байт little endian. Что такое порядок байт - лучше почитать на википедии (https://www.blast.hk/redirect/aHR0cHM6Ly9ydS53aWtpcGVkaWEub3JnL3dpa2kvJUQwJTlGJU QwJUJFJUQxJTgwJUQxJThGJUQwJUI0JUQwJUJFJUQwJUJBXyVE MCVCMSVEMCVCMCVEMCVCOSVEMSU4MiVEMCVCRSVEMCVCMg)

Если перевести релативный адрес в нормальное число, то получим 0x1DAE89. Откуда же вышло это число?

Оно было посчитано как разница между адреса вызова и адреса вызываемой функции. Считается по формуле: (Адрес назначения вызова/прыжка) - (Адрес вызова/прыжка) - 5



В процессоре есть специальный регистр EIP(RIP на x64). Расшифровывается как Instruction Pointer. После считывания процессором инструкции по адресу 0x53E972, Instrustion pointer смещается на 5 байт вперед(инструкция вызова имеет размер 5). А конечный адрес вызова вычисляется относительно EIP, поэтому нужно добавлять 5 байт смещения.

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

Займемся этим.

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

Перед подменой релативного адреса нужно снять защиту с секции кода приложения(защита там стоит воизбежание случайной записи в код и дальшейнего UB), а после подмены вернуть все обратно

Установка call хука:






void
*
SetCallHook
(
uintptr_t HookAddress
,
void
*
DetourFunction
)
{
uintptr_t OriginalFunction
=
*
reinterpret_cast

(
HookAddress
+
1
)
+
HookAddress
+
5
;
DWORD oldProt
;
VirtualProtect
(
reinterpret_cast

(
HookAddress
+
1
)
,
sizeof
(
uintptr_t
)
,
PAGE_READWRITE
,
&
oldProt
)
;
*
reinterpret_cast

(
HookAddress
+
1
)
=
reinterpret_cast

(
DetourFunction
)
-
HookAddress
-
5
;
VirtualProtect
(
reinterpret_cast

(
HookAddress
+
1
)
,
sizeof
(
uintptr_t
)
,
oldProt
,
&
oldProt
)
;
return
reinterpret_cast

(
OriginalFunction
)
;
}




Показывать буду на примере хука вывода сообщения в чат.

Хук будем ставить вот сюда:

Код:






.text:10067A2A 008 6A 00 push 0 ; a6
.text:10067A2C 00C C1 E8 08 shr eax, 8
.text:10067A2F 00C 0D 00 00 00 FF or eax, 0FF000000h
.text:10067A34 00C 50 push eax ; a5
.text:10067A35 010 6A 00 push 0 ; a4
.text:10067A37 014 56 push esi ; a3
.text:10067A38 018 6A 04 push 4 ; a2
.text:10067A3A 01C 8B CF mov ecx, edi ; this

.text:10067A3C 01C E8 1F FA FF FF call CChat__AddEntry ; this call will be hooked




Соглашение о вызове у нас

thiscall

(перед вызовом в ecx кладется pChat)

MSVC не дает использовать

thiscall

вне классов, поэтому мы будем эмулировать его через

fastcall

. Единственное отличие - дополнительный параметр EDX. В самой функции вы увидите его как void* EDX

Сначала напишем тело функции хука:

C++:






void
__fastcall
HOOK_AddChatMessage
(
void
*
pChat
,
void
*
EDX
,
int
nType
,
const
char
*
szText
,
const
char
*
szPrefix
,
unsigned
long
textColor
,
unsigned
long
prefixColor
)
{
std
::
cout
: "



Ну а теперь установим сам хук:

C++:





[CODE]
// Где нибудь за пределами функции
using
CChat__AddChatMessage
=
void
(
__fastcall
*
)
(
void
*
,
void
*
,
int
,
const
char
*
,
const
char
*
,
unsigned
long
,
unsigned
long
)
;
// прототип функции, взят из IDA PRO
CChat__AddChatMessage pOriginalFunction
=
nullptr
;
// Сама установка хука
if
(
uintptr_t dwSAMP
=
reinterpret_cast

(
GetModuleHandleA
(
"samp.dll"
)
)
;
dwSAMP
!=
0
)
{
pOriginalFunction
=
reinterpret_cast

(
SetCallHook
(
dwSAMP
+
0x67A3C
,
&
HOOK_AddChatMessage
)
)
;
}




Компилируем код, кидаем асишник в папку игры, устанавливаем DebugConsole (https://www.blast.hk/threads/22179/), заходим в игру и видим в консоли сообщения из чата.



1623618152617.pngkin4stat · 14 Июн 2021 в 00:43' data-fancybox="lb-post-766481" data-lb-caption-extra-html="" data-lb-sidebar-href="" data-single-image="1" data-src="https://www.blast.hk/attachments/101028/" style="cursor: pointer;" title="1623618152617.png">
https://forum.antichat.xyz/attachments/27766481/




Перейдем к jmp хукам.

jmp хуки ставятся где угодно(на самом деле call хуки тоже, но более запарно)

Для установки jmp хука требуется немного больше действий. Так как ставить мы его будем в случайном месте, не факт что там где мы будем ставить его, будет ровно 5 байт. Поэтому перед установкой хука нужно смотреть сколько байт занимают инструкции на месте установки хука. Я буду смотреть опять же на функции добавления сообщения в чат. Переходим в пролог(начало) функции и смотрим на ассемблерный код:

Код:






.text:10067460 000 55 push ebp
.text:10067461 004 56 push esi
.text:10067462 008 8B E9 mov ebp, ecx
.text:10067464 008 57 push edi




И видим что у нас тут 4 опкода занимающих ровно 5 байт. Но если вам не повезет как тут, то нужно брать в большую сторону.

Например тут, нужно будет взять 6 байт.

Код:






.text:10067478 00C 8B 74 24 18 mov esi, [esp+0Ch+a4]
.text:1006747C 00C 85 F6 test esi, esi




Идем дальше. Если мы просто затрем код по адресу, то у нас все сломается. Поэтому перед тем как ставить сам хук, нужно скопировать оригинальный код.

Пишем функцию для установки jmp хука(опкод у JMP - E9):

C++:






void
*
SetJmpHook
(
uintptr_t HookAddress
,
size_t HookSize
,
void
*
DetourFunction
)
{
void
*
Trampoline
=
VirtualAlloc
(
0
,
HookSize
+
5
,
MEM_COMMIT
|
MEM_RESERVE
,
PAGE_EXECUTE_READWRITE
)
;
// Аллоцируем память для трамплина
if
(
Trampoline
)
{
uintptr_t TrampolineJmpBack
=
reinterpret_cast

(
Trampoline
)
+
HookSize
;
memcpy
(
Trampoline
,
reinterpret_cast

(
HookAddress
)
,
HookSize
)
;
// Копируем оригинальные байты в трамплин
DWORD oldProt
;
VirtualProtect
(
reinterpret_cast

(
HookAddress
)
,
HookSize
,
PAGE_READWRITE
,
&
oldProt
)
;
memset
(
reinterpret_cast

(
HookAddress
)
,
0x90
,
HookSize
)
;
// Заполняем место хука нопами(чтобы не ломать листинг ассемблера)
*
reinterpret_cast

(
HookAddress
)
=
0xE9
;
// Ставим опкод прыжка
*
reinterpret_cast

(
HookAddress
+
1
)
=
reinterpret_cast

(
DetourFunction
)
-
HookAddress
-
5
;
// Ставим релативный адрес для прыжка в функцию обработчик хука
VirtualProtect
(
reinterpret_cast

(
HookAddress
)
,
HookSize
,
oldProt
,
&
oldProt
)
;
*
reinterpret_cast

(
TrampolineJmpBack
)
=
0xE9
;
// Ставим в конец трамплина прыжок обратно
// Ставим релативный адрес для прыжка обратно в функцию для продолжения выполнения
*
reinterpret_cast

(
TrampolineJmpBack
+
1
)
=
(
HookAddress
+
HookSize
)
-
TrampolineJmpBack
-
5
;
return
Trampoline
;
}
return
nullptr
;
}




В конец трамплина мы добавляем прыжок обратно, чтобы продолжить выполнение и ничего не сломать

Теперь пишем обработчик хука:

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

C++:






void
HOOK_AddChatMessage
(
void
*
pChat
,
int
nType
,
const
char
*
szText
,
const
char
*
szPrefix
,
unsigned
long
textColor
,
unsigned
long
prefixColor
)
{
std
::
cout
: "



Вероятно посмотрев на код вы ничего не поняли. Сейчас объясню.

Т.к. теперь телом хука выступает функция HOOK_Raw_AddChatMessage и из нее мы вызываем наш обработчик, т.к. вызов делаем мы сами, то
[CODE]
__fastcall

и прочие заморочки в обработчике не нужны


__declspec(naked)

указывает компилятору на то что не нужно генерировать код на входе и выходе из функции - мы сделаем это сами

pushad и popad нужны для сохранения и возврата в исходное состояние регистров. Т.к. мы указали компилятору не генерировать код на входе и выходе, то сохранять регистры некому, поэтому делаем это вручную.

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

Теперь устанавливаем сам хук. Ставить будем тут:

Код:






.text:10067460 000 55 push ebp
.text:10067461 004 56 push esi
.text:10067462 008 8B E9 mov ebp, ecx
.text:10067464 008 57 push edi




C++:






// Где-то вне функций
void
*
pOriginalFunction
=
nullptr
;
// Сама установка хука:
if
(
uintptr_t dwSAMP
=
reinterpret_cast

(
GetModuleHandleA
(
"samp.dll"
)
)
;
dwSAMP
!=
0
)
{
SetJmpHook
(
dwSAMP
+
0x67460
,
5
,
&
HOOK_Raw_AddChatMessage
)
;
}




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




https://forum.antichat.xyz/attachments/27766481/

trefa
14.06.2021, 02:16
Хук(от англ. Hook) - перехват


Ловушка/Крюк. Но больше подходит слово ловушка*

kin4stat
14.06.2021, 02:39
наконец то ты запилил гайд по хукам


Хотел сначала сделать вторую часть гайда, но потом понял что про хуки надо рассказать перед этим



У меня мозг закипел...


У меня у самого закипел пока гайд писал

manukhov
14.06.2021, 14:14
защита там стоит воизбежание случайной записи в код и дальшейнего UB


что такое UB

#Rin
14.06.2021, 14:21
что такое UB


Undefined Behaviour (https://www.blast.hk/redirect/aHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVW5kZWZpbm VkX2JlaGF2aW9y) (Неопределённое поведение (https://www.blast.hk/redirect/aHR0cHM6Ly9ydS53aWtpcGVkaWEub3JnL3dpa2kvJUQwJTlEJU QwJUI1JUQwJUJFJUQwJUJGJUQxJTgwJUQwJUI1JUQwJUI0JUQw JUI1JUQwJUJCJUQxJTkxJUQwJUJEJUQwJUJEJUQwJUJFJUQwJU I1XyVEMCVCRiVEMCVCRSVEMCVCMiVEMCVCNSVEMCVCNCVEMCVC NSVEMCVCRCVEMCVCOCVEMCVCNQ))

kin4stat
14.06.2021, 15:28
что такое UB


Невнимательно читаешь



UB(Undefined behaviour - неопределенное поведение)

SR_team
14.06.2021, 23:27
Но больше подходит слово ловушка*


А мне кажется, что крюк подходит больше

Ловушка больше подходит для UEF-хуков, но они медленные

kin4stat
08.07.2021, 14:09
86?



x87 FPU - Recherche Google (https://www.blast.hk/redirect/aHR0cHM6Ly9nb29nbGUuY29tL3NlYXJjaD9xPXg4NytGUFU)

Akat
08.07.2021, 14:19
Дайте ссылку на 1 тему, я не могу найти

manukhov
08.07.2021, 14:27
x87 FPU - Recherche Google (https://www.blast.hk/redirect/aHR0cHM6Ly9nb29nbGUuY29tL3NlYXJjaD9xPXg4NytGUFU)


да емае, я нашел почти сразу)

Fott
08.07.2021, 14:48
Дайте ссылку на 1 тему, я не могу найти



Гайд - Создание ASI-плагина с нуля [1] (https://www.blast.hk/threads/89122/)

Делать мне было нечего, а работать не хотелось, поэтому вы видите этот гайд Создание ASI-плагина с нуля Хуки – что это такое и как с ними работать Безопасная инициализация и работа с SAMP Работа с рендером и Directx9 Обработка событий окна + ImGui В этом гайде мы создадим свой ASI-плагин с...

www.blast.hk

Yuriy Code
05.03.2022, 05:48
Сложно очень... 🙁

x0r1x
05.03.2022, 17:29
Сложно очень... 🙁


это легко, просто луашеру который до этого вызывал функции, будет не просто их писать

Yuriy Code
10.09.2022, 11:55
Код:






.text:10067460 000 55 push ebp
.text:10067461 004 56 push esi
.text:10067462 008 8B E9 mov ebp, ecx
.text:10067464 008 57 push edi




И видим что у нас тут 4 опкода занимающих ровно 5 байт. Но если вам не повезет как тут, то нужно брать в большую сторону.
Например тут, нужно будет взять 6 байт.


Как ты узнал, что опкоды по 5 байт?

Расскажи, как ты посчитал это. Ибо, вообще нихуя не понятно.

RazorRw
10.09.2022, 12:13
Как ты узнал, что опкоды по 5 байт?
Расскажи, как ты посчитал это. Ибо, вообще нихуя не понятно.


там же написаны байты. 0x55, 0x56, 0x8B, 0xE9, 0x57 и всего их 5 в этом отрезке кода

Yuriy Code
10.09.2022, 12:14
там же написаны байты. 0x55, 0x56, 0x8B, 0xE9, 0x57 и всего их 5 в этом отрезке кода


Сложнооооооооооооо... ☹️😫

F0RQU1N and
10.09.2022, 12:48
Сложнооооооооооооо... ☹️😫



https://forum.antichat.xyz/attachments/28142336/

не дописал, четвёртый*

Yuriy Code
10.09.2022, 14:55
не дописал, четвёртый*


Да я уже понял, но, всё-равно сложно очень.

Yuriy Code
11.09.2022, 20:25
uintptr_t OriginalFunction = *reinterpret_cast(HookAddress + 1) + HookAddress + 5;


Что за дичь...

Зачем ты сложил адрес хука???

HookAddress + HookAddress... ЗАЧЕМ??? Если нужно вычесть. Но, Киня же сделал зачем-то наоборот...

Как мне быть, если я ничего не понимаю... 😭

sc6ut
13.09.2022, 18:26
Что за дичь...
Зачем ты сложил адрес хука???
HookAddress + HookAddress... ЗАЧЕМ??? Если нужно вычесть. Но, Киня же сделал зачем-то наоборот...

Как мне быть, если я ничего не понимаю... 😭


так, для начала хватит давать эти уебищные прозвища, заебал и не только меня. итак, к делу:

опкод jmp, размер которой 5 (x86), прыгает на определенное место в коде и она является релативной, то есть на сколько прыгнуть ПОСЛЕ себя.

например ты на адрес 10 и тебе надо прыгнуть на адрес 20. чтобы это сделать воспользуемся jmp. подводя итог прошлому абзацу, после инструкции jmp адрес будет 15 (т.к её размер 5) соотвественно нам нужно прыгнуть еще на 5. как это вычислить математически? jmp {куда надо}20-{откуда}10-{размер инструкции}5=5, то есть jmp 5.

так же работает и call, но она делает ещё несколько действий кроме прыжка.

с этим разобрались.

теперь, то что ты процитировал, kin4stat берет адрес оригинальной функции (для дальнейшего её вызова чтобы не прерывать flow программы) из существующей инструкции call/jmp (не читал контекст).

пользуясь знаниями из прошлого абзаца, зная как устроена инструкция jmp (JMP ADDR), то на 0 месте находится опкод, а на 1-4 сам РЕЛАТИВНЫЙ адресс.

возьмем пример из прошлого абзаца: jmp 5 на адресе 10, соотвественно после этой инструкции программа будет на адресе 20, его нам и нужно достать.

addr = {размер прыжка}5+{текущий адрес}10+{размер инструкции jmp}5=20.

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

вроде все понятно, не перечитывал да и по***

Yuriy Code
13.09.2022, 18:37
{куда надо}20-{откуда}10-{размер инструкции}5=5


Скаут, (20 - 10) - 5 = 5, либо

20 - (10 - 5) = 15...

У нас в итоге не получается адрес равному 20...

sc6ut
13.09.2022, 18:39
Скаут, (20 - 10) - 5 = 5, либо
20 - (10 - 5) = 15...

У нас в итоге не получается адрес равному 20...


ты скобки сам себе в голове придумал? перечитай как jmp работает, должно получится 5

Yuriy Code
13.09.2022, 18:42
ты скобки сам себе в голове придумал? перечитай как jmp работает, должно получится 5


😱, Скаут, но тогда jmp будет на адрес 5...

sc6ut
13.09.2022, 18:48
😱, Скаут, но тогда jmp будет на адрес 5...





она является релативной, то есть на сколько прыгнуть ПОСЛЕ себя.


ебаный рот читать научись я просто вахуе нет слов

15(адрес после jmp)+5(на сколько прыгнуть)=20

ARMOR
09.11.2022, 11:18
У меня одного jmp хук вызывает краш при запуске игры? В консоль выводится только первое сообщение сампа, и дальше моментальный краш.

maksmanus228
08.08.2024, 17:19
void* SetCallHook(uintptr_t HookAddress, void* DetourFunction) {

uintptr_t OriginalFunction = *reinterpret_cast(HookAddress + 1) + HookAddress + 5;

DWORD oldProt;

VirtualProtect(reinterpret_cast(HookAddress + 1), sizeof(uintptr_t), PAGE_READWRITE, &oldProt);

*reinterpret_cast(HookAddress + 1) = reinterpret_cast(DetourFunction) - HookAddress - 5;

VirtualProtect(reinterpret_cast(HookAddress + 1), sizeof(uintptr_t), oldProt, &oldProt);

return reinterpret_cast(OriginalFunction);

}

а причем тут хук адрес + 1 Откуда взялась единица? объясните пожалуйста

fuflexxxx
09.08.2024, 01:09
void* SetCallHook(uintptr_t HookAddress, void* DetourFunction) {
uintptr_t OriginalFunction = *reinterpret_cast(HookAddress + 1) + HookAddress + 5;
DWORD oldProt;
VirtualProtect(reinterpret_cast(HookAddress + 1), sizeof(uintptr_t), PAGE_READWRITE, &oldProt);
*reinterpret_cast(HookAddress + 1) = reinterpret_cast(DetourFunction) - HookAddress - 5;
VirtualProtect(reinterpret_cast(HookAddress + 1), sizeof(uintptr_t), oldProt, &oldProt);
return reinterpret_cast(OriginalFunction);
}

а причем тут хук адрес + 1 Откуда взялась единица? объясните пожалуйста


Инструкции Call/Jmp работают через переход по RVA, Инструкция состоит из байтов E8/E9 + 4 байта на RVA. Т.е HookAddress - это адрес, где будут байты примерно такие E8 05 00 00 00 - в данном примере будет вызвана функция по адресу текущему + 0x5, и получается, что HookAdress + 1 - это байты rva. Они обычно кастуются к типу 4 байта и туда пишется своё значение.

maksmanus228
26.08.2024, 14:16
Инструкции Call/Jmp работают через переход по RVA, Инструкция состоит из байтов E8/E9 + 4 байта на RVA. Т.е HookAddress - это адрес, где будут байты примерно такие E8 05 00 00 00 - в данном примере будет вызвана функция по адресу текущему + 0x5, и получается, что HookAdress + 1 - это байты rva. Они обычно кастуются к типу 4 байта и туда пишется своё значение.


а понял, спасибо большое