Autor Beitrag
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Do 26.08.04 13:59 
hab hier mal nen kleinen API hook geschrieben:

ausblenden volle Höhe 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:
var nextMessageboxA: function(hWnd: HWND; lpText, lpCaption: pchar; uType: cardinal): UINT; stdcall;
    oldMessageboxA: function(hWnd: HWND; lpText, lpCaption: pchar; uType: cardinal): UINT; stdcall;

function myMessageboxA(hWnd: HWND; lpText, lpCaption: pchar; uType: cardinal): UINT; stdcall;
begin
  result := nextMessageboxA(hWnd,pchar(lpText+' hooked!!!'),lpCaption,uType);
end;

procedure HookApi(my, old: pointer; var next: pointer); stdcall;
asm
  push PAGE_EXECUTE_READWRITE
  push MEM_COMMIT or MEM_RESERVE
  push 64+5*4
  push 0
  call VirtualAlloc
  push eax
  mov [eax], $C7241C8Badd eax, 4
  mov [eax], $00002404add eax, 4
  mov [eax], $058b0000add eax, 4
  mov [eax], $00000000add eax, 4
  mov [eax], $0000158Badd eax, 4
  mov [eax], $10890000add eax, 4
  mov [eax], $0000158Badd eax, 4
  mov [eax], $50890000add eax, 4
  mov [eax], $50E0FF04add eax, 4
  mov [eax], $00058B52add eax, 4
  mov [eax], $8B000000add eax, 4
  mov [eax], $00000015add eax, 4
  mov [eax], $8B108900add eax, 4
  mov [eax], $00000015add eax, 4
  mov [eax], $04508900add eax, 4
  mov [eax], $E3FF5A58add eax, 4
  pop eax
  push eax

  mov ebx, eax
  add eax, 6
  add ebx, $23
  mov [eax], ebx

  add eax, 6
  add ebx, $40-$23
  mov [eax], ebx

  add eax, 6
  add ebx, 4
  mov [eax], ebx

  add eax, 8
  add ebx, 4
  mov [eax], ebx

  add eax, 13
  sub ebx, 8
  mov [eax], ebx

  add eax, 6
  add ebx, 12
  mov [eax], ebx

  add eax, 8
  add ebx, 4
  mov [eax], ebx

  push eax
  push esp
  push PAGE_EXECUTE_READWRITE
  push 8
  push [old]
  call VirtualProtect

  pop eax
  pop eax
  push eax
  add eax, $40
  mov ebx, [old]
  mov [eax], ebx
  add eax, 4
  mov ecx, [ebx]
  mov [eax], ecx
  add ebx, 4
  add eax, 4
  mov ecx, [ebx]
  mov [eax], ecx

  mov eax, [old]
  mov byte ptr [eax], $E9
  add eax, 1
  mov ebx, [my]
  sub ebx, [old]
  sub ebx, 5
  mov [eax], ebx

  pop eax
  push eax
  add eax, $40
  add eax, 12
  mov ebx, [old]
  mov ecx, [ebx]
  mov [eax], ecx
  add eax, 4
  add ebx, 4
  mov ecx,[ebx]
  mov [eax], ecx

  mov eax, [next]
  pop edx
  mov [eax], edx
end;

procedure test;
begin
  @oldMessageBoxA := GetProcAddress(LoadLibrary('user32.dll'),'MessageBoxA');
  HookApi(@myMessageboxA,@oldMessageBoxA,@nextMessageboxA);
  oldMessageboxA(0,'hallo :) ',nil,0);
end;


das is nen bsp mit MessageBoxA aus der user32.dll
anstatt den text 'hallo :)' auszugeben wird 'hallo :) hooked!!!' ausgegeben
wenn jemand genauer daran interessiert wie der hook funzt kann ich ihm das erklären :)
Sprint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 849



BeitragVerfasst: Do 26.08.04 16:19 
Hallo,

beschäfitge mich auch gerade mit dem hooken von API's. Hab unter anderem madCodeHook, afxCodeHook und die HookImport Funktion aus dem JEDI Project getestet.
Ich finde das madCodeHook am stabilsten läuft. Naja, aber US $125 wollte ich eigentlich nicht ausgeben. Und ich möchte natürlich auch, das ich meine verwendeten Komponenten, als Quellcode hab.

Ich finde das gut, das du hier eine OpenSource Möglichkeit gepostet hast.
Ich suche noch ein Beispiel, wie ich meine DLL in ein Prozess injecten kann.
Zurzeit benutze ich CreateRemoteThread. Das funktioniert unter NT-basierten Systerm auch sehr gut. Nur auf Win9x Rechnern geht das nicht.
Also wenn du da noch irgendwo 'nen Quelltext liegen hast... Das würde mich sehr freuen, wenn du den hier auch noch veröffentlich kannst. :D

_________________
Ciao, Sprint.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Do 26.08.04 16:30 
klar hab ich da noch was schönes für dich:

1.) eine dll selbst in einen anderen prozess laden:

ausblenden volle Höhe 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:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
program prog2; 

uses windows, tlhelp32; 

// dll als array eingebunden 

var mydll: array[$1..$00003C00of byte = (*CUT* hier sollte die dll als array stehen */CUT*)

function UpperCase(const S: string): string
var 
  Ch: Char; 
  L: Integer; 
  Source, Dest: PChar; 
begin 
  L := Length(S); 
  SetLength(Result, L); 
  Source := Pointer(S); 
  Dest := Pointer(Result); 
  while L <> 0 do 
  begin 
    Ch := Source^; 
    if (Ch >= 'a'and (Ch <= 'z'then Dec(Ch, 32); 
    Dest^ := Ch; 
    Inc(Source); 
    Inc(Dest); 
    Dec(L); 
  end
end

function FindProcess: cardinal; 
var 
   FSnapshotHandle: THandle; 
   FProcessEntry32: TProcessEntry32; 
   ContinueLoop: BOOL; 
begin 
   FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); 
   FProcessEntry32.dwSize := Sizeof(FProcessEntry32); 
   ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32); 
   Result := 0
   while ContinueLoop do 
   begin 
     if (pos(uppercase('hl.exe'),uppercase(FProcessEntry32.szExeFile)) > 0or 
        (pos(uppercase('cstrike.exe'),uppercase(FProcessEntry32.szExeFile)) > 0then 
       result := openprocess(PROCESS_ALL_ACCESS, true, FProcessEntry32.th32ProcessID); 
     ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32); 
   end
   CloseHandle(FSnapshotHandle); 
end

procedure memcopy(p1,p2: pointer; a: integer); 
var i: integer; 
    b1, b2: ^byte; 
    old1,old2: cardinal; 
begin 
  virtualprotect(p1,a,PAGE_EXECUTE_READWRITE,old1); 
  virtualprotect(p2,a,PAGE_EXECUTE_READWRITE,old2); 
  b1 := p1; 
  b2 := p2; 
  for i := 0 to a do 
  begin 
    b1^ := b2^; 
    b1 := pointer(integer(b1)+1); 
    b2 := pointer(integer(b2)+1); 
  end
  virtualprotect(p1,a,old1,old1); 
  virtualprotect(p2,a,old2,old2); 
end

procedure changereloc(baseorgp, basedllp, relocp, basedllpop: pointer; size: integer); 
type trelocblock = record 
                     vaddress: integer; 
                     size: integer; 
                   end
     prelocblock = ^trelocblock; 
var myreloc: prelocblock; 
    reloccount: integer; 
    startp: pointer; 
    i: integer; 
    prelocitem: ^word; 
    relocitem: word; 
    p: ^integer; 
    old: cardinal; 
    dif: integer; 
begin 
  myreloc := relocp; 
  dif := integer(basedllpop)-integer(baseorgp); 
  startp := pointer(integer(relocp)+8); 
  repeat 
    reloccount := (myreloc^.size-8div sizeof(word); 
    if (reloccount > 0and (myreloc^.vaddress mod $1000 = 0and 
       ((size+integer(relocp))-integer(myreloc) > 0then 
    begin 
      for i := 0 to reloccount-1 do 
      begin 
        prelocitem := startp; 
        relocitem := prelocitem^; 
        if relocitem > $3000 then 
        begin 
          relocitem := relocitem mod $3000
          p := pointer(myreloc^.vaddress+relocitem+integer(basedllp)); 
          virtualprotect(p,4,PAGE_READWRITE,old); 
          p^ := p^+dif; 
          virtualprotect(p,4,old,old); 
        end
        startp := pointer(integer(startp)+sizeof(word)); 
      end
      myreloc := startp; 
      startp := pointer(integer(startp)+8); 
    end
  until (reloccount = 0or (myreloc^.vaddress mod $1000 <> 0or 
        ((size+integer(relocp))-integer(myreloc) <= 0); 
end

procedure createimporttable(dllbasep, importp: pointer); stdcall
type timportblock = record 
                      Characteristics: dword; 
                      TimeDateStamp: dword; 
                      ForwarderChain: dword; 
                      Name: dword; 
                      FirstThunk: pointer; 
                    end
     pimportblock = ^timportblock; 

     timportfblock = record 
                       hint: word; 
                       name: byte; 
                     end
     pimportfblock = ^timportfblock; 
var myimport: pimportblock; 
    myimportf: pimportfblock; 
    thunks: ^pointer; 
    dllname: pchar; 
    dllh: thandle; 
begin 
  myimport := importp; 
  repeat 
    dllname := pointer(cardinal(dllbasep)+myimport^.name); 
    dllh := getmodulehandle(dllname); 
    if dllh = 0 then dllh := loadlibrary(dllname); 
    thunks := pointer(integer(myimport^.FirstThunk)+integer(dllbasep)); 
    repeat 
      myimportf := pointer(integer(dllbasep)+integer(thunks^)); 
      if ((cardinal(thunks^)-dllh) <> (cardinal(thunks^) mod dllh)) then 
        thunks^ := getprocaddress(dllh,pchar(@myimportf^.name)); 
      thunks := pointer(integer(thunks)+4); 
    until (thunks^ = nilor (pchar(@myimportf^.name) = ''); 
    myimport := pointer(integer(myimport)+sizeof(timportblock)); 
    dllname := pointer(cardinal(dllbasep)+myimport^.name); 
  until (dllname = ''or (myimport^.name = 0or 
     (myimport^.FirstThunk = nil); 
end

procedure startdll; 
asm 
  push ebp 
  mov ebp, esp 
  push eax 
  push $0 
  push DLL_PROCESS_ATTACH 
  push $0 
  mov eax, $0 
  call eax 
  pop eax 
  pop ebp 
end

function readdll(f: pchar; calldllmain: boolean): pointer; stdcall
var IDH: PImageDosHeader; 
    read,memsize, firstsec: cardinal; 
    filemem, all: pointer; 
    INH: PImageNtHeaders; 
    seca: cardinal; 
    sectionh: PImageSectionHeader; 
    i, h: integer; 
    filesize: cardinal; 
    blad: ^pointer; 
    old, tid: cardinal; 
begin 
  result := nil
  h := CreateFile(f,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); 
  if h <> -1 then 
  begin 
    filesize := getfilesize(h,nil); 
    getmem(filemem,filesize); 
    readfile(h,filemem^,filesize,read,nil); 
    IDH := filemem; 
    INH := pointer(cardinal(filemem)+cardinal(IDH^._lfanew)); 
    if IDH^.e_magic = IMAGE_DOS_SIGNATURE then 
    if INH^.Signature = IMAGE_NT_SIGNATURE then 
    begin 
      sectionh := pointer(cardinal(INH)+cardinal(sizeof(TImageNtHeaders))); 
      firstsec := sectionh^.VirtualAddress; 
      memsize := INH^.OptionalHeader.SizeOfImage-firstsec; 
      if memsize <> 0 then 
      begin 
        all := virtualalloc(nil,memsize,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE); 
        seca := INH^.FileHeader.NumberOfSections; 
        for i := 0 to seca-1 do 
        begin 
          memcopy(pointer(cardinal(all)+sectionh^.VirtualAddress-firstsec), 
            pointer(cardinal(filemem)+cardinal(sectionh^.PointerToRawData)), 
            sectionh^.SizeOfRawData); 
          sectionh := pointer(integer(sectionh)+sizeof(TImageSectionHeader)); 
        end
        changereloc(pointer(INH^.OptionalHeader.ImageBase), 
                    pointer(cardinal(all)-firstsec), 
                    pointer(cardinal(all)-firstsec+INH^.OptionalHeader.DataDirectory[5].VirtualAddress), 
                    pointer(cardinal(all)-firstsec), 
                    INH^.OptionalHeader.DataDirectory[5].Size); 
        createimporttable(pointer(cardinal(all)-firstsec), pointer(cardinal(all)-firstsec+INH^.OptionalHeader.DataDirectory[1].VirtualAddress)); 
        blad := pointer(cardinal(@startdll)+11); 
        virtualprotect(blad,4,PAGE_EXECUTE_READWRITE,old); 
        blad^ := pointer(INH^.OptionalHeader.AddressOfEntryPoint+cardinal(all)-firstsec); 
        virtualprotect(blad,4,old,old); 
        freemem(filemem); 
        result := all; 
        if calldllmain then 
          createthread(nil,0,@startdll,nil,0,tid); 
      end
    end
  end
end

procedure loaddllmem(p: pointer; pid: cardinal); stdcall
var IDH: PImageDosHeader; 
    memsize, firstsec,old, tid, written, seca: cardinal; 
    INH: PImageNtHeaders; 
    sectionh: PImageSectionHeader; 
    i: integer; 
    blad: ^pointer; 
    allp, all, startpp: pointer; 
begin 
  IDH := p; 
  INH := pointer(cardinal(p)+cardinal(IDH^._lfanew)); 
  if IDH^.e_magic = IMAGE_DOS_SIGNATURE then 
  if INH^.Signature = IMAGE_NT_SIGNATURE then 
  begin 
    sectionh := pointer(cardinal(INH)+cardinal(sizeof(TImageNtHeaders))); 
    firstsec := sectionh^.VirtualAddress; 
    memsize := INH^.OptionalHeader.SizeOfImage-firstsec; 
    if memsize <> 0 then 
    begin 
      getmem(all,memsize); 
      startpp := virtualallocEX(pid,nil,memsize+20,MEM_TOP_DOWN or MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE); 
      allp := pointer(cardinal(startpp)+20); 
      seca := INH^.FileHeader.NumberOfSections; 
      for i := 0 to seca-1 do 
      begin 
        memcopy(pointer(cardinal(all)+sectionh^.VirtualAddress-firstsec), 
          pointer(cardinal(p)+cardinal(sectionh^.PointerToRawData)), 
          sectionh^.SizeOfRawData); 
        sectionh := pointer(integer(sectionh)+sizeof(TImageSectionHeader)); 
      end
      changereloc(pointer(INH^.OptionalHeader.ImageBase), 
                  pointer(cardinal(all)-firstsec), 
                  pointer(cardinal(all)-firstsec+INH^.OptionalHeader.DataDirectory[5].VirtualAddress), 
                  pointer(cardinal(allp)-firstsec), 
                  INH^.OptionalHeader.DataDirectory[5].Size); 
      createimporttable( 
        pointer(cardinal(all)-firstsec), 
        pointer(cardinal(all)-firstsec+INH^.OptionalHeader.DataDirectory[1].VirtualAddress)); 
      blad := pointer(cardinal(@startdll)+11); 
      virtualprotect(blad,4,PAGE_EXECUTE_READWRITE,old); 
      blad^ := pointer(INH^.OptionalHeader.AddressOfEntryPoint+cardinal(allp)-firstsec); 
      virtualprotect(blad,4,old,old); 
      writeprocessmemory(pid,startpp,@startdll,20,written); 
      writeprocessmemory(pid,allp,all,memsize,written); 
      createremotethread(pid,nil,0,startpp,nil,0,tid); 
    end
  end
end

procedure main; 
var pid: cardinal; 
    ende: boolean; 
begin 
  messagebox(0,'click "OK" to enable monitoring'+#13#10
               'press END key to stop monitoring'+#13#10
               'press END key in game to enable wallhack',nil,0); 
  ende := false; 
  repeat 
    pid := findprocess; 
    if pid <> 0 then 
    begin 
      sleep(5000); 
      loaddllmem(@mydll,pid); 
      ende := true; 
    end
    if getasynckeystate(VK_END) < 0 then 
    begin 
      messagebox(0,'monitoring aborted'+#13#10
                   'could not inject data into HL-process',nil,0); 
      ende := true; 
    end
    sleep(1); 
  until ende = true; 
end

begin 
  main; 
end.


2.)

www.arschvoll.net/elirt.zip

damit kann man CreateRemotheThread / OpenThread und VirtualAllocEx bei win98 / 95 benutzen

3.)

hier ne unit von mir, mit der man die länge von instruktioenn auslesen kann
ausserdem nen api hook der die ersten instruktioenn von ner api kopiert und dann nen jmp reinsetz (wie madhook)

ausblenden volle Höhe 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:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
{ (c) by uall :) } 

unit myhook; 

interface 

uses windows; 

procedure memcopy(toaddr,fromaddr: pointer; a: integer); 
procedure hookfkt(oldfkt,yourfkt: pointer; var newfkt: pointer); 
function instrlength(p: pointer): integer; 

implementation 

const 
  OP_eins = -1
  OPnull = 0
  OPeins = 1
  OPzwei = 2
  OPdrei = 3
  OPvier = 4
  OPfuenf = 5
  OPsechs = 6
  OPsieben = 7
  OPacht = 8
  OPneun = 9
  OPzehn = 10
  OPtable7 = 11;  // table2 +1  (ok) 
  OPtable2 = 12;  //            (ok) 
  OPtable5 = 15;  // 
  OPtable6 = 16;  // table2 +4  (ok) 
  OPtableFF = 17//            (ok) 
  OPtableF7 = 18//            (ok) 
  OPtable8 = 19;  //            (ok) 
  OPtableFE = 20//            (ok) 
  OPtableDD = 21//            (ok) 
  OPtable0F = 22//            (ok naja :P) 
  OPtable = 23

var firsttable: array[$00..$FFof integer = 


  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPnull  ,OPtable0F, 
OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPtable ,OPnull  ,OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPtable ,OPnull  , 
OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPtable ,OPnull  ,OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPvier  ,OPtable ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPtable2,OPtable2,OPtable ,OPtable ,OPtable ,OPtable5,OPvier  ,OPtable6,OPeins  ,OPtable7,OPnull  ,OPnull,  OPnull  ,OPnull  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  , 
OPtable7,OPtable6,OPtable7,OPtable7,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2, 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPsechs ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  , 
OPtable7,OPzwei  ,OPzwei  ,OPnull  ,OPtable2,OPtable2,OPtable7,OPtable6,OPvier  ,OPnull  ,OPzwei  ,OPnull  ,OPnull  ,OPeins  ,OPnull  ,OPnull  , 
OPtable2,OPtable2,OPtable2,OPtable2,OPeins  ,OPeins  ,OPnull  ,OPnull  ,OPtable2,OPtable2,OPtable2,OPtable2,OPtable2,OPtableDD,OPtable2,OPtable2, 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPvier  ,OPvier  ,OPsechs ,OPeins  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPtable ,OPnull  ,OPtable ,OPtable ,OPnull  ,OPnull  ,OPtable8,OPtableF7,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPtableFE,OPtableFF); 

var secondtable: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ); 

var fftable: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ); 

var f7table: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPacht  ,OPvier  ,OPvier  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPfuenf ,OPeins  ,OPeins  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPsechs ,OPfuenf ,OPfuenf ,OPfuenf ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPacht  ,OPacht  ,OPacht  ,OPacht  ,OPneun  ,OPacht  ,OPacht  ,OPacht  ,OPfuenf ,OPfuenf ,OPfuenf ,OPfuenf ,OPsechs ,OPfuenf ,OPfuenf ,OPfuenf , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull); 

var table8: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPfuenf ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPfuenf ,OPeins  ,OPeins  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPdrei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPzwei  ,OPdrei  ,OPzwei  ,OPzwei  ,OPzwei  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPfuenf ,OPfuenf ,OPfuenf ,OPfuenf ,OPsechs ,OPfuenf ,OPfuenf ,OPfuenf ,OPfuenf ,OPfuenf ,OPfuenf ,OPfuenf ,OPsechs ,OPfuenf ,OPfuenf ,OPfuenf , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull); 

var fetable: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins); 

var ddtable: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPeins  ,OPvier  ,OPnull  ,OPnull  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPeins  ,OPzwei  ,OPeins  ,OPeins  ,OPeins  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPfuenf ,OPnull ,OPvier  ,OPvier  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OP_eins  ,OPnull  ,OPnull , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OP_eins ,OPnull  ,OPnull  ); 

var table0f: array[$00..$FFof integer = 

  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f 
OPtable ,OPtable ,OPtable ,OPtable ,OP_eins ,OP_eins ,OPnull  ,OP_eins ,OPnull  ,OP_eins ,OP_eins ,OPnull  ,OP_eins ,OPtable ,OPnull  ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OP_eins ,OPtable ,OP_eins ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins ,OP_eins , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OP_eins ,OP_eins ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  ,OPvier  , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  ,OPnull  , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable , 
OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable ,OPtable); 

function instrlength(p: pointer): integer; 
var anzahl: integer; 
    fertig: boolean; 
    b: ^byte; 
begin 
  fertig := false; 
  anzahl := 1
  b := p; 
  repeat 
    case firsttable[b^] of 
      -1..10
      begin 
        inc(anzahl,firsttable[b^]); 
        fertig := true; 
      end
      OPtable: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
      end
      OPtable2: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,secondtable[b^]); 
        fertig := true; 
      end
      OPtable7: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,secondtable[b^]+1); 
        fertig := true; 
      end
      OPtable6: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,secondtable[b^]+4); 
        fertig := true; 
      end
      OPtableFF: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,FFtable[b^]); 
        fertig := true; 
      end
      OPtableF7: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,F7table[b^]); 
        fertig := true; 
      end
      OPtableFE: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,FEtable[b^]); 
        fertig := true; 
      end
      OPtableDD: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,DDtable[b^]); 
        fertig := true; 
      end
      OPtable8: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        inc(anzahl,table8[b^]); 
        fertig := true; 
      end
      OPtable0f: 
      begin 
        inc(anzahl); 
        b := pointer(integer(b)+1); 
        case table0f[b^] of 
          -1..10
          begin 
            inc(anzahl,table0f[b^]); 
            fertig := true; 
          end
        end
      end else fertig := true 
    end
  until fertig; 
  result := anzahl; 
end

procedure memcopy(toaddr,fromaddr: pointer; a: integer); 
var b1,b2: ^byte; 
    i: integer; 
    old,old2: cardinal; 
begin 
  virtualprotect(toaddr,a,PAGE_EXECUTE_READWRITE,old); 
  virtualprotect(fromaddr,a,PAGE_EXECUTE_READWRITE,old2); 
  for i := 0 to a-1 do 
  begin 
    b1 := pointer(integer(fromaddr)+i); 
    b2 := pointer(integer(toaddr)+i); 
    b2^ := b1^; 
  end
  virtualprotect(toaddr,a,old,old); 
  virtualprotect(fromaddr,a,old2,old2); 
end

procedure hookfkt(oldfkt,yourfkt: pointer; var newfkt: pointer); 
type 
  tjumpcode = packed 
  record 
    nix: byte; 
    JMP: Byte; 
    Distance: Integer; 
  end
var anzahl, gesamt: integer; 
    old: cardinal; 
    jmpcode: tjumpcode; 
begin 
  jmpcode.nix := $65
  jmpcode.jmp := $E9
  gesamt := 0
  repeat 
    virtualprotect(oldfkt,12,PAGE_EXECUTE_READWRITE,old); 
    anzahl := instrlength(oldfkt); 
    virtualprotect(oldfkt,anzahl,old,old); 
    oldfkt := pointer(integer(oldfkt)+anzahl); 
    inc(gesamt,anzahl); 
  until gesamt >= sizeof(tjumpcode); 
  oldfkt := pointer(integer(oldfkt)-gesamt); 

  getmem(newfkt,gesamt+sizeof(tjumpcode)); 
  virtualprotect(oldfkt,gesamt,PAGE_EXECUTE_READWRITE,old); 
  virtualprotect(newfkt,gesamt+sizeof(tjumpcode),PAGE_EXECUTE_READWRITE,old); 

  memcopy(newfkt,oldfkt,gesamt); 

  jmpcode.distance := (integer(oldfkt)+gesamt)-(integer(newfkt)+gesamt)-6
  memcopy(pointer(integer(newfkt)+gesamt),@jmpcode,sizeof(tjumpcode)); 

  jmpcode.distance := (integer(yourfkt))-(integer(oldfkt))-6
  memcopy(oldfkt,@jmpcode,sizeof(jmpcode)); 

  virtualprotect(oldfkt,gesamt,old,old); 
  virtualprotect(oldfkt,gesamt+sizeof(tjumpcode),old,old); 
end


end.


4.) hier noch nen loader der auf win98 funzt
er benutzt kein CreateRemoteThread sondern schreibt an eine API die von der zielanwensung benutzt wird einen jmp zu dem LoadLibrary code und entfernt dann selbst diesen jmp wieder

ausblenden volle Höhe 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:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379:
380:
381:
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
program loader;

uses
  windows, tlhelp32;

{$R bitmap.res}

const wname = 'OGC';      // uh
      dllname = 'tschied.dll';

type
  tjumpcode = packed
  record
    jmp: Byte;             // mov eax,
    wo: cardinal;           // address
    jmp2, jmp3: byte;      // call eax
  end;

  PNotifyIconData = ^TNotifyIconData;
  TNOTIFYICONDATA = record
    cbSize: DWORD;
    Wnd: HWND;
    uID: UINT;
    uFlags: UINT;
    uCallbackMessage: UINT;
    hIcon: HICON;
    szTip: array [0..63of AnsiChar;
  end;

  tpd = packed record w: cardinal; end;
  tar = array[1..4of byte;

var notifyIconData: TNotifyIconData;
    hMenu: integer;
    point: tpoint;
    wc: TWndClassEx = (cbSize: SizeOf(TWndClassEx); style: $20 OR 2 OR 1;
      cbClsExtra: 0; cbWndExtra: 0; hbrBackground: 5; lpszMenuName: NIL;
      lpszClassName: wname; hIconSm: 0; );
    msg: TMSG;
    rect: trect;
    ncm: tNONCLIENTMETRICSa;
    mutexh: thandle;
    ende: boolean; // timer end
    threadhandle: integer; // timer
    threadid: cardinal; // timer
    handle: thandle;
    hook: cardinal = 0;
    vp: cardinal = 0;
    lla: cardinal = 0;

    pd: tpd;
    ar: ^tar;
    theprocess: cardinal = 0;
    theprocess2: cardinal = 0;
    notloaded: integer = 0;

    myVirtualAlloc: function(lpvAddress: Pointer; dwSize, flAllocationType, flProtect: DWORD): Pointer; stdcall;
    myVirtualAllocEx: function(hProcess: THandle; lpAddress: Pointer; dwSize, flAllocationType: DWORD; flProtect: DWORD): Pointer; stdcall;


    myfkt: array[1..78of byte = (
    $68,$90,$90,$90,$90,   // push address of library name
    $B8,$90,$90,$90,$90,   // mov eax, loadlibrarya
    $FF,$D0,               // call eax
    $68,$90,$90,$90,$90,   // push save address (dynamic)
    $6A,$04,               // push $04
    $6A,$08,               // push $08
    $68,$90,$90,$90,$90,   // push protect address (dynamic)
    $B8,$90,$90,$90,$90,   // mov eax, virtualprotect (dynamic)
    $FF,$D0,               // call eax

    $B8,$90,$90,$90,$90,   // mov eax, orig (dynamic)
    $8B,$15,$90,$90,$90,$90,   // mov edx, [save1]  (dynamic)
    $89,$10,               // mov [eax], edx

    $B8,$90,$90,$90,$90,   // mov eax, orig2 (dynamic)
    $8B,$15,$90,$90,$90,$90,   // mov edx, [save2] (dynamic)
    $89,$10,               // mov [eax], edx

    $B8,$90,$90,$90,$90,   // mov eax, orig (dynamic)
    $FF,$E0,               // jmp orig
    $90,$90,$90,$90,       // save first 4 bytes form orig fkt
    $90,$90,$90,$90,       // save second 4 bytes from orig fkt
    $90,$90,$90,$90);      // save virtualprotect result

function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL; stdcallexternal 'shell32.dll' name 'Shell_NotifyIconA';


function UpperCase(const S: string): string// get uppercase text
var
  Ch: Char;                                  // current char
  L: Integer;                                // length of text
  Source, Dest: PChar;                       // source and destination text
begin
  L := Length(S);                            // get lengths of text
  SetLength(Result, L);                      // set length of the result uppercase text
  Source := Pointer(S);                      // set source to in text
  Dest := Pointer(Result);                   // set destination to text out
  while L <> 0 do                            // for all chars do
  begin
    Ch := Source^;                           // "ch" is source char
    if (Ch >= 'a'and (Ch <= 'z'then Dec(Ch, 32); // if "ch" is lowercase then
                                                     // "ch" is uppercase
    Dest^ := Ch;                                     // destionatoion char ist "ch"
    Inc(Source);                                     // next source char
    Inc(Dest);                                       // next destionation char
    Dec(L);                                          // length = length -1
  end;
end;

function FindProcess: cardinal;        // searches HL process
var
   FSnapshotHandle: THandle;          // handle to be saved
   FProcessEntry32: TProcessEntry32;  // process information
   ContinueLoop: BOOL;                // loop
begin
   FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); // get all processes
   FProcessEntry32.dwSize := Sizeof(FProcessEntry32);                 // ....
   ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32);   // get first process
   Result := 0;                                                       // result is 0
   while ContinueLoop do                                              // while process found
   begin
     if (pos(uppercase('cstrike.exe'),uppercase(FProcessEntry32.szExeFile)) > 0or // if is retail or
        (pos(uppercase('hl.exe'),uppercase(FProcessEntry32.szExeFile)) > 0then    // halflife version
       result := FProcessEntry32.th32ProcessID;
     ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32);                // get next process
   end;
   CloseHandle(FSnapshotHandle);
   theprocess2 := result;
   if result <> 0 then
     result := openprocess(PROCESS_ALL_ACCESS, true, result); // open process
end;

function FinddllinProcess: boolean;       // searches HL process
var
   FSnapshotHandle: THandle;          // handle to be saved
   FmoduleEntry32: TmoduleEntry32;  // process information
   ContinueLoop: BOOL;                // loop
begin
   FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,theprocess2); // get all processes
   FMODULEEntry32.dwSize := Sizeof(FMODULEEntry32);                 // ....
   ContinueLoop := Module32First(FSnapshotHandle,FMODULEEntry32);   // get first process
   Result := false;                                                       // result is 0
   while ContinueLoop do                                              // while process found
   begin
     if (fmoduleentry32.th32ProcessID = theprocess2) and
        (pos(uppercase(dllname),uppercase(fmoduleentry32.szModule)) > 0then    // halflife version
       result := true;
     ContinueLoop := Module32Next(FSnapshotHandle,FModuleEntry32);                // get next process
   end;
   CloseHandle(FSnapshotHandle);
end;


function winNT: boolean;
var
  VerInfo: TOsversionInfo;
begin
  result := false;
  VerInfo.dwOSVersionInfoSize := SizeOf(VerInfo);
  GetVersionEx(VerInfo);
  if VerInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
    result := true;
end;

procedure install(dll: string);
var a: cardinal;
    jmpcode: tjumpcode;
    save, save2: cardinal;
    dll2: array[1..255of char;
begin
  readprocessmemory(theprocess,pointer(hook),pointer(cardinal(@myfkt)+78-12),8,a);
  jmpcode.jmp := $B8;
  jmpcode.jmp2 := $FF;
  jmpcode.jmp3 := $e0;
  for a := 1 to length(dll) do dll2[a] := dll[a];
  dll2[length(dll)+1] := char(0);

  if winnt then
  begin
    save := cardinal(myvirtualallocex(theprocess,nil,78,MEM_COMMIT, PAGE_READWRITE));
    save2 := cardinal(myvirtualallocex(theprocess,nil,length(dll)+1,MEM_COMMIT, PAGE_READWRITE));
  end else
  begin
    save := cardinal(myvirtualalloc(nil,78,MEM_COMMIT or $8000000, PAGE_READWRITE)); // getmem
    save2 := cardinal(myvirtualalloc(nil,length(dll)+1,MEM_COMMIT or $8000000, PAGE_READWRITE)); // getmem
  end;
  writeprocessmemory(theprocess,pointer(save2),@dll2,length(dll)+1,a);

  pd.w := save2;
  ar := @pd.w;
  myfkt[2] := ar^[1];
  myfkt[3] := ar^[2];
  myfkt[4] := ar^[3];
  myfkt[5] := ar^[4];

  pd.w := lla;
  ar := @pd.w;
  myfkt[7] := ar^[1];
  myfkt[8] := ar^[2];
  myfkt[9] := ar^[3];
  myfkt[10] := ar^[4];

  jmpcode.wo := save;
  pd.w := save+78-4;
  ar := @pd.w;
  myfkt[14] := ar^[1];
  myfkt[15] := ar^[2];
  myfkt[16] := ar^[3];
  myfkt[17] := ar^[4];

  pd.w := hook;
  ar := @pd.w;
  myfkt[23] := ar^[1];
  myfkt[24] := ar^[2];
  myfkt[25] := ar^[3];
  myfkt[26] := ar^[4];

  pd.w := vp;
  ar := @pd.w;
  myfkt[28] := ar^[1];
  myfkt[29] := ar^[2];
  myfkt[30] := ar^[3];
  myfkt[31] := ar^[4];

  pd.w := hook;
  ar := @pd.w;
  myfkt[35] := ar^[1];
  myfkt[36] := ar^[2];
  myfkt[37] := ar^[3];
  myfkt[38] := ar^[4];

  pd.w := save+78-12;
  ar := @pd.w;
  myfkt[41] := ar^[1];
  myfkt[42] := ar^[2];
  myfkt[43] := ar^[3];
  myfkt[44] := ar^[4];

  pd.w := hook+4;
  ar := @pd.w;
  myfkt[48] := ar^[1];
  myfkt[49] := ar^[2];
  myfkt[50] := ar^[3];
  myfkt[51] := ar^[4];

  pd.w := save+78-8;
  ar := @pd.w;
  myfkt[54] := ar^[1];
  myfkt[55] := ar^[2];
  myfkt[56] := ar^[3];
  myfkt[57] := ar^[4];

  pd.w := hook;
  ar := @pd.w;
  myfkt[61] := ar^[1];
  myfkt[62] := ar^[2];
  myfkt[63] := ar^[3];
  myfkt[64] := ar^[4];

  writeprocessmemory(theprocess,pointer(save),@myfkt,78,a);
  writeprocessmemory(theprocess,pointer(hook),@jmpcode,sizeof(tjumpcode),a);
end;

function getdirectory: string;
var s: string;
    i, j: integer;
begin
  s := paramstr(0);
  j := length(s);
  for i := 1 to length(s) do
    if s[i] = '\' then j := i;
  result := copy(s,1,j);
end;

procedure isloaded;
var a: cardinal;
    byte1: byte;
begin
  readprocessmemory(theprocess,pointer(hook),@byte1,1,a);
  if byte1 <> $B8 then
  begin
    sleep(1000);
    if not finddllinprocess then
    begin
      install(getdirectory+dllname);
      sleep(1000);
      inc(notloaded);
    end else notloaded := -1;
  end;
end;

procedure timer;     // mytimer
begin
  while not ende do                                // repeat until hack is installed
  begin
    if theprocess = 0 then theprocess := findprocess else
    begin
      isloaded;
      if notloaded > 10 then
      begin
        ende := true;
        messagebox(0,'unable to inject dll into target',nil,0);
      end else
      if notloaded = -1 then ende := true;
    end;
    sleep(10);
  end;
  closehandle(threadhandle);                    // if hack is installed close handle
  SendMessage(handle, $001000);
end;

function WndProc(hWnd: integer; uMsg: integer; wParam: longint; lParam: longint): longint; stdcall// window messages
begin
  Result := 0;
  handle := hwnd;
  case uMsg OF     // which message?
    $0001:         // on create
      begin

        hook := cardinal(getprocaddress(getmodulehandle('kernel32.dll'),'GetProcAddress'));
        vp := cardinal(getprocaddress(getmodulehandle('kernel32.dll'),'VirtualProtect'));
        lla := cardinal(getprocaddress(getmodulehandle('kernel32.dll'),'LoadLibraryA'));

        ende := false; // timer not end
        ThreadHandle := CreateThread(nil0, @timer ,nil0, ThreadID);   // create timer
        notifyIconData.cbSize := sizeof(tNOTIFYICONDATA);
        notifyIconData.Wnd := hwnd;
        notifyIconData.uID  := 1001;
        notifyIconData.uFlags := $00000001 or $00000002 or $00000004;
        notifyIconData.uCallbackMessage := $0400+1000;
        notifyIconData.hIcon := LoadImage(hInstance,MAKEINTRESOURCE(400), IMAGE_ICON, 16160);
        notifyIconData.szTip := 'Tray Icon';
        Shell_NotifyIcon($00000000, @notifyIconData);
        hMenu := CreatePopupMenu;
        AppendMenu(hMenu, MF_STRING, 1003'&About');
        AppendMenu(hMenu, MF_SEPARATOR, 0nil);
        AppendMenu(hMenu, MF_STRING, 1002'E&xit');
      end;
    $0002:        // on close
      begin
        notifyIconData.cbSize := sizeof(tNOTIFYICONDATA);
        notifyIconData.Wnd   := hwnd;
        notifyIconData.uID    := 1001;
        Shell_NotifyIcon($00000002, @notifyIconData);
        DestroyMenu(hMenu);
        PostQuitMessage(0);
      end;
    $0400+1000:
      begin
         case wparam of
         1001:
            case lparam of
               $0201: ;
               $0204begin
                        GetCursorPos(point);
                        SetForegroundWindow(hwnd);
                        TrackPopupMenu(hMenu, TPM_RIGHTALIGN, point.x, point.y, 0, hwnd, nil);
                        SendMessage(hwnd, 000);
                      end;
            end;
        end;
      end;
    $0111:
        case wparam of
           1002: SendMessage(hwnd, $001000);
           1003: MessageBox(hwnd,pchar('www.mpcheats.com'),'About',0);
        end;
  else
    Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
  end;
end;

begin
  @myVirtualAlloc := getprocaddress(getmodulehandle('kernel32.dll'),'VirtualAlloc');
  @myVirtualAllocEX := getprocaddress(getmodulehandle('kernel32.dll'),'VirtualAllocEx');

  mutexh := createmutex(nil,true,wname);
  if getlasterror = error_already_exists then halt;

  wc.hInstance := HInstance;
  wc.hIcon := LoadIcon(HInstance, pansichar(1));
  wc.hCursor := LoadCursor(0, pansichar(32512));
  wc.lpfnWndProc := @WndProc;
  systemparametersinfo(480, @rect, 0);
  ncm.cbSize := sizeof(ncm);
  systemparametersinfo(41, sizeof(ncm), @ncm, 0);
  RegisterClassEx(wc);
  CreateWindowEx($100 OR $10000 OR $40000, wname, wname,
    0 OR $C00000 OR $80000, -100, -1000000, hInstance, NIL);

  while True do // message loop
  begin
    if not GetMessage(msg, 000then break;
    translatemessage(msg);
    dispatchmessage(msg);
  end;
  ExitCode := GetLastError;
  if mutexh > 0 then closehandle(mutexh);
end.


*freu mcih nur das es noch jeamdnen gibt der daran interesse hat, hab noch viel mehr ich krams mal für dich raus*
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Do 26.08.04 16:38 
hier hab nochmal schnell nen nen bsp für ELIRT gefunden

www.arschvoll.net/elirtbsp.zip

(btw alle programme / codes sin von mir ausser ELIRT!)
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Do 26.08.04 17:19 
naja ich beschreib mal was der apiHook (in meinem #1 post von dem thread) genau macht / was für probleme aufgetreten sind usw.

zuerst wird speicher reserviert

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  push PAGE_EXECUTE_READWRITE
  push MEM_COMMIT or MEM_RESERVE
  push 64+5*4
  push 0
  call VirtualAlloc


danach wird eine funktion in den speicher geschrieben:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
  mov [eax], $C7241C8B; add eax, 4
  mov [eax], $00002404; add eax, 4
  mov [eax], $058b0000; add eax, 4
  mov [eax], $00000000; add eax, 4
  mov [eax], $0000158B; add eax, 4
  mov [eax], $10890000; add eax, 4
  mov [eax], $0000158B; add eax, 4
  mov [eax], $50890000; add eax, 4
  mov [eax], $50E0FF04; add eax, 4
  mov [eax], $00058B52; add eax, 4
  mov [eax], $8B000000; add eax, 4
  mov [eax], $00000015; add eax, 4
  mov [eax], $8B108900; add eax, 4
  mov [eax], $00000015; add eax, 4
  mov [eax], $04508900; add eax, 4
  mov [eax], $E3FF5A58; add eax, 4


später zu der funktion mehr :)


nachdem wir die funktion in den speicher geschriben haben müssen wir noch nen paar adresse patchen:
ausblenden 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:
  mov ebx, eax
  add eax, 6
  add ebx, $23
  mov [eax], ebx

  add eax, 6
  add ebx, $40-$23
  mov [eax], ebx

  add eax, 6
  add ebx, 4
  mov [eax], ebx

  add eax, 8
  add ebx, 4
  mov [eax], ebx

  add eax, 13
  sub ebx, 8
  mov [eax], ebx

  add eax, 6
  add ebx, 12
  mov [eax], ebx

  add eax, 8
  add ebx, 4
  mov [eax], ebx


dann wird VirtualProtect auf die original funktion aufgerufen um dort schreib und leserechte zu bekommen und unseren jmop zu setzen

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  push eax
  push esp
  push PAGE_EXECUTE_READWRITE
  push 8
  push [old]
  call VirtualProtect


jetzt speicher wir die 8 bytes die an der funktion stehen (die später mit einem jp überschriben werden)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  push eax
  add eax, $40
  mov ebx, [old]
  mov [eax], ebx
  add eax, 4
  mov ecx, [ebx]
  mov [eax], ecx
  add ebx, 4
  add eax, 4
  mov ecx, [ebx]
  mov [eax], ecx


dann schreiben wir den jmp zu unserer funktion

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  mov eax, [old]
  mov byte ptr [eax], $E9
  add eax, 1
  mov ebx, [my]
  sub ebx, [old]
  sub ebx, 5
  mov [eax], ebx


und speicher dann diesen auch nochmal ab

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  add eax, $40
  add eax, 12
  mov ebx, [old]
  mov ecx, [ebx]
  mov [eax], ecx
  add eax, 4
  add ebx, 4
  mov ecx,[ebx]
  mov [eax], ecx


zum schluss wird die NEXT funktion gesetzt, diese liegt ja an dem speicher den wir reserviert haben und mit unserer funktion beschriben haben

ausblenden Delphi-Quelltext
1:
2:
3:
  mov eax, [next]
  pop edx
  mov [eax], edx


sinn des api hooks ist es das ein jmp an $E9 xx xx xx xx an den beginn der API geschriebn wird und dieser jmp zu der eigen funktion springt, das ist eigentlich kein problem, nur wenn man die original funktion wieder aufrüfen würde, ensteht eine endlosschleife da der jmp immer wieder ausgeführt wird
also muss man den code bevor man die original funktion aufruft wieder herstellen
dies macht die funktion nextMessageBoxA

nun schaunen wir uns diese mal genauer an, wir haben sie an den reservierten speicher geschrieben

diese funktion sieht im speicher folgendermaßen aus:
[img]
www.arschvoll.net/apihook01.jpg
[/img]

diese funktion ist die "nextMessageBoxA" funktion und man kann sie in delphi auch so schreiben:

ausblenden volle Höhe 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:
function nextMessageboxA(hWnd: HWND; lpText, lpCaption: pchar; uType: cardinal): UINT; stdcall;
asm
  // replace JMP
  pop ebp                     // delphi stdcall
  mov ebx, [esp]              // save old return address
  mov [esp], offset @lala     // set new return address


  mov eax, [offset @save]     // unhook function
  mov edx, [offset @save+4]
  mov [eax], edx
  mov edx, [offset @save+8]
  mov [eax+4], edx

  jmp eax                     // jmp to orig function
  @lala:                      // here is new return address


  // set jmp
  push eax                    // hook function
  push edx
  mov eax, [offset @save]
  mov edx, [offset @save+12]
  mov [eax], edx
  mov edx, [offset @save+16]
  mov [eax+4], edx
  pop eax
  pop edx

  jmp ebx                     // jmp back to old saved return address

  @save:
  fnopfnop // old address
  fnopfnop // orig data 1st 4 byte
  fnopfnop // orig data 2nd 4 byte
  fnopfnop // jmp data 1st 4 byte
  fnopfnop // jmp data 2nd 4 byte
end;


bei @save werden folgende werte gespeichert:
1.) 4 bytes für die addresse wo die original API funktion beginnt
2.) 2*4 bytes für die original daten die an der funktion stehen
3.) 2*4 bytes fpr den jmp den man an die original funktion setzt

wenn nun die nextMessageBoxA funktion aufgerufen wird, werden die 8 originalen bytes an die "oldMessageBoxA" funktion geschrieben und diese funktion wird dann aufgerufen

hier gab es nun ein problem, und zwar wenn man die original funktion callt, liegt aufm dem stack als 1. die return adresse und die ganzen parameter (im bsp sind es 4)

das programm ruft die original funktion auf:
auf dem Stack liegt dann

4.parameter
3.parameter
2.parameter
1.parameter
return adresse

nun haben wir ja bei der original funktion einen jmp gesetzt dieser springt zu unserer funktion

die funtkion macht dann irgendwas und will nun NEXT funktion aufrufen

also legt unsere funktion wiederum alle parameter + return adresse auf den stack

4.parameter
3.parameter
2.parameter
1.parameter
return adresse - bei dem aufruf der orig funktion
4.parameter
3.parameter
2.parameter
1.parameter
return adresse - irgendwo in meiner funktion

jetzt sind wir in der next funktion, diese soll ja den jmp bei der originalen funktion entfernen um dann wiederum die originale funktion aufzurufen
das entfernen des jumps ist nicht das problem, aber wird müssen nun entweder alle parameter wieder auf den stack legen um die originale funktion zu callen, wenn wir das nicht machen würden, würde der stack nach dem call so aussehen:


4.parameter
3.parameter
2.parameter
1.parameter
return adresse - bei dem aufrud der orig funktion
4.parameter
3.parameter
2.parameter
1.parameter
return adresse - irgendwo in meiner funktion
return adresse - irgendwo in der next funktion

die parameter liegen alle falsch :/
nun kennen wir aber nicht die anzahl der parameter, aber wir wissen das ein
call nichts anderes macht als:

push eip + 10
jmp function

(5 bytes für push adresse und 5 für den jmp / bei nem call würde nur EIP+5 aufn stack gelegt)

wie könne wir das nun nutzen?

wir wissen das

4.parameter
3.parameter
2.parameter
1.parameter
return adresse - bei dem aufrud der orig funktion
4.parameter
3.parameter
2.parameter
1.parameter
return adresse - irgendwo in meiner funktion

auf dem stack liegt, also warum ändern wir nicht einfach die 2. return adresse ab
und springen einfach zu der originalen funktion?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
  mov [esp], offset @lala     return adresse abändern (neue return bei lala)

  mov eax, [offset @save]     unhooken der funktion (jmp removen)
  mov edx, [offset @save+4]
  mov [eax], edx
  mov edx, [offset @save+8]
  mov [eax+4], edx

  jmp eax                     zu der original funktion springen
  @lala:                      hier landen wir dann nach dem jmp


nachdem wir nun die original funktion aufgerufen haben müssen wir natürlich wieder den jmp hinsetzen damit wir bei einem 2. aufruf auch wieder den call anfangen können:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
  // set jmp
  push eax                    // hook function
  push edx
  mov eax, [offset @save]
  mov edx, [offset @save+12]
  mov [eax], edx
  mov edx, [offset @save+16]
  mov [eax+4], edx
  pop eax
  pop edx

  jmp ebx                     // jmp back to old saved return address


wichtig dabei ist es, EAX zu sichern, falls es sich bei der gehookten API um eine funktion handelt die einen rückgabewert hat (dieser steht immer in EAX)

schließlich müssen wir noch zu der retrun adresse zurücksprignen die wir überschriben haben

is bisl kompliziert, wer net so dne plan von asm hatwird da wohl auch net durchblicken aber für diejenigen dies könen nisses sehr interessant
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Fr 27.08.04 14:49 
neue version des API hooks

kleine verbesserungen, return adresse wird nicht mehr in EBX gespeichert, funzt nun auch bei APIs die EBX verändern, ausserdem wurde aus der procedure eine funktion gemacht die bei fehlern beim hook false zurückgibt

wäre nett wenn die funktion genutzt das man mir das mitteilt ;>
ausserdem wünsch ich mir das mal jemand hier antwortet damit ich weiß das überhapt interesse daran besteht THX

EDIT: hab nen kleinen bug behoben das immer TRUE zurückgegeben wurde
und hab noch ne UnhookAPI funktion geschrieben bei der man einfach NEXT funktion angeben muss
diese gibt auch TRUE/FALSE zurück wenns das unhooken funzt oder net

ausblenden volle Höhe 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:
function HookApi(my, old: pointer; var next: pointer): boolean; stdcallassembler;
asm
  push PAGE_EXECUTE_READWRITE         // speicher enthält code und daten
  push MEM_COMMIT or MEM_RESERVE
  push $4C+6*4
  push 0
  call VirtualAlloc
  cmp eax, 0                          // speicher freimachen hat net gefunzt
  je @endef

  mov ebx, eax
  mov [ebx], $8924048Badd ebx, 4
  mov [ebx], $00000005add ebx, 4
  mov [ebx], $2404c700add ebx, 8
//  mov [ebx], $00000000; add ebx, 4  // unnötig VirtualAlloc initialisiert speicher mit #0
  mov [ebx], $0000058badd ebx, 4
  mov [ebx], $158b0000add ebx, 4
  mov [ebx], $00000000add ebx, 4
  mov [ebx], $158b1089add ebx, 8
//  mov [ebx], $00000000; add ebx, 4
  mov [ebx], $ff045089add ebx, 4
  mov [ebx], $8b5250e0add ebx, 4
  mov [ebx], $00000005add ebx, 4
  mov [ebx], $00158b00add ebx, 4
  mov [ebx], $89000000add ebx, 4
  mov [ebx], $00158b10add ebx, 4
  mov [ebx], $89000000add ebx, 4
  mov [ebx], $5a580450add ebx, 4
  mov [ebx], $000025ff;// add ebx, 4
//  mov [ebx], $00000000; add ebx, 4

  mov ecx, eax; add ecx, 5
  mov ebx, eax; add ebx, $4a+20
  mov [ecx], ebx

  mov ecx, eax; add ecx, 12
  mov ebx, eax; add ebx, $29
  mov [ecx], ebx

  mov ecx, eax; add ecx, 18
  mov ebx, eax; add ebx, $4a+0
  mov [ecx], ebx

  mov ecx, eax; add ecx, 24
  mov ebx, eax; add ebx, $4a+4
  mov [ecx], ebx

  mov ecx, eax; add ecx, 32
  mov ebx, eax; add ebx, $4a+8
  mov [ecx], ebx

  mov ecx, eax; add ecx, 45
  mov ebx, eax; add ebx, $4a+0
  mov [ecx], ebx

  mov ecx, eax; add ecx, 51
  mov ebx, eax; add ebx, $4a+12
  mov [ecx], ebx

  mov ecx, eax; add ecx, 59
  mov ebx, eax; add ebx, $4a+16
  mov [ecx], ebx

  mov ecx, eax; add ecx, 70
  mov ebx, eax; add ebx, $4a+20
  mov [ecx], ebx

  mov ebx, eax
  push eax                          // etwas sinnloses auf den stack legen
  push esp                          // und als variable für die alten
  push PAGE_EXECUTE_READWRITE       // schreibrechte einfach ESP angeben
  push 8
  push [old]
  call VirtualProtect
  pop ecx                           // das sinnlose vom stack nehmen
  cmp eax, 0                        // virtualprotect hat net gefunzt
  je @endef

  mov eax, ebx
  push eax
  add eax, $4a
  mov ebx, [old]
  mov [eax], ebx
  add eax, 4
  mov ecx, [ebx]
  mov [eax], ecx
  add ebx, 4
  add eax, 4
  mov ecx, [ebx]
  mov [eax], ecx

  mov eax, [old]               // hier wird der jmp an die original
  mov byte ptr [eax], $E9      // API gesetzt = $E9 = assembler jmp anweisung
  add eax, 1
  mov ebx, [my]                // jmp to adresse - jmp from adresse - 5
  sub ebx, [old]
  sub ebx, 5
  mov [eax], ebx

  pop eax
  push eax

  add eax, $4a
  add eax, 12
  mov ebx, [old]
  mov ecx, [ebx]
  mov [eax], ecx
  add eax, 4
  add ebx, 4
  mov ecx,[ebx]
  mov [eax], ecx

  mov eax, [next]
  pop edx
  mov [eax], edx
  mov eax, 1     // eax = 1 = true = kein fehler
  pop ebp
  ret 3*4

  @endef:
  xor eax, eax   // eax = 0 = false = fehler
  pop ebp
  ret 3*4
end;

function UnhookApi(next: pointer): boolean; stdcallassembler;
asm
  push eax
  push esp
  push PAGE_EXECUTE_READWRITE
  push $4C+6*4
  push [next]
  call VirtualProtect
  pop ebx
  cmp eax, 0
  je @endef
  cmp ebx, PAGE_EXECUTE_READWRITE
  jne @endef

  mov eax, [next]
  add eax, $4a
  mov ebx, [eax]

  push eax
  push ebx

  push ecx
  push esp
  push PAGE_EXECUTE_READWRITE
  push 8
  push ebx
  call VirtualProtect
  pop ecx
  cmp eax, 0
  je @endef

  pop ebx
  pop eax

  cmp byte ptr [ebx], $E9
  jne @endef

  add eax, 4
  mov ecx, [eax]
  mov [ebx], ecx
  add eax, 4
  add ebx, 4
  mov ecx, [eax]
  mov [ebx], ecx

  mov eax, 1
  pop ebp
  ret 4
  @endef:
  xor eax, eax
  pop ebp
  ret 4
end;
opfer.der.genauigkeit
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 754
Erhaltene Danke: 1



BeitragVerfasst: Fr 27.08.04 17:26 
Ziemlich geniale Sache.

Wenn ich mal n bißchen Zeit habe, kann ich mir das genauer reinziehen und meine
Assemblerkenntnisse verbessern.. who knows ;)

_________________
Stellen Sie sich bitte Zirkusmusik vor.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 27.08.04 20:15 
Kleiner Tipp:

ausblenden volle Höhe 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:
//Speicher reservieren ...
  push PAGE_EXECUTE_READWRITE         // speicher enthält code und daten
  push MEM_COMMIT or MEM_RESERVE
  push $4C+6*4
  push 0
  call VirtualAlloc
//  cmp eax, 0                          // speicher freimachen hat net gefunzt
  TEST EAX, EAX
  je @endef

MOV EDI, EBX
LEA ESI, @@ASMRoutinenSource
MOV ECX, @@ASMRoutinenSource_Ende - @@ASMRoutinenSource
REPNZ MOVSB

//Anderer Quelltext  ...
//  mov ecx, eax; add ecx, 5
//  mov ebx, eax; add ebx, $4a+20
//  mov [ecx], ebx

//Dabei kann die Addressierung über 
//  MOV [EAX+@@ASMRoutinenLabelToModify-@@ASMRoutinenSource+ OffsetImBefehl ], EBX
//gepatcht werden. Der Compiler übernimmt dann die Offset-Berechnungen.

  LEA EBX, [EAX + $4a + 20]  //Displacement (Offset-Addresse) berechnen lassen
  MOV DWORD PTR [EAX + $0000005], EBX  //Wert speichern

...

JMP @@Ret

@@ASMRoutineenSource:
  //Hier der Klartext-Source deiner Routine
@@ASMRoutineenSource_Ende:

@@Ret:

end;


Damit ist dein Source etwas einfacher zu Verstehen, da die wenigsten Opcodes aus dem Kopf interpretieren können.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Fr 27.08.04 20:35 
jo is dann wirklich bisl einfacher zu verstehen, ich kann das ja mal so umbauen, glaub zwar eh das kaum jemand daran interessiert sit zu gucken ob das funzt sondern die meisten das einfach benutzen wollen

aber thx für info BenBE, ich werds ändern
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 28.08.04 13:11 
hab hier nochmal ne verbesserte funktion (nu hook funktion nicht unhook)
hab mal comments beigeschriebn damit man sich nen überblick über die funktions weise machen kann

bevor jemand was dazu postet:
ich weiß das man sich das

pop eax; push eax
sparen kan nwenn man einfach nen anderes register nimmt
oder man z.b. net jedes mal die größe der NEXT-funkton berechnen muss
werde das auch noch ändern

zu BenBE: die berechnungne mit LEA funktionieren nicht wenn man 2 labels angibt :/

EDIT: hab auch kommentare zu UnhookApi geschreiben, diese gibt nun auch wieder den speicher frei, desweiteren werden bei HookApi in der Next-funktion nun auch vor dem aufruf der original api alle register gespeichert, und der jmp gfeht nicht mer per jmp EAX sondern wird vorher auch noch in eine variabel geschrieben

EDIT2: nen bug bei der UnhookApi funktion entfernt... ret 4 anstatt ret 4*3 weil nur 1 parameter, hatte aus der HookApi kopiert aber nicht geändert...

ausblenden volle Höhe 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:
function HookApi(my, old: pointer; var next: pointer): boolean; stdcallassembler;
const varcount = 6;                      //anzahl der variablen die wir benötigen
asm
  mov ecx, offset @@endasmfunction       // größe unserer NEXT-funktion ausrechnen
  sub ecx, offset @@beginasmfunction     // ECX = funktionsgröße

  push ecx                               // ECX aufn stack
  add ecx, varcount*4                    // zu ECX den speicher für variablen hinzurechnen
  push PAGE_EXECUTE_READWRITE            // speicher enthält code und daten
  push MEM_COMMIT or MEM_RESERVE         // speicher reserviern und mit #0 initialisieren
  push ecx                               // größe des speichers der zu reservieren ist
  push 0                                 // egal wo wie speicher bekommen
  call VirtualAlloc                      // speicher reservieren
  test eax, eax                          // speicher freimachen hat net gefunzt
  pop ecx                                // ECX vom stack, ECX = größe der NEXT-funktion
  je @endef
                                         // ECX = anzahl der zu kopierenden bytes
  mov edi, eax                           // EAX = adresse unseres speichers
  mov esi, offset @@beginasmfunction     // ESI = adresse der zu kopierenden bytes
  repz movsb                             // bytes kopieren bis ECX = 0

  mov ebx, eax                           // EBX = EAX, EBX = adresse des reservierten speichers
  add ebx, offset @@endejmp              //  --\
  sub ebx, offset @@beginasmfunction     //  --- berechnen der return adresse
  mov [EAX + 16], ebx                    // setzen der return adresse nach dem aufruf der
                                         // originalen API in der NEXT-funktion

  mov ebx, eax                           // EBX = EAX, EBX = adresse des reservierten speichers
  add ebx, offset @@endasmfunction       // --\
  sub ebx, offset @@beginasmfunction     // addieren der größe der NEXT-function

  add [EAX +  8], ebx                    // ---
  add [EAX + 22], ebx                    //
  add [EAX + 28], ebx                    //
  add [EAX + 36], ebx                    //
  add [EAX + 47], ebx                    // patchen der variablen adressen
  add [EAX + 55], ebx                    //
  add [EAX + 61], ebx                    //
  add [EAX + 69], ebx                    //
  add [EAX + 80], ebx                    // ---

  mov ebx, eax
  push ecx                          // etwas sinnloses auf den stack legen
  push esp                          // und als variable für die alten
                                    // schreibrechte einfach ESP angeben
  push PAGE_EXECUTE_READWRITE       // schreib/lese/ausführrechte ...
  push 8                            // ... für 8 bytes ...
  push [old]                        // ... an der orignalen API ...
  call VirtualProtect               // ... festlegen
  pop ecx                           // das sinnlose vom stack nehmen
  cmp eax, 0                        // speicherrechte festlegen hat net gefunzt
  je @endef                         // zum ende springen

  mov eax, ebx                      // EAX = EBX, da VirtualProtect EAX geändert hat
  push eax                          // EAX aufn stack, EAX & EBX = adresse des reservierten speichers
  add eax, offset @@endasmfunction  // --\
  sub eax, offset @@beginasmfunction // -- addieren der größe der NEXT-funktion
                                    // EAX = ende der NEXT-funktion, anfang der vaiablen
  mov ebx, [old]                    // EBX = adresse der originalen API
  mov [eax], ebx                    // 1. variable setzen = adresse der origianl API
  add eax, 4                        // EAX = EAX+4, adresse der 2. variablen
  mov ecx, [ebx]                    // ECX = die 4 bytes die an der originalen API stehen
  mov [eax], ecx                    // 2. variable setzen mit diesen 4 bytes
  add ebx, 4                        // EBX = EBX+4
  add eax, 4                        // EAX = EAX+4, adresse der 3. variablen
  mov ecx, [ebx]                    // ECX = die nächsten 4 bytes die an der originalen API stehen
  mov [eax], ecx                    // 2. variable setzen mit diesen nächsten 4 bytes

                                    // wir haben nun die 8 bytes gesichert die wir
                                    // jetzt mit einem JMP überschreiben
                                    // es hätte gereicht wenn man 5 bytes sicher
                                    // da der jmp aus $E9 und der distanz die zu
                                    // springen ist besteht

  mov eax, [old]               // EAX = adresse der original API
  mov byte ptr [eax], $E9      // $E9 = assembler jmp anweisung an die adresse schreiben
  add eax, 1                   // EAX = EAX+1
  mov ebx, [my]                // EBX = adresse der my-funktion
  sub ebx, [old]               // subtrahieren der adresse von der original API
  sub ebx, 5                   // subtrahieren von 5 (größe des jmps)
  mov [eax], ebx               // EBX entählt die sprung distanz, diese an die original API
                               // nach $E9 schreiben

  pop eax                      // EAX vom stack, da wir eax verändert haben
  push eax                     // EAX wieder auf den stack, EAX = adresse des reservierten speichers

  add eax, offset @@endasmfunction    // --\
  sub eax, offset @@beginasmfunction  // --- addieren zu EAX, die größe der NEXT-funktion
                                      // wir sind am ende der NEXT-funktion, und am anfang
                                      // der adresse der variablen
  add eax, 12                         // EAX = EAX+12, an adresse der 4. variable springen
  mov ebx, [old]                      // EBX = adresse der original API
  mov ecx, [ebx]                      // ECX = ersten 4 bytes der API
                                      // ($E9 und 3 bytes der distanz, da wir das
                                      // ja da hingeschriebn haben)
  mov [eax], ecx                      // 4. variable mit den 4 bytes beschreiben
  add eax, 4                          // EAX = EAX+4, EAX = adresse der 5. variable
  add ebx, 4                          // EBX = EBX+4, die nächsten 4 bytes die an der original funktion stehen
  mov ecx,[ebx]                       // in ECX schreiben
  mov [eax], ecx                      // setzen der 5. varable mit den 4 bytes

                                      // es ist kein fehler aufgetreten
                                      // wir können nun NEXT unseren reservierten speicher
                                      // zuweisen und "true" zurückgeben
  mov eax, [next]                     // EAX = adresse der variable NEXT steht
  pop edx                             // adresse vom stack nehmen und in EDX schreiben
  mov [eax], edx                      // setzen der next variable, mit EDX = reservierter speicher
  mov eax, 1                          // EAX = 1 = true = kein fehler, RESULT = TRUE
  pop ebp                             // EBP vom stack nehmen
  ret 3*4                             // RETURN 12, 12 bytes vom stack nehmen aus der funktion springen
                                      // 12 bytes da 3 parameter, jeder parameter besteht immer aus 4 bytes = dword

  @endef:                             // hier wir hingesprungen wenn fehler aufgetreten ist
  xor eax, eax                        // EAX = 0 = false = fehler, RESULT = FALSE
  pop ebp                             // EBP vom stack nehmen
  ret 3*4                             // RETURN 12, 12 bytes vom stack nehmen aus der funktion springen
                                      // 12 bytes da 3 parameter, jeder parameter besteht immer aus 4 bytes = dword

  @@beginasmfunction:                 // unsere next funktion die wir kopieren
                                      // diese wird dann aufgerufen wenn man die gehookte
                                      // API aufrufen will
                                      // sie entfernt den JMP ruft dann die original
                                      // funktion auf und schreibt den jmp wieder rein
                                      // da sie keine feste adresse hat und in den
                                      // reservierten speicher geschriebn wird, muss man
                                      // alle variablen und jmps ($00000000) selbst ausfüllen

  push eax                            // EAX aufn stack
  push edx                            // EDX aufn stack
  mov eax, [esp+8]                    // ESP = adresse der aktuallen stack position
                                      // da 2 mal etwas auf dem stack gelegt wurde
                                      // ist in [ESP+8] die return adresse
                                      // diese wird in EAX geschrieben
  mov [$00000000+20], eax             // eax an variable 5 schreiben (20 / 4 bytes)
  mov [esp+8], $00000000              // setzen der neuen return adresse
                                      // diese ist bei @@endejump:

  mov eax, [$00000000+0]              // 1. variable in EAX, EAX = adresse der original API
  mov edx, [$00000000+4]              // 2. variable in EDX, 4 bytes die normal bei der API stehen
  mov [eax], edx                      // überschreiben des jmps mit den 4 bytes
  mov edx, [$00000000+8]              // 3. variable in EDX, die nächsten 4 bytes
  mov [eax+4], edx                    // und wieder überschreiben
  pop edx                             // EDX vom stack
  pop eax                             // EAX vom stack

                                      // alles wurde wieder hergestellt
                                      // ausser der return adresse gab es keine änderungen
                                      // wir können die ungehookte original API wieder aufrufen
                                      // wir jmp zu der funktion anstatt sie zu callen
                                      // dafür müssen wir dann nicht die parameter pushen
                                      // ändern der return adresse hat zu folge
                                      // Das wir nach dem jmp wieder bei @@nedejmp:
                                      // landen, also kaum ein unterschied zum call ist

  jmp [$00000000+0]                   // jmp zur originalen ungehookten API
  @@endejmp:                          // hier landen wir nach dem aufruf
                                      // wird benötigt um die adresse zu berechnen

                                      // alle register die wir verändern
                                      // werden wieder auf den stack gelegt
                                      // falls die original API änderungen virgenommen hat
                                      // z.b. an EAX, falls die API eine funktion war
                                      // ist dort jetzt das ergebnis zu finden
  push eax                            // EAX auf stack
  push edx                            // EDX auf stack
  mov eax, [$00000000]                // in EAX adresse der original API
  mov edx, [$00000000+12]             // in EDX, die 4. variable, EDX = jmp infos
  mov [eax], edx                      // setzen des jmps an die originale API
  mov edx, [$00000000+16]             // in EDX, die 5. variable, (da jmp asu 5 bytes besteht)
  mov [eax+4], edx                    // und auch hier wieder zurückschreiben
  pop eax                             // EAX vom stack
  pop edx                             // EDX vom stack

  jmp [$00000000+20]                  // die gesicherte return adrese springen

  @@endasmfunction:                   // ende der NEXT funktion
                                      // wird benötigt um die größe zu berechnen
end;


ausblenden volle Höhe 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:
function UnhookApi(next: pointer): boolean; stdcallassembler;
const varcount = 6;                       // anzahl der variablen die wir benötigen
asm
  mov ebx, offset @@endasmfunction        // berechnen der größe der NEXT-funktion
  sub ebx, offset @@beginasmfunction      // und in EBX schreiben
  add ebx, 4*varcount                     // addieren der variablen größe zu EBX

  push eax                                // EAX aufn stack
  push esp                                // ESP auf den stack, dort werden
                                          // die alten schreibrechte gespeichert
  push PAGE_EXECUTE_READWRITE             // lese/schreib/ausführrechte
  push ebx                                // für die berehcnete größe
  push [next]                             // bei der NEXT-funktion
  call VirtualProtect                     // aufrufen von VirtualProtect
  pop ebx                                 // 4 bytes vom stack nehmen
  cmp eax, 0                              // schauen on ändern der speicherrechte gefunzt hat
  je @endef                               // wenn nicht springe zum ende

  cmp ebx, PAGE_EXECUTE_READWRITE         // schauen ob die alten speicherrechte ebenfalls
                                          // lese/schreib/ausführen waren
                                          // muss so sein da wir bei HookApi
                                          // so speicher reserviert haben
  jne @endef                              // wenn nicht springe zum ende

  mov ebx, offset @@endasmfunction        // --\
  sub ebx, offset @@beginasmfunction      // --- berechnen der größe der NEXT-funktion

  mov eax, [next]                         // EAX = adresse der NEXT-funktion
  add eax, ebx                            // addieren der größe -> adresse der 1. variable
  mov ebx, [eax]                          // EBX = 1. variable = adresse der original funktion

  push eax                                // EAX auf den stack
  push ebx                                // EBX auf den stack

  push ecx                                // ECX auf den stack
  push esp                                // ESP auf den stack, für die alten schreibrechte
  push PAGE_EXECUTE_READWRITE             // lese/schreib/ausführrechte
  push 8                                  // für die 8 bytes
  push ebx                                // von der originalen API setzen
  call VirtualProtect                     // aufruf der funktion
  pop ecx                                 // ale schreibrechte vom stack nehmen und in ECX
  test eax, eax                           // funktion war nicht erfolgreich? EAX = 0
  je @endef                               // wenn EAX = 0 dann zum ende springen

  pop ebx                                 // EBX vom stack
  pop eax                                 // EAX vom stack

  cmp byte ptr [ebx], $E9                 // steht an der originalen API $E9 für jmp?
  jne @endef                              // wenn nicht dann zum ende springen

  add eax, 4                              // EAX = EAX+4, adresse der 2. variable
  mov ecx, [eax]                          // diese in EAX schreiben
  mov [ebx], ecx                          // diese wiederum an die original API
  add eax, 4                              // EAX = EAX+4, adresse der 3. variable
  add ebx, 4                              // EBX = EBX+4
  mov ecx, [eax]                          // 3. variable in ECX
  mov [ebx], ecx                          // diese an die nächsten 4 bytes der original API
                                          // der JMP hook wurde überschrieben mit den richtigen daten

  push MEM_RELEASE                        // art der speicher freigabe
  push 0                                  // bei MEM_RELEASE muss speichergröße 0 sein
  push [next]                             // adresse des speichers der freigegeben werden soll
  call VirtualFree                        // aufrufen der API zum speicher freigeben
                                          // resultat muss nicht auf wahr/falsch
                                          // geprüft werden da der hook entfernt wurde
                                          // egal ob speicher freigegeben werden konnte
                                          // oder nicht

  mov eax, 1                          // EAX = 1 = true = kein fehler, RESULT = TRUE
  pop ebp                             // EBP vom stack nehmen
  ret 4                               // RETURN 12, 12 bytes vom stack nehmen aus der funktion springen
                                      // 12 bytes da 3 parameter, jeder parameter besteht immer aus 4 bytes = dword

  @endef:                             // hier wir hingesprungen wenn fehler aufgetreten ist
  xor eax, eax                        // EAX = 0 = false = fehler, RESULT = FALSE
  pop ebp                             // EBP vom stack nehmen
  ret 4                               // RETURN 12, 12 bytes vom stack nehmen aus der funktion springen
                                      // 12 bytes da 3 parameter, jeder parameter besteht immer aus 4 bytes = dword

  @@beginasmfunction:                 // unsere next funktion die wir kopieren
                                      // diese wird dann aufgerufen wenn man die gehookte
                                      // API aufrufen will
                                      // sie entfernt den JMP ruft dann die original
                                      // funktion auf und schreibt den jmp wieder rein
                                      // da sie keine feste adresse hat und in den
                                      // reservierten speicher geschriebn wird, muss man
                                      // alle variablen und jmps ($00000000) selbst ausfüllen

  push eax                            // EAX aufn stack
  push edx                            // EDX aufn stack
  mov eax, [esp+8]                    // ESP = adresse der aktuallen stack position
                                      // da 2 mal etwas auf dem stack gelegt wurde
                                      // ist in [ESP+8] die return adresse
                                      // diese wird in EAX geschrieben
  mov [$00000000+20], eax             // eax an variable 5 schreiben (20 / 4 bytes)
  mov [esp+8], $00000000              // setzen der neuen return adresse
                                      // diese ist bei @@endejump:

  mov eax, [$00000000+0]              // 1. variable in EAX, EAX = adresse der original API
  mov edx, [$00000000+4]              // 2. variable in EDX, 4 bytes die normal bei der API stehen
  mov [eax], edx                      // überschreiben des jmps mit den 4 bytes
  mov edx, [$00000000+8]              // 3. variable in EDX, die nächsten 4 bytes
  mov [eax+4], edx                    // und wieder überschreiben
  pop edx                             // EDX vom stack
  pop eax                             // EAX vom stack

                                      // alles wurde wieder hergestellt
                                      // ausser der return adresse gab es keine änderungen
                                      // wir können die ungehookte original API wieder aufrufen
                                      // wir jmp zu der funktion anstatt sie zu callen
                                      // dafür müssen wir dann nicht die parameter pushen
                                      // ändern der return adresse hat zu folge
                                      // Das wir nach dem jmp wieder bei @@nedejmp:
                                      // landen, also kaum ein unterschied zum call ist

  jmp [$00000000+0]                   // jmp zur originalen ungehookten API
  @@endejmp:                          // hier landen wir nach dem aufruf
                                      // wird benötigt um die adresse zu berechnen

                                      // alle register die wir verändern
                                      // werden wieder auf den stack gelegt
                                      // falls die original API änderungen virgenommen hat
                                      // z.b. an EAX, falls die API eine funktion war
                                      // ist dort jetzt das ergebnis zu finden
  push eax                            // EAX auf stack
  push edx                            // EDX auf stack
  mov eax, [$00000000]                // in EAX adresse der original API
  mov edx, [$00000000+12]             // in EDX, die 4. variable, EDX = jmp infos
  mov [eax], edx                      // setzen des jmps an die originale API
  mov edx, [$00000000+16]             // in EDX, die 5. variable, (da jmp asu 5 bytes besteht)
  mov [eax+4], edx                    // und auch hier wieder zurückschreiben
  pop eax                             // EAX vom stack
  pop edx                             // EDX vom stack

  jmp [$00000000+20]                  // die gesicherte return adrese springen

  @@endasmfunction:                   // ende der NEXT funktion
                                      // wird benötigt um die größe zu berechnen
end;


Zuletzt bearbeitet von uall@ogc am So 29.08.04 13:57, insgesamt 2-mal bearbeitet
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 28.08.04 23:08 
Warum nutzt du in der Unhook-Funktion im Displacement $00000000 als Basis-Adresse? Ich denk mal, das wird zu ner AV führen ... (Oder welchen Grund gibt es dafür beim Unhooken das System zu crashen???)

Ooops, hat sich erledigt, hab übersehen, dass die Routine in der Unhook-Funktion nicht geschrieben werden. Self-Modifying Code ist aber auch immer Kompliziert :D :oops:

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 29.08.04 12:12 
nene beim unhook ist die funktion nur zum berechnen der größe da, damit ich weiß wo die variablen beginnen (di stehen hinter der funktion die in in den reservierten speicher kopiere) die erste variable ist die adresse der original API wo ich den JMP hinsetze, diese lese ich aus schau ob der jmp da ist und überschreibe das einfach mit den originalen 8 bytes (5 bytes für den jmp) dann gebe ich den reservierten speicher wieder frei, die funktion mit den $00000000 rufe ich nie auf, sie ist halt nur dafür da um zu berechnen wo die variablen beginnen :)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 29.08.04 20:28 
Beim Studieren des Codes von afx ist mir noch ne Idee gekommen, wie du nur einmal den Code für Hook und Unhook brauchst und trotzdem einfach die Größe berechnen kannst:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure HookCode;assembler;
asm
//Assembler-Code zum Hooken, der in den anderen Prozess geschrieben wird
end;

procedure HookCodeEnd;assembler;
asm;
end;


Die Größe erhälst du dann mit DWORD(@HookCodeEnd) - DWORD(HookCode) und den HookCode selber mit @HookCode.

in ASM also:
LEA ECX, [HookCodeEnd]
LEA ESI, [HookCode] //Offset
SUB ECX, ESI //Größe

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 29.08.04 20:54 
ausblenden Delphi-Quelltext
1:
DWORD(@HookCodeEnd) - DWORD(HookCode)					


fehlt nen @ = DWORD(@HookCode)

oder man nimmt

ausblenden Delphi-Quelltext
1:
2:
MOV ECX, offset HookCodeEnd
SUB ECX, offset HookCode


;>
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 29.08.04 21:33 
Wobei die Möglichkeit über LEA den Vorteil hat, dass schon alles (Größe und Offset) in den Richtigen Registern stehen.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 08.09.04 22:28 
Ich wollte mal, weil mir das nicht so richtig klar geworden ist, anfragen, in wie weit es Einschränkungen bei den API Hooks gibt, weil bestimmte Berechtigungen erforderlich sind?

Also, z.B. funzt das als Otto Normal-User ohne Extra-Privilegien?
(P.S.: Das es mit Umwegen funzt, wenn man den SMC steuern kann, hat Assabad ja schon bewiesen ;-), das mein ich aber nicht)

Ich mein im Speziellen, ob ein normaler User, der Benutzer-Gruppe, sich z.B. in den Explorer, oder PID 8 einklinken könnte, d.h. in Prozesse auch von anderen Usern.

TIA.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Sprint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 849



BeitragVerfasst: Mi 08.09.04 23:01 
BenBE hat folgendes geschrieben:
Ich mein im Speziellen, ob ein normaler User, der Benutzer-Gruppe, sich z.B. in den Explorer, oder PID 8 einklinken könnte, d.h. in Prozesse auch von anderen Usern.

Ich weiß jetzt nicht was du mit PID 8 meinst. Aber beim Explorer und so, da kannst du dich so auch ganz leicht einklicken.
Zum Beispiel installierst z.B. ein MsgHook systemweit und wenn deine DLL in Prozess vom Explorer geladen wird, kannst du dort die API's gegen deine Funktionen austauschen.

_________________
Ciao, Sprint.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 09.09.04 09:28 
Sprint hat folgendes geschrieben:
BenBE hat folgendes geschrieben:
Ich mein im Speziellen, ob ein normaler User, der Benutzer-Gruppe, sich z.B. in den Explorer, oder PID 8 einklinken könnte, d.h. in Prozesse auch von anderen Usern.

Ich weiß jetzt nicht was du mit PID 8 meinst.

PID 8 ist der System Prozess (Kernel) von Windows 2000.

Sprint hat folgendes geschrieben:
Aber beim Explorer und so, da kannst du dich so auch ganz leicht einklicken.
Zum Beispiel installierst z.B. ein MsgHook systemweit und wenn deine DLL in Prozess vom Explorer geladen wird, kannst du dort die API's gegen deine Funktionen austauschen.
Schon klar, aber ich glaub nicht, dass der Explorer meine DLL ohne Grund laden wird ;-) Und außerdem wolte ich in einen anderen Prozess rein, der nicht durch ein paar simple RegKeys dazu gebracht werden kann, eine DLL zu laden...

Und das es als Admin geht, weiß ich ... Jedoch nicht, ob's auch als Normal-User geht ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Sprint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 849



BeitragVerfasst: Do 09.09.04 12:59 
BenBE hat folgendes geschrieben:
Schon klar, aber ich glaub nicht, dass der Explorer meine DLL ohne Grund laden wird ;-)

Auf NT-basierten Betriebssystemen kannst du ja auch CreateRemoteThread benutzen. Das funktioniert wunderbar.
Und mit einem systemweitern MsgHook (SetWindowsHookEx) wird deine DLL auch in den Prozess des Explores geladen.

Zitat:
Und außerdem wolte ich in einen anderen Prozess rein, der nicht durch ein paar simple RegKeys dazu gebracht werden kann, eine DLL zu laden...

Weiß ich nicht was du damit meinst? Von RegKeys habe ich nicht geredet. Geht ja auch nur, wenn die Anwendug die user32dll geladen hat. So macht das z.B. Window Blinds.

_________________
Ciao, Sprint.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Do 09.09.04 16:22 
@BenBE

suchst vill sowas:

function GetDebugPrivilege: boolean;
{unser prozess bekomm debug previlegien,
benötigt um einen prozess handle von einem systemprozess zu bekommen}


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function GetDebugPrivilege: boolean;
var hToken,rel: cardinal;
    tkp: TOKEN_PRIVILEGES;
    luid: int64;
begin
  result := false;
  if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
  begin
    if LookupPrivilegeValue(nil'SeDebugPrivilege', luid) then
    begin
      tkp.PrivilegeCount            := 1;
      tkp.Privileges[0].Attributes  := SE_PRIVILEGE_ENABLED;
      tkp.Privileges[0].Luid        := luid;
      result := AdjustTokenPrivileges(hToken, FALSE, tkp, sizeof(tkp), nil, rel);
    end;
    CloseHandle(hToken);
  end;
end;