unit frmStackViewUnit; {$mode delphi} interface uses {$ifdef darwin} macport, {$endif} {$ifdef windows} windows, {$endif} cefuncproc, newkernelhandler, Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus, stacktrace2, Clipbrd, ComCtrls, strutils, frmSelectionlistunit, maps, betterControls, contexthandler; type { TfrmStackView } TfrmStackView = class(TForm) ColorDialog1: TColorDialog; FindDialog1: TFindDialog; svImageList: TImageList; lvStack: TListView; MenuItem1: TMenuItem; MenuItem2: TMenuItem; MenuItem3: TMenuItem; MenuItem4: TMenuItem; MenuItem5: TMenuItem; MenuItem6: TMenuItem; miAddRef: TMenuItem; miSetColor: TMenuItem; miFindNext: TMenuItem; miFind: TMenuItem; miLockAndTrace: TMenuItem; miCopyValue: TMenuItem; miCopySecondary: TMenuItem; miCopyAddress: TMenuItem; miAddESP: TMenuItem; miAddEBP: TMenuItem; PopupMenu1: TPopupMenu; procedure FindDialog1Find(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); procedure lvStackCustomDrawItem(Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean); procedure lvStackDblClick(Sender: TObject); procedure MenuItem3Click(Sender: TObject); procedure miAddRefClick(Sender: TObject); procedure miSetColorClick(Sender: TObject); procedure miFindClick(Sender: TObject); procedure miLockAndTraceClick(Sender: TObject); procedure miAddESPClick(Sender: TObject); procedure miCopyAddressClick(Sender: TObject); procedure PopupMenu1Popup(Sender: TObject); private { private declarations } c: pointer; contexthandler: TContextInfo; stack: pbyte; size: integer; allocs: tlist; colors: TMap; StackReference: ptruint; public { public declarations } procedure SetContextPointer(c: pointer; stack: pbyte; size: integer); end; var frmStackView: TfrmStackView; resourcestring rsTheStructuresListIsBroken = 'The structures list is broken'; rsNewWindow = ''; rsLockAndAddToStructureDissect = 'Lock and add to structure dissect'; rsSelectTheStructureDissectWindowYouWishToAddThisReg = 'Select the structure' +' dissect window you wish to add this region to'; rsSVThisStackViewWindowHasAllocatedStackSnapshotsEtc = 'This stackview window has allocated stack snapshots in the target process. Do you wish to free them?'; implementation uses MemoryBrowserFormUnit, StructuresFrm2, frmstacktraceunit, processhandlerunit; procedure TfrmStackView.miAddESPClick(Sender: TObject); begin SetContextPointer(c, stack, size); end; procedure TfrmStackView.miCopyAddressClick(Sender: TObject); var i: integer; s: tstringlist; part: integer; begin part:=TMenuItem(sender).Tag; s:=tstringlist.create; try for i:=0 to lvstack.items.count-1 do begin if lvstack.items[i].Selected then begin case part of 0: s.add(lvstack.items[i].caption); 1,2: s.add(lvstack.items[i].SubItems[part-1]); 3: s.add(PadRight(lvstack.items[i].caption,20)+' - '+PadRight(lvstack.items[i].SubItems[0],20) + ' - '+lvstack.items[i].SubItems[1]); end; end; end; Clipboard.AsText:=s.text; finally s.free; end; end; procedure TfrmStackView.PopupMenu1Popup(Sender: TObject); var x: ptruint; ch: TContextInfo; begin ch:=getBestContextHandler; miAddESP.Caption:='('+ch.StackPointerRegister^.name+')'; miAddEBP.Caption:='('+ch.FramePointerRegister^.name+')'; if lvStack.selected<>nil then begin x:=ptruint(lvstack.selected.data); miAddRef.caption:=format('(ref+*) Ref will be %x',[x]); end; miAddEBP.Enabled:=ch.FramePointerRegister^.getValue(c)<>0; if not miAddEBP.Enabled and miAddEBP.Checked then miAddESP.Checked:=true; end; procedure TfrmStackView.lvStackDblClick(Sender: TObject); var p: tpoint; a: ptruint; begin if lvstack.Selected<>nil then begin //get tht column that is clicked p:=lvStack.ScreenToClient(mouse.CursorPos); a:=ptruint(lvstack.selected.data); if p.x>lvStack.Column[0].Width then a:=StrToQWord('$'+lvstack.Selected.SubItems[0]); if not MemoryBrowser.visible then MemoryBrowser.visible:=true; if p.x>lvStack.column[1].width then MemoryBrowser.disassemblerview.SelectedAddress:=a else MemoryBrowser.hexview.address:=a; end; end; procedure TfrmStackView.MenuItem3Click(Sender: TObject); var i: integer; s: tstringlist; f: TfrmSelectionList; structurefrm: TfrmStructures2; new: boolean; begin //find out which data dissect windows are open s:=tstringlist.create; if frmStructures2=nil then raise exception.create(rsTheStructuresListIsBroken); for i:=0 to frmStructures2.Count-1 do s.add(TfrmStructures2(frmStructures2[i]).Caption); s.add(rsNewWindow); f:=TfrmSelectionList.Create(self, s); f.caption:=rsLockAndAddToStructureDissect; f.label1.Caption:=rsSelectTheStructureDissectWindowYouWishToAddThisReg; if f.showmodal=mrok then begin if f.itemindex=-1 then f.itemindex:=0; if f.itemindex>=frmStructures2.Count then //new window begin structurefrm:=tfrmstructures2.create(application); structurefrm.show; end else structurefrm:=TfrmStructures2(frmStructures2[f.itemindex]); //add this esp (c.rsp/esp) as locked address structurefrm.addLockedAddress(contexthandler.StackPointerRegister^.getValue(c), stack,size); structurefrm.show; if structurefrm.mainStruct=nil then //if no structure is selected define it then structurefrm.DefineNewStructure(size); end; end; procedure TfrmStackView.miAddRefClick(Sender: TObject); begin if lvStack.Selected<>nil then begin StackReference:=ptruint(lvstack.selected.data); SetContextPointer(c, stack, size); end else miAddESP.Checked:=true; end; procedure TfrmStackView.miSetColorClick(Sender: TObject); var i: integer; a: ptruint; oldc, c: tcolor; begin if lvStack.selected<>nil then begin a:=ptruint(lvStack.Selected.Data); if colors.GetData(a,c) then colordialog1.Color:=c; if ColorDialog1.execute then begin c:=colordialog1.Color; for i:=0 to lvstack.items.count-1 do begin if lvstack.items[i].Selected then begin a:=ptruint(lvStack.items[i].Data); if colors.HasId(a) then colors.SetData(a, c) else colors.Add(a, c); end; end; end; lvStack.Refresh; lvStack.Repaint; end; end; procedure TfrmStackView.miFindClick(Sender: TObject); begin finddialog1.execute; end; procedure TfrmStackView.miLockAndTraceClick(Sender: TObject); var x: PtrUInt; alloc: pointer; f: TfrmStacktrace; begin if contexthandler=nil then contexthandler:=getBestContextHandler; alloc:=VirtualAllocEx(processhandle, nil, size+1, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE); if alloc<>nil then begin if allocs=nil then allocs:=tlist.create; //copy the original bytes to the copy WriteProcessMemory(processhandle, pointer(alloc), stack, size, x); allocs.Add(alloc); f:=TfrmStacktrace.create(application); f.shadowstacktrace(c, alloc, size); f.show; end; end; procedure TfrmStackView.FormDestroy(Sender: TObject); begin colors.Free; end; procedure TfrmStackView.FormShow(Sender: TObject); var x: array of integer; w: integer; begin setlength(x,3); if LoadFormPosition(self, x) then begin if length(x)>=3 then begin lvstack.Column[0].width:=x[0]; lvstack.Column[1].width:=x[1]; lvstack.Column[2].width:=x[2]; end; end else begin {$ifdef cpu32} lvStack.Column[0].Width:=lvStack.Canvas.TextWidth('DDDDDDDD'); lvStack.Column[1].Width:=lvStack.Canvas.TextWidth('DDDDDDDD'); {$else} lvStack.Column[0].Width:=lvStack.Canvas.TextWidth('DDDDDDDDDDDDDD'); lvStack.Column[1].Width:=lvStack.Canvas.TextWidth('DDDDDDDDDDDDDD'); w:=lvStack.Column[0].Width+lvStack.Column[1].Width; if (lvStack.ColumnCount>2) and (lvStack.Column[2].Visible) then begin lvStack.Column[2].Width:=lvStack.Canvas.TextWidth('DDDDDDDDDDDDDD'); w:=w+lvStack.Column[2].Width; end; clientwidth:=w; {$endif} end; end; procedure TfrmStackView.lvStackCustomDrawItem(Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean); var address: ptruint; c: tcolor; begin address:=ptruint(item.data); if colors.GetData(address, c) then sender.canvas.brush.color:=c; DefaultDraw:=true; end; procedure TfrmStackView.FormCreate(Sender: TObject); begin ColorDialog1.color:=clWhite; colors:=TMap.create(ituPtrSize, sizeof(TColor)); end; procedure TfrmStackView.FormClose(Sender: TObject; var CloseAction: TCloseAction); var x: array of integer; begin setlength(x,3); x[0]:=lvstack.Column[0].Width; x[1]:=lvstack.Column[1].Width; x[2]:=lvstack.Column[2].Width; SaveFormPosition(self, x); end; procedure TfrmStackView.FindDialog1Find(Sender: TObject); var i: integer; s: string; begin miFindNext.enabled:=true; s:=lowercase(finddialog1.FindText); lvStack.MultiSelect:=false; for i:=lvStack.ItemIndex+1 to lvStack.Items.Count-1 do begin if (pos(s, lowercase(lvStack.Items[i].Caption))>0) or (pos(s, lowercase(lvStack.Items[i].SubItems[0]))>0) or (pos(s, lowercase(lvStack.Items[i].SubItems[1]))>0) then begin lvStack.ItemIndex:=i; lvStack.Items[lvStack.ItemIndex].Selected:=true; lvStack.Items[lvStack.ItemIndex].MakeVisible(false); lvStack.Selected:=lvStack.Items[lvStack.ItemIndex]; lvStack.MultiSelect:=true; exit; end; end; lvStack.MultiSelect:=true; beep; end; procedure TfrmStackView.FormCloseQuery(Sender: TObject; var CanClose: boolean); var r: TModalResult; i: integer; begin canclose:=true; if allocs<>nil then begin r:=messagedlg(rsSVThisStackViewWindowHasAllocatedStackSnapshotsEtc, mtconfirmation, [mbyes, mbno, mbCancel], 0); if not (r in [mryes, mrno]) then begin canclose:=false; //something else besides yes or no was clicked exit; end; if r=mryes then begin //free the allocated memory in the target process for i:=0 to allocs.count-1 do VirtualFreeEx(processhandle, allocs[i], 0, MEM_RELEASE); end; allocs.free; allocs:=nil; end; end; procedure TfrmStackView.SetContextPointer(c: pointer; stack: pbyte; size: integer); var tempstringlist: tstringlist; p1, p2: integer; i: integer; s: string; address: string; value: string; secondary: string; li: tlistitem; refname: string; refaddress: ptruint; begin contexthandler:=getBestContextHandler; self.c:=c; self.stack:=stack; self.size:=size; tempstringlist:=tstringlist.create; lvStack.BeginUpdate; lvStack.Items.BeginUpdate; try if miAddESP.checked then begin refname:=contexthandler.StackPointerRegister^.name; refaddress:=contexthandler.StackPointerRegister^.getValue(c); end else if miAddEBP.checked then begin refname:=contexthandler.FramePointerRegister^.name; refaddress:=contexthandler.FramePointerRegister^.getValue(c); end else if miAddRef.checked then begin refname:=' '; refaddress:=StackReference; end; ce_stacktrace(contexthandler.StackPointerRegister^.getValue(c), contexthandler.FramePointerRegister^.getValue(c), contexthandler.InstructionPointerRegister^.getValue(c), pbytearray(stack), size, tempstringlist, true,false,false,0,refaddress, refname); //now fill the listview with this information lvStack.Items.Clear; for i:=0 to tempstringlist.count-1 do begin s:=tempstringlist[i]; p1:=posex(' - ',s); p2:=posex(' - ',s,p1+1); address:=copy(s, 1, p1); value:=copy(s, p1+3, p2-p1-3); secondary:=copy(s, p2+3, length(s)); li:=lvStack.Items.Add; li.Caption:=address; li.SubItems.Add(value); li.subitems.add(secondary); li.Data:=pointer(tempstringlist.objects[i]); end; finally tempstringlist.Free; lvStack.items.EndUpdate; lvStack.EndUpdate; end; end; initialization {$I frmStackViewUnit.lrs} end.