Rzadko pytam, ale cóż, może tym razem znajdzie się ktoś kto będzie w stanie mi pomóc.
Wpadłem na pomysł, aby przechwytywać wysyłane do Opery klawisze i przerabiać je tak, żebym pisał jak pokemony (przydatne do trollingu). Ale ponieważ lubię się przy okazji czegoś nauczyć, postanowiłem że sam sobie napiszę program który będzie przechwytywać input wysyłany do Opery, przerabiać go zgodnie z moimi wytycznymi i przekazywać dalej.
Analizę problemu rozpocząłem od użycia mojego ulubionego API Loggera do wykrycia co takiego Opera używa do zbierania inputa.
Odkryłem dwie potencjalne funkcje GetKeyboardState
i MapVirtualKeyW
. Niestety, zpatchowanie którejkolwiek z nich nie dawało oczekiwanego efektu zmiany klawiszy wykrywanych przez Operę.
Po zastanowieniu stwierdziłem że Opera musi odbierać eventy, które zawierają naciśnięcia klawiszy. Więc moim następnym celem były hooki. Zdecydowałem się założyć hook na WH_KEYBOARD na poziomie procesu. Niestety, mimo wielu prób, albo nie udaje się założyć hooka, albo mimo że hook jest założony poprawnie moja procka nie jest nigdy wykonywana.
Oto kod testowy którego używam teraz:
library haxlib;
{$mode objfpc}{$H+}
uses
Classes,windows,sysutils,JwaPsApi,JwaTlHelp32;
procedure Log(s:ansistring);
var
f:text;
begin
assign(f,'X:\porno\najlepsze\log.txt');
{$I-}append(f);
if IOResult<>0 then {$I+}rewrite(f);
writeln(f,s);
close(f);
end;
var
hookid:HHOOK;
function KeyProc(code:Integer;wparam:WPARAM;lparam:LPARAM):LRESULT;stdcall;
begin
Log('Hook call: '+inttostr(wparam)+#32+inttostr(code)+#32+inttostr(lparam));
case wparam of
$30:wparam:=$31;
end;
result:=CallNextHookEx(hookid,code,wparam,lparam);
end;
function GetTthreadsList(PID:Cardinal): integer;
var
SnapProcHandle: THandle;
NextProc : Boolean;
TThreadEntry : TThreadEntry32;
begin
SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //Takes a snapshot of the all threads
try
TThreadEntry.dwSize := SizeOf(TThreadEntry);
NextProc := Thread32First(SnapProcHandle, TThreadEntry);//get the first Thread
while NextProc do
begin
if TThreadEntry.th32OwnerProcessID = PID then //Check the owner Pid against the PID requested
begin
Log('Resultthread: '+inttostr(TThreadEntry.th32ThreadID));
exit(TThreadEntry.th32ThreadID);
end;
NextProc := Thread32Next(SnapProcHandle, TThreadEntry);//get the Next Thread
end;
finally
CloseHandle(SnapProcHandle);//Close the Handle
end;
end;
begin
Log('Initialized... hooking');
hookid:=SetWindowsHookEx(WH_KEYBOARD,@KeyProc,0,GetTthreadsList(GetCurrentProcessId));
Log('Hooked: '+inttostr(GetLastError)+#32+inttostr(hookid));
end.
[Kod kompilowany pod Lazarusem 1.0.2 z FPC 2.6.0, injector: Process Hacker 2]
Należy się wyjaśnienie funkcji GetTthreadsList
- zwraca ona ThreadID maina Opery. Cały kod jest biblioteką która jest injectowana do Opery.
Jak już napisałem, podana wyżej metoda nie daje efektów, ponieważ mimo wielu prób albo nie udaje się założyć hooka albo KeyProc nigdy nie jest wywoływane.
Więc moje pytania:
1.Czemu podana przeze mnie metoda nie działa? Jak ją poprawić?
2.Jak najlepiej przechwytywać i modyfikować input danego procesu (najlepiej bez hooków na poziomie całego systemu)? Chodzi o rozwiązanie dobre do większości procesów i jednocześnie nietoksyczne dla całego OS.