unit Unit9; {$MODE Delphi} interface uses windows, LCLIntf, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, LResources; type TForm9 = class(TForm) Label1: TLabel; Label2: TLabel; Memo1: TMemo; Button2: TButton; Button1: TButton; Button3: TButton; SpeedButton1: TSpeedButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure Button2Click(Sender: TObject); procedure SpeedButton1Click(Sender: TObject); private { Private declarations } procedure relocate; public { Public declarations } end; type TLevel4 = record a: integer; b: integer; c: integer; d: integer; e: integer; f: integer; health: integer; end; type PLevel4=^TLevel4; type TLevel3 = record p: PLevel4; a: integer; b: integer; c: integer; d: integer; e: integer; f: integer; end; type PLevel3=^TLevel3; type TLevel2 = record a: integer; b: integer; c: integer; d: integer; e: integer; p: PLevel3; f: integer; end; type PLevel2=^TLevel2; type TLevel1 = record a: integer; b: integer; c: integer; p: PLevel2; d: integer; e: integer; f: integer; end; type PLevel1=^TLevel1; var Form9: TForm9; basepointer: plevel1; implementation uses Unit4, Unit10; resourcestring rsStep8MultilevelPointersPW = 'Step 8: Multilevel pointers: (PW=%s)'; rsUnrandomizerDetected = 'Unrandomizer detected'; rsYouVeGotSecondsLeftToChangeTheValueTo5000 = 'You''ve got %s seconds left to change the value to 5000'; rsTryAgain9 = 'Aw, you''ve almost reached the end. But don''t worry, multilevel pointers can be a real pain when dealing with. If you get more experienced ' +'someday you can try it again. Are you sure you want to quit?'; rsLOSER = 'BOO'; rsTutorialStep8= 'This step will explain how to use multi-level pointers.'+#13#10+ 'In step 6 you had a simple level-1 pointer, with the first address found already being the real base address.'+#13#10+ 'This step however is a level-4 pointer. It has a pointer to a pointer to a pointer to a pointer to a pointer to the health.'+#13#10+ ''+#13#10+ 'You basicly do the same as in step 6. Find out what accesses the value, look at the instruction and what probably is '+ 'the base pointer value, and what is the offset, and already fill that in or write it down. But in this case the address '+ 'you''ll find will also be a pointer. You just have to find out the pointer to that pointer exactly the same way as you did '+ 'with the value. Find out what accesses that address you found, look at the assembler instruction, note the probable '+ 'instruction and offset, and use that.'+#13#10+ 'and continue till you can''t get any further (usually when the base address is a static address, shown up as green)'+#13#10+ ''+#13#10+ 'Click Change Value to let the tutorial access the health.'+#13#10+ 'If you think you''ve found the pointer path click Change Register. The pointers and value will then change and you''ll '+ 'have 3 seconds to freeze the address to 5000'+#13#10+ ''+#13#10+ 'Extra: This problem can also be solved using a auto assembler script, or using the pointer scanner'+#13#10+ 'Extra2: In some situations it is recommended to change ce''s codefinder settings to Access violations when '+#13#10+ 'Encountering instructions like mov eax,[eax] since debugregisters show it AFTER it was changed, making it hard to '+ 'find out the the value of the pointer'+#13#10+ ''+#13#10+ ''+#13#10+ ''+#13#10+ ''+#13#10+ ''+#13#10+ 'Extra3: If you''re still reading. You might notice that when looking at the assembler instructions that the pointer is '+ 'being read and filled out in the same codeblock (same routine, if you know assembler, look up till the start of the '+ 'routine). This doesn''t always happen, but can be really useful in finding a '+ 'pointer when debugging is troublesome'; procedure TForm9.relocate; begin //just adding some more chaos: if (basepointer<>nil) then begin zeromemory(basepointer.p.p.p,sizeof(TLevel4)); zeromemory(basepointer.p.p,sizeof(TLevel3)); freemem(basepointer.p.p); zeromemory(basepointer.p,sizeof(TLevel2)); freemem(basepointer.p); zeromemory(basepointer,sizeof(TLevel1)); //delete a chunk inbetween if emptying wasn't enough already end; getmem(basepointer,sizeof(TLevel1)+random(128)); basepointer.a:=random(99999); basepointer.b:=random(99999); basepointer.c:=random(99999); basepointer.d:=random(99999); basepointer.e:=random(99999); basepointer.f:=random(99999); getmem(basepointer.p,sizeof(TLevel2)+random(128)); basepointer.p.a:=random(99999); basepointer.p.b:=random(99999); basepointer.p.c:=random(99999); basepointer.p.d:=random(99999); basepointer.p.e:=random(99999); basepointer.p.f:=random(99999); getmem(basepointer.p.p,sizeof(TLevel3)+random(128)); basepointer.p.p.a:=random(99999); basepointer.p.p.b:=random(99999); basepointer.p.p.c:=random(99999); basepointer.p.p.d:=random(99999); basepointer.p.p.e:=random(99999); basepointer.p.p.f:=random(99999); getmem(basepointer.p.p.p,sizeof(TLevel4)+random(128)); basepointer.p.p.p.a:=random(99999); basepointer.p.p.p.b:=random(99999); basepointer.p.p.p.c:=random(99999); basepointer.p.p.p.d:=random(99999); basepointer.p.p.p.e:=random(99999); basepointer.p.p.p.f:=random(99999); end; procedure TForm9.FormCreate(Sender: TObject); begin relocate; basepointer.p.p.p.health:=random(4000); label1.caption:=inttostr(basepointer.p.p.p.health); memo1.lines.text:=rsTutorialStep8; memo1.Lines.Insert(0, Format(rsStep8MultilevelPointersPW, [inttostr(525)+inttostr(927)])); memo1.SelStart:=0; font.size:=12; end; procedure TForm9.Button1Click(Sender: TObject); var h: ^integer; i: integer; a: plevel1; b: plevel2; c: plevel3; d: plevel4; begin a:=basepointer; if (a.a=a.b) and (a.b=a.c) and (a.c=a.d) and (a.d=a.e) and (a.e=a.f) then begin showmessage(rsUnrandomizerDetected); exit; end; if a.p=nil then exit; b:=a.p; if (b.a=b.b) and (b.b=b.c) and (b.c=b.d) and (b.d=b.e) and (b.e=b.f) then begin showmessage(rsUnrandomizerDetected); exit; end; if b.p=nil then exit; c:=b.p; if (c.a=c.b) and (c.b=c.c) and (c.c=c.d) and (c.d=c.e) and (c.e=c.f) then begin showmessage(rsUnrandomizerDetected); exit; end; if c.p=nil then exit; d:=c.p; if (d.a=d.b) and (d.b=d.c) and (d.c=d.d) and (d.d=d.e) and (d.e=d.f) then begin showmessage(rsUnrandomizerDetected); exit; end; d.health:=random(4000); label1.caption:=inttostr(d.health); end; procedure TForm9.Button3Click(Sender: TObject); var j: integer; k: integer; i: integer; a: plevel1; b: plevel2; c: plevel3; d: plevel4; begin relocate; a:=basepointer; if (a.a=a.b) and (a.b=a.c) and (a.c=a.d) and (a.d=a.e) and (a.e=a.f) then begin showmessage(rsUnrandomizerDetected); exit; end; if a.p=nil then exit; b:=a.p; if (b.a=b.b) and (b.b=b.c) and (b.c=b.d) and (b.d=b.e) and (b.e=b.f) then begin showmessage(rsUnrandomizerDetected); exit; end; if b.p=nil then exit; c:=b.p; if (c.a=c.b) and (c.b=c.c) and (c.c=c.d) and (c.d=c.e) and (c.e=c.f) then begin showmessage(rsUnrandomizerDetected); exit; end; if c.p=nil then exit; d:=c.p; if (d.a=d.b) and (d.b=d.c) and (d.c=d.d) and (d.d=d.e) and (d.e=d.f) then begin showmessage(rsUnrandomizerDetected); exit; end; d.health:=random(4000); label1.caption:=inttostr(d.health); label1.Repaint; k:=3; label2.Caption:=IntToStR(k); label2.Visible:=true; button1.Anchors:=[akLeft]; label2.anchors:=[akLeft]; button3.visible:=false; while k>0 do begin label2.Caption:=Format(rsYouVeGotSecondsLeftToChangeTheValueTo5000, [IntToStR(k)]); label2.Repaint; sleep(1000); deC(k); end; label2.visible:=false; button3.visible:=true; button1.Anchors:=[akLeft, akBottom]; label2.anchors:=[akLeft, akBottom]; //check if it is 5000 if d.health=5000 then button2.Enabled:=true; {$O+} j:=0; {$O-} //if j=1 then beep; end; procedure TForm9.FormClose(Sender: TObject; var Action: TCloseAction); begin application.Terminate; end; procedure TForm9.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin canclose:=MessageDlg(rsTryAgain9, mtconfirmation, [mbyes, mbno], 0)=mryes; end; procedure TForm9.Button2Click(Sender: TObject); begin hide; form10:=tform10.create(self); form10.left:=left; form10.top:=top; form10.width:=width; form10.height:=height; form10.show; { hide; form4:=tform4.create(self); form4.show; } end; procedure TForm9.SpeedButton1Click(Sender: TObject); begin showmessage(rsLOSER); button2.Click; end; initialization {$i Unit9.lrs} {$i Unit9.lrs} end.