Довольно простой код реализующеий перехват через сплайсинг.
Принцип работы этого чуда таков:
1) проверяется ровное кол-во команда по адресу функции которую ты собираешься перехватывать. Чтобы точно знать что там не стоит чьихто уже хуков ну и проверка на версию ядра такаяже. Это всё делает CheckFunctionBytesNtDeviceIoControlFile
2) DetourFunctionNtDeviceIoControlFile как раз делает подменяет первое целое кол-во команд на адерс перехода на твою функцию.
ТАм reentry_address будет содержать адрес кода который идет после этих команд
Тебе достаточно только 7 байт подменить (чтобы засунуть свой jmp)
Вот к примеру есть у тебя
Код:
nt!NtDeviceIoControlFile:
8058efad 8bff mov edi,edi
8058efaf 55 push ebp
8058efb0 8bec mov ebp,esp
8058efb2 6a01 push 1
8058efb4 ff752c push dword ptr [ebp+2Ch] <-------reentry_address будет ссылатьс яна этоместо
8058efb7 ff7528 push dword ptr [ebp+28h]
То заменим 7 байт на JMP на твою функцию
8058efad ea3806c4850800 jmp 0008:85C40638
8058efb4 ff752c push dword ptr [ebp+2Ch]
8058efb7 ff7528 push dword ptr [ebp+28h]
И теперь при выполненнии данной функции управление перейдет по твоему адресу.
Затем ты чтото делает в своём обработчики. Далее тебе нужно выполнить команды которые ты затер. Вот там как раз и видно где они выполняются.
А далее идет переход на reentry_address. Причем оформлено это в виде
Код:
_emit 0xEA
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0x08
_emit 0x00
3) non_paged_memory = ExAllocatePool(NonPagedPool, 256); ты юзаешь чтобы выделить память гденить в ядре, скопировать туда свой код обработчика. т.к. память доступка для записи, то тымета в обработчике где стояли _emit забиваешь адресов содержащимся в reentry_address и в этоге конец обработчика выглядит как
JMP XXXX:XXXXXXXX
Выделяется память только для того чтобы хук работал после выгрузки драйвера, ну и также чтобы была возможность записать вконце JMP на оригенальное продолжение функии которую ты перехватываешь