Entwickler-Ecke

Windows API - EXECUTE-Hooker bearbeiten.


Yooda - So 18.01.04 02:12
Titel: EXECUTE-Hooker bearbeiten.
Hallo nochmal...


Ich habe mir den Code einmal angeschaut... Ich hab da ein Problem.
Ich poste mal den Code der HookUnit mit einer Bitte. Könnt Ihr mir sagen, dass wenn ich diese Unit später einbinde, ich statt der Messageboxen einen Timer auf der Form des Hauptprogrammes einschalte wenn einer einen Prozess gestartet hat?

nochmal "übersichtlicher"

Wenn jeman nen prozes startet, soll die hookunit einen timer in der Projekt1.exe starten.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
unit HookUnit;

interface

uses
  Windows, PEStuff, Classes, ShellAPI;

type
  TShellExecute = function(hWnd: HWND; Operation, FileName, Parameters, Directory: PChar; ShowCmd: Integer): HINST; stdcall;

  TCreateProcessA = function(
    lpApplicationName: LPCSTR; lpCommandLine: LPSTR; lpProcessAttributes: TSECURITYATTRIBUTES;
    lpThreadAttributes: TSECURITYATTRIBUTES; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
    lpCurrentDirectory: LPCSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): Bool; stdcall;

  TCreateProcess = function(lpApplicationName: PChar; lpCommandLine: PChar;
    lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
    bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
    lpCurrentDirectory: PChar; const lpStartupInfo: TStartupInfo;
    var lpProcessInformation: TProcessInformation): BOOL; stdcall;

  TCreateProcessW = function(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
    lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
    bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
    lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfo;
    var lpProcessInformation: TProcessInformation): BOOL; stdcall;


  PPointer = ^Pointer;

  TImportCode = packed record
    JumpInstruction: word; // should be $25FF
    AddressOfPointerToFunction: PPointer;
  end;
  PImportCode = ^TImportCode;

procedure HookFunctions;
procedure UnHookFunctions;

implementation

var
  OldShellExecute: TShellExecute = nil;
  OldCreateProcess: TCreateProcess = nil;
  OldCreateProcessA: TCreateProcessA = nil;
  OldCreateProcessW: TCreateProcessW = nil;

function Int2Str(Number: Int64): string;
var
  Minus: Boolean;
begin
  Result := '';
  if Number = 0 then
    Result := '0';
  Minus := Number < 0;
  if Minus then
    Number := -Number;
  while Number > 0 do
  begin
    Result := Char((Number mod 10) + Integer('0')) + Result;
    Number := Number div 10;
  end;
  if Minus then
    Result := '-' + Result;
end;



function NewShellExecute(hWnd: HWND; Operation, FileName, Parameters, Directory: PChar; ShowCmd: Integer): HINST; stdcall;
begin
  Result := 0;
  // HIER SOLL DER TIMER1 DER FORM1 EINGESCHALTET WERDEN
    Result := OldShellExecute(hwnd, Operation, FileName, Parameters, Directory, ShowCmd);
end;

function NewCreateProcess(lpApplicationName: PChar; lpCommandLine: PChar;
  lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
  lpCurrentDirectory: PChar; const lpStartupInfo: TStartupInfo;
  var lpProcessInformation: TProcessInformation): BOOL; stdcall;
begin
  // HIER SOLL DER TIMER1 DER FORM1 EINGESCHALTET WERDEN
    Result := OldCreateProcess(
      lpApplicationName, lpCommandLine, lpProcessAttributes,
      lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
      lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
end;

function NewCreateProcessA(
  lpApplicationName: LPCSTR; lpCommandLine: LPSTR; lpProcessAttributes: TSECURITYATTRIBUTES;
  lpThreadAttributes: TSECURITYATTRIBUTES; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
  lpCurrentDirectory: LPCSTR; lpStartupInfo: TStartupInfo; lpProcessInformation: TProcessInformation): Bool; stdcall;
begin
  // HIER SOLL DER TIMER1 DER FORM1 EINGESCHALTET WERDEN
    Result := OldCreateProcessA(
      lpApplicationName, lpCommandLine, lpProcessAttributes,
      lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
      lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
end;

function NewCreateProcessW(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
  lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
  lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfo;
  var lpProcessInformation: TProcessInformation): BOOL; stdcall;
begin
  // HIER SOLL DER TIMER1 DER FORM1 EINGESCHALTET WERDEN
    Result := OldCreateProcessW(
      lpApplicationName, lpCommandLine, lpProcessAttributes,
      lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
      lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
end;

function PointerToFunctionAddress(Code: Pointer): PPointer;
var
  func: PImportCode;
begin
  Result := nil;
  if Code = nil then Exit;
  try
    func := code;
    if (func.JumpInstruction = $25FFthen
    begin
      Result := func.AddressOfPointerToFunction;
    end;
  except
    Result := nil;
  end;
end;

function FinalFunctionAddress(Code: Pointer): Pointer;
var
  func: PImportCode;
begin
  Result := Code;
  if Code = nil then Exit;
  try
    func := code;
    if (func.JumpInstruction = $25FFthen
    begin
      Result := func.AddressOfPointerToFunction^;
    end;
  except
    Result := nil;
  end;
end;


function PatchAddress(OldFunc, NewFunc: Pointer): integer;
var
  BeenDone: TList;

  function PatchAddressInModule(hModule: THandle; OldFunc, NewFunc: Pointer): integer;
  var
    Dos: PImageDosHeader;
    NT: PImageNTHeaders;
    ImportDesc: PImage_Import_Entry;
    rva: DWORD;
    Func: PPointer;
    DLL: string;
    f: Pointer;
    written: DWORD;
  begin
    Result := 0;
    Dos := Pointer(hModule);
    if BeenDone.IndexOf(Dos) >= 0 then Exit;
    BeenDone.Add(Dos);
    OldFunc := FinalFunctionAddress(OldFunc);
    if IsBadReadPtr(Dos, SizeOf(TImageDosHeader)) then Exit;
    if Dos.e_magic <> IMAGE_DOS_SIGNATURE then Exit;
    NT := Pointer(integer(Dos) + dos._lfanew);
    // if IsBadReadPtr(NT,SizeOf(TImageNtHeaders)) then exit;

    RVA := NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    if RVA = 0 then Exit;
    ImportDesc := Pointer(integer(Dos) + RVA);
    while (ImportDesc^.Name <> 0do
    begin
      DLL := PChar(integer(Dos) + ImportDesc^.Name);
      PatchAddressInModule(GetModuleHandle(PChar(DLL)), OldFunc, NewFunc);
      Func := Pointer(integer(DOS) + ImportDesc.LookupTable);
      while Func^ <> nil do
      begin
        f := FinalFunctionAddress(Func^);
        if f = OldFunc then
        begin
          WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
          if Written > 0 then Inc(Result);
        end;
        Inc(Func);
      end;
      Inc(ImportDesc);
    end;
  end;
begin
  BeenDone := TList.Create;
  try
    Result := PatchAddressInModule(GetModuleHandle(nil), OldFunc, NewFunc);
  finally
    BeenDone.Free;
  end;
end;

procedure HookFunctions;
begin

  if @OldShellExecute = nil then
    @OldShellExecute := FinalFunctionAddress(@ShellExecute);

  if @OldCreateProcess = nil then
    @OldCreateProcess := FinalFunctionAddress(@CreateProcess);

  if @OldCreateProcessA = nil then
    @OldCreateProcessA := FinalFunctionAddress(@CreateProcessA);

  if @OldCreateProcessW = nil then
    @OldCreateProcessW := FinalFunctionAddress(@CreateProcessW);

  PatchAddress(@OldShellExecute, @NewShellExecute);
  PatchAddress(@OldCreateProcess, @NewCreateProcess);
  PatchAddress(@OldCreateProcessA, @NewCreateProcessA);
  PatchAddress(@OldCreateProcessW, @NewCreateProcessW);
end;

procedure UnhookFunctions;
begin
  if @OldShellExecute <> nil then
    PatchAddress(@NewShellExecute, @OldShellExecute);

  if @OldCreateProcess <> nil then
    PatchAddress(@NewCreateProcess, @OldCreateProcess);

  if @OldCreateProcessA <> nil then
    PatchAddress(@NewCreateProcessA, @OldCreateProcessA);

  if @OldCreateProcessW <> nil then
    PatchAddress(@NewCreateProcessW, @OldCreateProcessW);
end;

initialization

finalization
  UnhookFunctions;
end.




Bitte helft mir.

Moderiert von user profile iconMotzi: Code- durch Delphi-Tags ersetzt


Motzi - Mo 19.01.04 16:21

Das Problem ist, dass das ja eine Hook-Dll ist die immer in die jeweiligen Prozesse eingeblendet ist, also nicht in deinem Prozessraum liegt. Am einfachsten wäre es eine selbstdefinierte Message an das Fenster deines Prozesses zu schicken.

Alternativ kann man auch ohne Hook das Starten eines Prozesses mitbekommen nämlich per Suche in: Delphi-Forum, Delphi-Library WMI...!


Anonymous - Mo 19.01.04 17:15

Und Alternativ kann man auch keine DLL verwenden, weil ein Hook hier sowieso überflüssig ist.


Motzi - Mo 19.01.04 18:41

Wieso ist ein Hook hier überflüssig? Entweder man macht es (wie in dem Code) per API-Hook oder eben per WMI..! Oder welche Alternative schwebt dir noch vor..?!? :roll:


Anonymous - Mo 19.01.04 18:49

In dem Beispiel von toms wird noch ein Message-Hook verwendet. Der ist überflüssig und für den API-Hook braucht man keine DLL. Vielleicht hätte ich mich anders ausdrücken sollen.