Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Dll хук (перехват) метода EnumDevices интерфейса DirectInput8 [Delphi]


smakss   (21.12.18 02:03

Привет. Поставил себе задачу скрытия от DirectInput приложения игровых устройств. Написал перекрывающую библиотеку "dinput8.dll". Но после вызова метода EnumDevices из игрового приложения и вывода сообщения "Hook Work!" выдаётся Accees violation. Никак не пойму почему.


library dinput8;
uses Windows, Classes;

type
 TDirectInput8 = class
   //function CreateDevice(const rguid: TGUID; out lplpDirectInputDevice: IDirectInputDevice8A; pUnkOuter: IUnknown): HResult; virtual; stdcall; abstract;
   function EnumDevices (dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): HResult; virtual; stdcall; abstract;
   //function GetDeviceStatus(const rguidInstance: TGUID): HResult; virtual; stdcall; stdcall; abstract;
   //function RunControlPanel(hwndOwner: HWND; dwFlags: DWORD): HResult; virtual; stdcall; abstract;
   //function Initialize(hinst: THandle; dwVersion: DWORD): HResult; virtual; stdcall; abstract;
   //function FindDevice(const rguidClass: TGUID; ptszName: PAnsiChar; out pguidInstance: TGUID): HResult; virtual; stdcall; abstract;
   //function EnumDevicesBySemantics(ptszUserName: PAnsiChar; const lpdiActionFormat: TDIActionFormatA; lpCallback: TDIEnumDevicesBySemanticsCallbackA; pvRef: Pointer; dwFlags: DWORD): HResult; virtual; stdcall; abstract;
   //function ConfigureDevices(lpdiCallback: TDIConfigureDevicesCallback; const lpdiCDParams: TDIConfigureDevicesParamsA; dwFlags: DWORD; pvRefData: Pointer): HResult; virtual; stdcall; abstract;
 end;

// Замена методов по указателям в памяти
function ReplaceMethod(pTargetAddr: Pointer; pNewAddr: Pointer; var pOrigAddr: Pointer): Boolean;
type
 TJumP = packed record // Смещение на другой метод
   bJmp: Byte;
   dwAddress: DWord;
 end;

var
 dwLength: Cardinal;
 gJump: TJump;
 dwProtect: DWord;

 // Получить размер памяти, занимаемой методом
 function getMethodSize(MPtr: Pointer): Integer;
 const MAX_SIZE = 5000;
 var
   ch: Byte;
   i: Integer;
 begin
   i := 0; Result := 0;
   repeat
     CopyMemory(@ch, Ptr(DWORD(MPtr)+i), 1);
     inc(i);
   until (ch = $C3) or (i >= MAX_SIZE);
   if i < MAX_SIZE then Result := i;
 end;

begin Result := False;
 dwLength := getMethodSize(pTargetAddr);

 // Сохранить код старого метода
 pOrigAddr := GetMemory(dwLength); // Выделить память для оригинального метода
 CopyMemory(pOrigAddr, pTargetAddr, dwLength); // Скопировать оригинальный метод в новое место

 gJump.bJmp := $E9;
 gJump.dwAddress := DWord(pNewAddr) - DWord(pTargetAddr) - 5;

 // Изменить участок памяти текущего процесса
 if VirtualProtectEx(GetCurrentProcess(), pTargetAddr, dwLength, PAGE_READWRITE, dwProtect) then begin
   CopyMemory(pTargetAddr, @gJump, sizeOf(TJump)); // Поменять вместо оригинального метода смещение на другой метод
   VirtualProtectEx(GetCurrentProcess(), pTargetAddr, dwLength, dwProtect, dwProtect);
   Result := True;
 end;
end;

// *****************************************************************************

var
 DirectInput8CreateOrig: function (hinst: THandle; dwVersion: DWORD; const riidltf: TGUID; out ppvOut{: Pointer}; punkOuter: IUnknown): HResult; stdcall; // external 'dinput8.dll' Name 'DirectInput8Create';
 DInput: TDirectInput8;
 EnumOrig: function (dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): HResult; stdcall;

// Заменяемый хук-метод перечисления устройств через DirectInput
function EnumDevices(dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): HResult; stdcall;
begin
   MessageBox(0, 'Hook Work!', nil, 0);
   Result := 0;
   //Result := EnumOrig(dwDevType, lpCallback, pvRef, dwFlags);
end;

// Перекрытие создания главного объекта DirectInput
function DirectInput8Create(hinst: THandle; dwVersion: DWORD; const riidltf: TGUID; var ppvOut: Pointer; punkOuter: IUnknown): HResult; stdcall;
var
 LibHandle: THandle;
 PrcAddr:   Pointer;

 addr_proc: function (dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): HResult of object; stdcall;

begin
 Result := 0; PrcAddr := nil;

 LibHandle := LoadLibrary('C:\Windows\System32\dinput8.dll');
 if LibHandle <> 0 then begin
   PrcAddr := GetProcAddress(LibHandle, 'DirectInput8Create');
   if PrcAddr <> nil then begin
     DirectInput8CreateOrig := PrcAddr;
     Result := DirectInput8CreateOrig(hinst, dwVersion, riidltf, ppvOut, punkOuter);

     DInput := ppvOut;
     addr_proc := DInput.EnumDevices;

     ReplaceMethod(@addr_proc, @EnumDevices, PrcAddr);
     EnumOrig := PrcAddr;

   end;
   //FreeLibrary(LibHandle);
 end;
end;

Exports DirectInput8Create;
begin
end.


Rouse_ ©   (21.12.18 11:12[1]

// Скопировать оригинальный метод в новое место

Молодец, а ничего что там релоки, которые тоже править надо? Да и RET (0xC3) их несколько может быть ибо ветвления. Да и новый код, который ты переместил должен быть на странице с PAGE_EXECUTE правами


Rouse_ ©   (21.12.18 11:24[2]

ЗЫ: я уж не говорю что выходы могут быть сразу с правкой стека типа
75B1B23B: C2 04 00                                   RET 0x4
75B1B2DA: C2 08 00                                   RET 0x8
75B1B496: C2 0C 00                                   RET 0xC
75B1B9B1: C2 20 00                                   RET 0x20


Rouse_ ©   (21.12.18 11:29[3]

В частности в твоем случае пролог функции выглядит вот так, обрати внимание на опкоды инструкций слева:

                                         loc_C34CE2C:            ; DllRelease()
E8 A6 F9 FF FF                            call    _DllRelease@0
8B 4D FC                                  mov     ecx, [ebp+var_4]
8B 85 E8 FC FF FF                         mov     eax, [ebp+var_318]
5F                                        pop     edi
5E                                        pop     esi
33 CD                                     xor     ecx, ebp
5B                                        pop     ebx
E8 2E 1E 01 00                            call    @__security_check_cookie@4 ; __security_check_cookie(x)
C9                                        leave
C2 14 00                                  retn    14h
                                         _DirectInput8Create@20 endp


smakss   (21.12.18 14:55[4]

Благодарю за помощь. Я, к сожалению, ещё не работаю на таком уровне отладки. И ассемблер почти не знаю. Поэтому и спросил на форуме. Даже если закомментировать часть кода копирования оригинального метода и просто затереть его, всё равно выдаётся ошибка Accees violation.

Ниже прикладываю простой пример опроса устройств и подмены метода опроса с ошибкой. Может, кому удастся исправить и пояснить.
https://drive.google.com/file/d/1wdaZ_jSvx5MI0xaFXhi6cB41Dq6x776t/view


smakss   (21.12.18 15:17[5]

Раз очень сложно перенести оригинальный метод в новый участок памяти, то может есть способ заменить указатель на сам метод, вроде:
DInput8.EnumDevices := @MyEnumDevices?


Rouse_ ©   (21.12.18 15:58[6]

Изучи вот эти две статьи, должны дать общее представление к подходу:
https://habr.com/post/178393/
https://habr.com/post/181157/

Грубо, копировать тело функции тебе не нужно, достаточно организовать трамплин описанный во второй статье + общая метода в седьмой главе первой статьи.


smakss   (21.12.18 18:21[7]

Сейчас попробовал несколько способов через Detours (https://github.com/MahdiSafsafi/delphi-detours-library) и тоже получил Accees violation. Я понял так, что у меня проблема с точным определением позиции метода EnumDevices в памяти COM интерфейса IDirectInput8.

Кто-то решал похожую проблему (https://www.unknowncheats.me/forum/c-and-c/153692-send-keys-game-directinput-hook.html) но только с методом GetDeviceState, а искал он этот метод COM-интерфейса в памяти через расчёт смещения от метода DirectInput8Create. То есть всё совсем не так просто, как начал делать я.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо