Entwickler-Ecke

Windows API - API HOOK problem


geeky - Do 26.01.06 11:17
Titel: API HOOK problem
hello, i have a piece of code that hooks some api
but when i run it i got system crash, i thing something is wrong in patching api adress, so i need your help ( rllibby, madshi, others are all welcome too ;-)


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:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
library mylib;

uses windows;
const
  PC_WRITEABLE = $00020000;
  PC_USER = $00040000;
  PC_STATIC = $20000000;

  HOOK_NEED_CHECK = 0;
  HOOK_CAN_WRITE = 1;
  HOOK_ONLY_READ = 2;

  BUFFERLEN = 7;



type _tagApiHookStruct = record

    lpszApiModuleName: LPSTR;
    lpszApiName: LPSTR;
    dwApiOffset: DWORD;
    lpWinApiProc: Pointer; //Target API function
    oldWinAPIProc: Pointer; //old function kcahcn
    WinApiFiveByte: array[0..6of BYTE;

    lpszHookApiModuleName: LPSTR;
    lpszHookApiName: LPSTR;
    lpHookApiProc: POINTER; //New function
    NewHookApiProc: POINTER; //Our New function
    HookApiFiveByte: array[0..6of BYTE; //array[0..4]of BYTE;

    hInst: LongWord;

    WinApiBakByte: array[0..6of BYTE;
  end;
  TKS_APIHOOKSTRUCT = _tagApiHookStruct;
  PKS_APIHOOKSTRUCT = ^_tagApiHookStruct;
//FARPROC WINAPI

function MyGetFuncAddress(hInst: LongWord; lpMod: LPCSTR; lpFunc: LPCSTR): tfarproc; stdcall;
procedure MakeJMPCode(var lpJMPCode: array of BYTE {lpJMPCode:PBYTE}; lpCodePoint: Pointer);
procedure HookWin32Api(lpApiHook: PKS_APIHOOKSTRUCT; nSysMemStatus: integer);
procedure RestoreWin32Api(lpApiHook: PKS_APIHOOKSTRUCT; nSysMemStatus: integer);
function MyExtTextOutW(hdc: HDC; X, Y: integer;
  fuOptions: Longint;
  lprc: PRect; lpString: PWideChar;
  cbCount: Longint;
  lpDx: PInteger): BOOL; stdcall;


function ByteArraylcomp(const Str1, Str2: array of byte; MaxLen: Cardinal): Integer;
var
  i: Cardinal;
begin
  result := 0;
  for i := 0 to MaxLen do
    if i < MaxLen then
    begin
      if str1[i] > str2[i] then
      begin
        result := 1;
        exit;
      end
      else if str1[i] < str2[i] then
      begin
        result := -1;
        exit;
      end
    end;
end;

function MyExtTextOutW(hdc: HDC; X, Y: integer;
  fuOptions: Longint;
  lprc: PRect; lpString: PWideChar;
  cbCount: Longint;
  lpDx: PInteger): BOOL; stdcall;

begin
 // restore
  RestoreWin32Api(@g_ExtTextOutWHook, HOOK_NEED_CHECK);
   //do something/process texts
   //....
   //do something end

  ExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx);

  HookWin32Api(@g_ExtTextOutWHook, {HOOK_CAN_WRITE);//} HOOK_NEED_CHECK);

  result := TRUE;
end;

function MyGetFuncAddress(hInst: LongWord; lpMod: LPCSTR; lpFunc: LPCSTR): tfarproc; stdcall;
var
  hMod: HMODULE;
  procFunc: FARPROC;
begin
  if ('' <> lpMod) then
  begin
    hMod := GetModuleHandle(lpMod);
    procFunc := GetProcAddress(hMod, lpFunc);
  end
  else
  begin //current dll kcahcn
    procFunc := GetProcAddress(hInst, lpFunc);
  end;

  result := procFunc;
end;

procedure MakeJMPCode(var lpJMPCode: array of BYTE; lpCodePoint: Pointer);
var
  temp: BYTE;
  wHiWord: WORD;
  wLoWord: WORD;
  wCS: WORD;
begin
  wHiWord := HIWORD(DWORD(lpCodePoint));
  wLoWord := LOWORD(DWORD(lpCodePoint));
  asm                          // ???????
          push ax;
          push cs;
          pop  ax;
          mov  wCS, ax;
          pop  ax;
  end;

  lpJMPCode[0] := $EA;

  temp := LOBYTE(wLoWord);
  lpJMPCode[1] := temp;
  temp := HIBYTE(wLoWord);
  lpJMPCode[2] := temp;
  temp := LOBYTE(wHiWord);
  lpJMPCode[3] := temp;
  temp := HIBYTE(wHiWord);
  lpJMPCode[4] := temp;

  temp := LOBYTE(wCS);
  lpJMPCode[5] := temp;
  temp := HIBYTE(wCS);
  lpJMPCode[6] := temp;

end;



procedure HookWin32Api(lpApiHook: PKS_APIHOOKSTRUCT; nSysMemStatus: integer);
var
  dwReserved: DWORD;
  dwTemp: DWORD;
  bWin32Api: array[0..4of BYTE;
begin
  bWin32Api[0] := $00;
  if (lpApiHook.lpWinApiProc = nilthen
  begin
    //Get the old function address kcahcn
    lpApiHook.lpWinApiProc := MyGetFuncAddress(lpApiHook.hInst,
      lpApiHook.lpszApiModuleName,
      lpApiHook.lpszApiName);
    if (lpApiHook.dwApiOffset <> 0then
      lpApiHook.lpWinApiProc := Pointer(DWORD(lpApiHook.lpWinApiProc) +
        lpApiHook.dwApiOffset);
  end;

  if (lpApiHook.lpHookApiProc = nilthen
  begin
    //Get the new function address kcahcn
    lpApiHook.lpHookApiProc := MyGetFuncAddress(//HInstance,
      lpApiHook.hInst,
      lpApiHook.lpszHookApiModuleName,
      lpApiHook.lpszHookApiName);

  end;

 // ?T JMP ???
  if (lpApiHook.HookApiFiveByte[0] = $00then //no new code
  begin
    //make the new code
    MakeJMPCode(lpApiHook.HookApiFiveByte, lpApiHook.lpHookApiProc);

  end;

  if (not VirtualProtect(lpApiHook.lpWinApiProc, 16, PAGE_READWRITE, @dwReserved)) then
  begin
  //MessageBox(0, 'VirtualProtect-READWRITE', nil, MB_OK);
    exit;
  end;

  if (nSysMemStatus = HOOK_NEED_CHECK) then
  begin
     //Do the hook by writing the new code
     //New code already made.. kcahcn
    CopyMemory(lpApiHook.lpWinApiProc, @lpApiHook.HookApiFiveByte, BUFFERLEN);
     //move(lpApiHook.HookApiFiveByte,lpApiHook.lpWinApiProc,BUFFERLEN);
  end
  else
  begin
    if (lpApiHook.WinApiFiveByte[0] = $00then // ?????????
    begin
   // ??
   // ?? API ????????
        // save old function address
      CopyMemory(@lpApiHook.WinApiFiveByte, lpApiHook.lpWinApiProc, BUFFERLEN);
   // ?????????(???????????????T?JMP??)
        //
      if (ByteArraylcomp(lpApiHook.WinApiFiveByte, lpApiHook.HookApiFiveByte,
        BUFFERLEN) = 0then
      begin
    // ????????
        CopyMemory(@lpApiHook.WinApiFiveByte, @lpApiHook.WinApiBakByte, BUFFERLEN);
      end;
    end
    else
    begin
   // ??
      CopyMemory(@bWin32Api, @lpApiHook.lpWinApiProc, BUFFERLEN);
    end;

    if (ByteArraylcomp(bWin32Api, lpApiHook.HookApiFiveByte, BUFFERLEN) <> 0then
    begin
   // ? JMP ???? API ?????
      CopyMemory(@lpApiHook.lpWinApiProc, @lpApiHook.HookApiFiveByte, BUFFERLEN);
    end;
  end;

  if (not VirtualProtect(lpApiHook.lpWinApiProc, 16, dwReserved, @dwTemp)) then
  begin
  //MessageBox(0, 'VirtualProtect-RESTORE', 0, MB_OK);
    exit;
  end;
end;

procedure RestoreWin32Api(lpApiHook: PKS_APIHOOKSTRUCT; nSysMemStatus: integer);
var
  dwReserved, dwTemp: DWORD;
begin
  if (lpApiHook.lpWinApiProc = nilthen
  begin
   //    OutputDebugString('Restore lpWinApiProc = nil');
    exit;
  end;

  if (not VirtualProtect(lpApiHook.lpWinApiProc, 16, PAGE_READWRITE,
    @dwReserved)) then
  begin
  //MessageBox(0, 'VirtualProtect-READWRITE', 0, MB_OK);
    exit;
  end;
  CopyMemory(@lpApiHook.lpWinApiProc, @lpApiHook.WinApiFiveByte, BUFFERLEN);
  if (not VirtualProtect(lpApiHook.lpWinApiProc, 16, dwReserved, @dwTemp)) then
  begin
  //MessageBox(NULL, "VirtualProtect-RESTORE", NULL, MB_OK);
    exit;
  end;

end;
//...
//..
// other codes and dll entry here , eliminated
end// end of library

//==========================================
// and in my program i call like this
//=========================================

var
  g_ExtTextOutWHook: TKS_APIHOOKSTRUCT =
  (
    lpszApiModuleName: 'gdi32.dll';
    lpszApiName: 'ExtTextOutW';
    dwApiOffset: 0;
    lpWinApiProc: nil//Target function
    oldWinAPIProc: nil//old function
    WinApiFiveByte: (0000000);
    lpszHookApiModuleName: 'MyLib.dll';
    lpszHookApiName: 'MyExtTextOutW';
    lpHookApiProc: nil//new function
    NewHookApiProc: nil;
    HookApiFiveByte: (0000000);
    hInst: 0;
    WinApiBakByte: ($FF$15$FA$13$F3$BF$33)
    );

   //HookWin32Api is exported from my lib
HookWin32Api(@g_ExtTextOutWHook, HOOK_CAN_WRITE);


thanks

Moderiert von user profile iconGausi: Code-Tags replaced by Delphi-Tags


uall@ogc - Do 26.01.06 11:46

Hi, I havent looked at the source, but the hook code isnt that good (because of hooking / unhooking every call)

have a look here (its my hook method)

http://cvs.sourceforge.net/viewcvs.py/omorphia/uallCollection/

unit: uallHook
name: HookCode(...)

Example with TextOutW hook inside http://uall.overclock.ch/uallCollection.zip


geeky - Do 26.01.06 11:58

hi uall@ogc , i already got your code from there ;-)
but sisnce this piece of code was part of a big library im working on, and im forced to use this code so i asked help.

anyway i'll try to replace it with your code .. much thanks for your greate code.


Sebastian R. - So 26.02.06 20:05

Possibly you can copy some of the codes from uall (when you got his permission to do so)?


BenBE - Mo 27.02.06 00:32

Although the code is being managed inside the Omorphia project it is kept separate and may be used separate from the Omorphia Library. The uallCollection itself is LGPL thus free to use as long as original copyrights remain intact. There's no limitation on using the source, but it is appreciated giving credits for the uallCollection if source outa there is being used.

Regarding your code it might be useful to describe the exact problems (occurence of the error) in some more detail. Maybe (if used as global hook) it might also be usefule to inject that library in one single process only and verify all the patching is done correct.