ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Хуки – что это такое и как с ними работать [2] (https://forum.antichat.xyz/showthread.php?t=1391079)

kin4stat 14.06.2021 01:43

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

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

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

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

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

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

Все действия производились на 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. Что такое порядок байт - лучше почитать на википедии

Если перевести релативный адрес в нормальное число, то получим 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++:





[CODE]
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++:





Код:

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

Цитата:

Сообщение от Спойлер

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++:





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



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

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

__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, а не одно из ее использований

Цитата:

Сообщение от Спойлер


trefa 14.06.2021 02:16

Цитата:

Сообщение от KiN4StAt

Хук(от англ. Hook) - перехват

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

kin4stat 14.06.2021 02:39

Цитата:

Сообщение от stereoliza

наконец то ты запилил гайд по хукам

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

Цитата:

Сообщение от ARMOR

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

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

manukhov 14.06.2021 14:14

Цитата:

Сообщение от KiN4StAt

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

что такое UB

#Rin 14.06.2021 14:21

Цитата:

Сообщение от T4yz1e

что такое UB

Undefined Behaviour (Неопределённое поведение)

kin4stat 14.06.2021 15:28

Цитата:

Сообщение от T4yz1e

что такое UB

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

Цитата:

Сообщение от KiN4StAt

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


SR_team 14.06.2021 23:27

Цитата:

Сообщение от trefa

Но больше подходит слово ловушка*

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

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

kin4stat 08.07.2021 14:09

Цитата:

Сообщение от T4yz1e

86?

x87 FPU - Recherche Google

Akat 08.07.2021 14:19

Дайте ссылку на 1 тему, я не могу найти

manukhov 08.07.2021 14:27

Цитата:

Сообщение от KiN4StAt

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

Fott 08.07.2021 14:48

Цитата:

Сообщение от Akat

Дайте ссылку на 1 тему, я не могу найти

Гайд - Создание ASI-плагина с нуля [1]

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

www.blast.hk

Yuriy Code 05.03.2022 05:48

Сложно очень... 🙁

x0r1x 05.03.2022 17:29

Цитата:

Сообщение от Yuriy Code

Сложно очень... 🙁

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

Yuriy Code 10.09.2022 11:55

Цитата:

Сообщение от kin4stat

Код:





Код:

.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

Цитата:

Сообщение от Yuriy Code

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

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

Yuriy Code 10.09.2022 12:14

Цитата:

Сообщение от Heroku

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

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

F0RQU1N and 10.09.2022 12:48

Цитата:

Сообщение от Yuriy Code

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

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

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

Yuriy Code 10.09.2022 14:55

Цитата:

Сообщение от F0RQU1N and

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

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

Yuriy Code 11.09.2022 20:25

Цитата:

Сообщение от kin4stat

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

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

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

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

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

sc6ut 13.09.2022 18:26

Цитата:

Сообщение от Yuriy Code

Что за дичь...
Зачем ты сложил адрес хука???
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

Цитата:

Сообщение от sc6ut

{куда надо}20-{откуда}10-{размер инструкции}5=5

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

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

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

sc6ut 13.09.2022 18:39

Цитата:

Сообщение от Yuriy Code

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

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

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

Yuriy Code 13.09.2022 18:42

Цитата:

Сообщение от sc6ut

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

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

sc6ut 13.09.2022 18:48

Цитата:

Сообщение от Yuriy Code

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

Цитата:

Сообщение от sc6ut

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

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

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

Цитата:

Сообщение от maksmanus228

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

Цитата:

Сообщение от fuflexxxx

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

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


Время: 12:42