-
Привет. Поставил себе задачу скрытия от DirectInput приложения игровых устройств. Написал перекрывающую библиотеку "dinput8.dll". Но после вызова метода EnumDevices из игрового приложения и вывода сообщения "Hook Work!" выдаётся Accees violation. Никак не пойму почему.
library dinput8;
uses Windows, Classes;
type
TDirectInput8 = class
function EnumDevices (dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): 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; punkOuter: IUnknown): HResult; stdcall; DInput: TDirectInput8;
EnumOrig: function (dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): HResult; stdcall;
function EnumDevices(dwDevType: DWORD; lpCallback: Pointer; pvRef: Pointer; dwFlags: DWORD): HResult; stdcall;
begin
MessageBox(0, 'Hook Work!', nil, 0);
Result := 0;
end;
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;
end;
end;
Exports DirectInput8Create;
begin
end.
-
// Скопировать оригинальный метод в новое место
Молодец, а ничего что там релоки, которые тоже править надо? Да и RET (0xC3) их несколько может быть ибо ветвления. Да и новый код, который ты переместил должен быть на странице с PAGE_EXECUTE правами
-
ЗЫ: я уж не говорю что выходы могут быть сразу с правкой стека типа
75B1B23B: C2 04 00 RET 0x4 75B1B2DA: C2 08 00 RET 0x8 75B1B496: C2 0C 00 RET 0xC 75B1B9B1: C2 20 00 RET 0x20
-
В частности в твоем случае пролог функции выглядит вот так, обрати внимание на опкоды инструкций слева: 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
-
Благодарю за помощь. Я, к сожалению, ещё не работаю на таком уровне отладки. И ассемблер почти не знаю. Поэтому и спросил на форуме. Даже если закомментировать часть кода копирования оригинального метода и просто затереть его, всё равно выдаётся ошибка Accees violation. Ниже прикладываю простой пример опроса устройств и подмены метода опроса с ошибкой. Может, кому удастся исправить и пояснить. https://drive.google.com/file/d/1wdaZ_jSvx5MI0xaFXhi6cB41Dq6x776t/view
-
Раз очень сложно перенести оригинальный метод в новый участок памяти, то может есть способ заменить указатель на сам метод, вроде:
DInput8.EnumDevices := @MyEnumDevices ?
-
-
|