Es ist eigentlich egal ob man MMF's nimmt oder nicht. Man könnte auch VirtualAllocEx() benutzten um einen Speicherbereich innerhalb eines anderen Processes zu injezieren. Man sollte nun zwei unterschiedliche Vorgehensweisen betrachten, abhängig ob
Win9x oder Win2x.
Generell sähe es so aus:
1.) erzeuge einen Speicherbereich im Zielprozess
2.) initialisiere in diesem Speicher den Code + Datenstrukturen. In diesem Speicher liegt eine Threadfunktion und die WindowProc
3.) erzeuge einen Remote Thread, also einen Thread der im Zielprozess läuft. Unter Win2x gibts dafür CreateRemoteThread() unter
Win9x kann man diese Funktion nachbauen.
4.) die Threadfunktion zeigt in unserem Speicherbereich
Nun ist es wichtig was die Threadfunktion überhaupt macht. Sie subclasses das betroffene Fensterhandle und setzt deren Fensterfunktion auf die Fensterfunktion in unserem Speicherbereich. Danach Terminiert sie den Thread.
Als Pseudocode sähe das so aus:
Delphi-Quellcode:
type
PHookData = ^THookData;
THookData =
packed record
SaveWindowProc: Pointer;
hWnd: HWnd;
GetWindowLong:
function(hWnd,
Index): Pointer:
stdcall;
SetWindowLong:
function(hWnd,
Index, Pointer): Bool;
stdcall;
ExitThread:
procedure(Return);
stdcall;
CallWndProc:
function(Proc, hWnd, wParam, lParam): lResult;
stdcall;
VirtualFree: fucntion(Pointer): Integer;
stdcall;
WindowProc:
array[0..0]
of Byte;
// hier wird MyWndProc rein kopiert
ThreadCode:
array[0..0]
of Byte;
// hier wird ThreadProc hineinkopiert
end;
function MyWndProc(...): Integer;
stdcall;
var
Memory: PHookData;
begin
asm
CALL @@1
@@1: POP EAX
AND EAX,$FFFFF000
// align
MOV Memory,EAX
end;
if Msg = wm_Destroy
then
begin
Memory.CallWndProc(Memory.SaveWindowProc, hWnd, Msg, wParam, lParam);
// hier Memory freigeben, wichtig dabei das der aktuelle Code ja in diesem Memory^ liegt
// wir müssen also die Reücksrungadresse aus dem Stack holen. Dann Memory auf den Stack pushen
// danach Rücksrungadresse pushen und einem Jump nach VirtualFree() durchführen.
// Somit kehrt VirtualFree NICHT in unseren nun freigegebene Memory zurück, sondern zum
// Aufrufer von MyWndProc().
asm
POP EDX
MOV EAX,Memory
PUSH EAX
PUSH EDX
JMP [EAX].VirtualFree
end;
end else
if Msg = wm_Close
then
begin
end else
Result := Memory.CallWndProc(Memory.SaveWindowProc, Wnd, Msg, wParam, lParam);
end;
function ThreadProc(Memory: PHookData): Dword;
stdcall;
// wichtig !! keine Aufrufe von Funktionen und Daten die nicht Importe/Inhalte in Memory sind !!
begin
Memory.SaveWindowProc := Memory.GetWindowLong(Memory.hWnd, gwl_WndProc);
Memory.SetWindowLong(Memory.hWnd, gwl_WindowProc, @Memory.WindowProc);
Memory.ExitThread(0);
end;
procedure Subclass(hWnd);
var
Memory: PHookData;
ProcSize: Integer;
ThreadFunc: Pointer;
begin
ProcSize := PChar(@Subclass) - PChar(@MyWndProc);
Memory := VirtualAllocEx(..., SizeOf(THookData) + ProcSize);
// align on Pageboundary needed !!
Move(@MyWndProc, @Memory.WindowProc, ProcSize);
Memory.hWnd := hWnd;
Memory.GetWindowLong := GetProcAddress();
Memory.SetWindowLong := GetProcAddress();
Memory.ExitThread := GetProcAddress();
Memory.CallWndProc := GetProcAddress();
Memory.VirtualFree := GetProcAddress();
ThreadFunc := PChar(Memory) + SizeOf(THookData) + PChar(@ThreadProc) - PChar(@MyWndProc);
CreateRemoteThread(..., ThreadFunc, Memory, ...);
end;
WICHTIG ! dies niemals mit dem integrierten Debugger testen, da BorDbk Importe im Prozess wie GetProcAddress() selber umbiegt. Somit kann zB. GetProcAddress(, 'GetWindowLong') eine Adresse zurückgeben die in den BorDbk zeigt statt in's Kernel/
GDI. Am besten eine eigene GetProcAddress() Funktion benutzen die ohne
API auskommt !.
Jetzt mus man nur noch zum hWnd das Process
Handle und Process ID rausbekommen.
Gruß Hagen
PS: Den Feinschliff müsst ihr selber rausfinden, da dieses Posting so ziemlich der direkte Weg ist für schlaue Jungs.