mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
6234 lines
177 KiB
ObjectPascal
Executable file
6234 lines
177 KiB
ObjectPascal
Executable file
unit MemoryBrowserFormUnit;
|
|
|
|
{$MODE Delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$ifdef darwin}
|
|
LCLType,
|
|
{$endif}
|
|
{$ifdef windows}
|
|
jwawindows, windows,imagehlp,
|
|
{$endif}
|
|
LCLProc, LCLIntf, Messages, SysUtils, Classes, Graphics,
|
|
Controls, Forms, Dialogs, frmMemoryAllocHandlerUnit, math, StdCtrls, Spin,
|
|
ExtCtrls,CEFuncProc,symbolhandler,Clipbrd, Menus,plugin,CEDebugger,KernelDebugger,
|
|
Assemblerunit,disassembler,addressparser, Buttons, Contnrs,
|
|
disassemblerviewunit, PEInfoFunctions ,DissectCodeThread,stacktrace2,
|
|
NewKernelHandler, ComCtrls, LResources, byteinterpreter, StrUtils, hexviewunit,
|
|
debughelper, debuggertypedefinitions,frmMemviewPreferencesUnit, registry,
|
|
disassemblerComments, multilineinputqueryunit, frmMemoryViewExUnit,
|
|
LastDisassembleData, ProcessHandlerUnit, commonTypeDefs, binutils,
|
|
fontSaveLoadRegistry, LazFileUtils, ceregistry, frmCR3SwitcherUnit,
|
|
betterControls, ScrollBoxEx, contexthandler,iptlogdisplay
|
|
{$ifdef darwin}, macport, macportdefines{$endif} ;
|
|
|
|
|
|
type
|
|
|
|
{ TMemoryBrowser }
|
|
|
|
TMemoryBrowser = class(TForm)
|
|
aflabel: TLabel;
|
|
cflabel: TLabel;
|
|
CSLabel: TLabel;
|
|
dflabel: TLabel;
|
|
dispQwords: TMenuItem;
|
|
DSLabel: TLabel;
|
|
EAXLabel: TLabel;
|
|
EBPlabel: TLabel;
|
|
EBXlabel: TLabel;
|
|
ECXlabel: TLabel;
|
|
EDIlabel: TLabel;
|
|
EDXlabel: TLabel;
|
|
EIPlabel: TLabel;
|
|
ESIlabel: TLabel;
|
|
ESlabel: TLabel;
|
|
ESPlabel: TLabel;
|
|
FSlabel: TLabel;
|
|
GSlabel: TLabel;
|
|
miClearCache: TMenuItem;
|
|
miIPTLog: TMenuItem;
|
|
miShowRelativeDisassembler: TMenuItem;
|
|
miArchX86: TMenuItem;
|
|
miArchArm: TMenuItem;
|
|
miArchAutodetect: TMenuItem;
|
|
MenuItem4: TMenuItem;
|
|
copyBytesAndOpcodesAndComments: TMenuItem;
|
|
MenuItem5: TMenuItem;
|
|
MenuItem6: TMenuItem;
|
|
miArchitecture: TMenuItem;
|
|
miCR3Switcher: TMenuItem;
|
|
miShowSectionAddresses: TMenuItem;
|
|
miOpenInDissectData: TMenuItem;
|
|
miCopyOpcodesOnly: TMenuItem;
|
|
miUndoLastEdit: TMenuItem;
|
|
miFollowInHexview: TMenuItem;
|
|
miSetSpecificBreakpoint: TMenuItem;
|
|
miWatchBPHardware: TMenuItem;
|
|
miWatchBPException: TMenuItem;
|
|
miWatchBPDBVM: TMenuItem;
|
|
N9: TMenuItem;
|
|
miSetBreakpointSW: TMenuItem;
|
|
miSetBreakpointHW: TMenuItem;
|
|
miSetBreakpointPE: TMenuItem;
|
|
miSetBreakpointDBVMExec: TMenuItem;
|
|
mvImageList: TImageList;
|
|
MenuItem1: TMenuItem;
|
|
MenuItem10: TMenuItem;
|
|
miSearchForAccessibleStrings: TMenuItem;
|
|
MenuItem12: TMenuItem;
|
|
MenuItem13: TMenuItem;
|
|
MenuItem14: TMenuItem;
|
|
miDBVMFindoutwhataddressesthisinstructionaccesses: TMenuItem;
|
|
Showdebugtoolbar1: TMenuItem;
|
|
miCopyAddressesOnly: TMenuItem;
|
|
miHideToolbar: TMenuItem;
|
|
miDBVMActivateCloak: TMenuItem;
|
|
miDBVMDisableCloak: TMenuItem;
|
|
miUltimap: TMenuItem;
|
|
MenuItem15: TMenuItem;
|
|
MenuItem16: TMenuItem;
|
|
MenuItem17: TMenuItem;
|
|
MenuItem18: TMenuItem;
|
|
MenuItem19: TMenuItem;
|
|
miLoadTrace: TMenuItem;
|
|
dispChar: TMenuItem;
|
|
dispShorts: TMenuItem;
|
|
DispLongs: TMenuItem;
|
|
miTextEncoding: TMenuItem;
|
|
miWatchMemoryPageAccess: TMenuItem;
|
|
miSetUnsetBookmark: TMenuItem;
|
|
miGotoBookmark: TMenuItem;
|
|
miUserWriteInteger: TMenuItem;
|
|
miUltimap2: TMenuItem;
|
|
miWatchList: TMenuItem;
|
|
miStackTraceSep: TMenuItem;
|
|
miCompareStructures: TMenuItem;
|
|
miCodeFilter: TMenuItem;
|
|
miExceptionIgnoreList: TMenuItem;
|
|
N19: TMenuItem;
|
|
miUnexpectedExceptionBreakNever: TMenuItem;
|
|
miUnexpectedExceptionBreakAlways: TMenuItem;
|
|
miUnexpectedExceptionBreakIfInRegion: TMenuItem;
|
|
miExceptionRegionSeperator: TMenuItem;
|
|
miExceptionRegionManageList: TMenuItem;
|
|
miExceptionRegionAutoAddAllocs: TMenuItem;
|
|
miBreakOnExceptions: TMenuItem;
|
|
miRunUnhandled: TMenuItem;
|
|
miChangeProtectionRWE: TMenuItem;
|
|
miChangeProtectionRE: TMenuItem;
|
|
miChangeProtectionRW: TMenuItem;
|
|
miChangeProtectionR: TMenuItem;
|
|
miTextEncodingCodePage: TMenuItem;
|
|
miSVCopy: TMenuItem;
|
|
miShowRelative: TMenuItem;
|
|
miHVBack: TMenuItem;
|
|
miHVFollow: TMenuItem;
|
|
miAddRef: TMenuItem;
|
|
miTextEncodingUTF8: TMenuItem;
|
|
miDebugSetAddress: TMenuItem;
|
|
miGNUAssembler: TMenuItem;
|
|
miBinutilsSelect: TMenuItem;
|
|
miBinUtils: TMenuItem;
|
|
miSetBookmark0: TMenuItem;
|
|
miGotoBookmark0: TMenuItem;
|
|
miSetBookmark1: TMenuItem;
|
|
miSetBookmark2: TMenuItem;
|
|
miSetBookmark3: TMenuItem;
|
|
miSetBookmark4: TMenuItem;
|
|
miSetBookmark5: TMenuItem;
|
|
miSetBookmark6: TMenuItem;
|
|
miSetBookmark7: TMenuItem;
|
|
miSetBookmark8: TMenuItem;
|
|
miSetBookmark9: TMenuItem;
|
|
miGotoBookmark1: TMenuItem;
|
|
miGotoBookmark2: TMenuItem;
|
|
miGotoBookmark3: TMenuItem;
|
|
miGotoBookmark4: TMenuItem;
|
|
miGotoBookmark5: TMenuItem;
|
|
miGotoBookmark6: TMenuItem;
|
|
miGotoBookmark7: TMenuItem;
|
|
miGotoBookmark8: TMenuItem;
|
|
miGotoBookmark9: TMenuItem;
|
|
miTextEncodingAscii: TMenuItem;
|
|
miTextEncoding16: TMenuItem;
|
|
miReferencedFunctions: TMenuItem;
|
|
miUserDefinedHeader: TMenuItem;
|
|
miShowIndisassembler: TMenuItem;
|
|
miShowInHexview: TMenuItem;
|
|
miCopyBytesOnly: TMenuItem;
|
|
miDissectData2: TMenuItem;
|
|
miPointerSpider: TMenuItem;
|
|
MenuItem9: TMenuItem;
|
|
miDisassembly32: TMenuItem;
|
|
miDisassembly64: TMenuItem;
|
|
miDisassemblyAutodetect: TMenuItem;
|
|
miDisassemblerType: TMenuItem;
|
|
miAddEBP: TMenuItem;
|
|
miAddESP: TMenuItem;
|
|
miFindWhatWrites: TMenuItem;
|
|
miSelectCurrentFunction: TMenuItem;
|
|
MenuItem3: TMenuItem;
|
|
miDataBreakPointMenu: TMenuItem;
|
|
miWatchAccess: TMenuItem;
|
|
miWatchWrite: TMenuItem;
|
|
MenuItem7: TMenuItem;
|
|
miBreakAndTrace: TMenuItem;
|
|
miFindWhatAccesses: TMenuItem;
|
|
miDeleteBP: TMenuItem;
|
|
miLock: TMenuItem;
|
|
miShowDifference: TMenuItem;
|
|
miUserdefinedComment: TMenuItem;
|
|
miSepEvery4Bytes: TMenuItem;
|
|
miSepEvery8Bytes: TMenuItem;
|
|
miSepEvery2Bytes: TMenuItem;
|
|
miSeperators: TMenuItem;
|
|
miConditionalBreak: TMenuItem;
|
|
miTextPreferences: TMenuItem;
|
|
miLuaEngine: TMenuItem;
|
|
miPaging: TMenuItem;
|
|
miDebugEvents: TMenuItem;
|
|
miLockRowsize: TMenuItem;
|
|
memorypopup: TPopupMenu;
|
|
Goto1: TMenuItem;
|
|
debuggerpopup: TPopupMenu;
|
|
oflabel: TLabel;
|
|
pnlGeneralRegisters: TPanel;
|
|
pnlExtraRegisters: TPanel;
|
|
pnlFlags: TPanel;
|
|
pflabel: TLabel;
|
|
pmRegisters: TPopupMenu;
|
|
pmDebugToolbar: TPopupMenu;
|
|
sbShowFloats: TButton;
|
|
sflabel: TLabel;
|
|
SSlabel: TLabel;
|
|
Timer2: TTimer;
|
|
Panel1: TPanel;
|
|
Panel4: TPanel;
|
|
miReplacewithnops: TMenuItem;
|
|
Gotoaddress1: TMenuItem;
|
|
Search1: TMenuItem;
|
|
Change1: TMenuItem;
|
|
Addthisaddresstothelist1: TMenuItem;
|
|
miAddToTheCodelist: TMenuItem;
|
|
N1: TMenuItem;
|
|
N2: TMenuItem;
|
|
Splitter1: TSplitter;
|
|
Panel5: TPanel;
|
|
RegisterView: TPanel;
|
|
MainMenu1: TMainMenu;
|
|
File1: TMenuItem;
|
|
Loadsymbolfile1: TMenuItem;
|
|
Debug1: TMenuItem;
|
|
miDebugStep: TMenuItem;
|
|
miDebugStepOver: TMenuItem;
|
|
miDebugRunTill: TMenuItem;
|
|
miDebugToggleBreakpoint: TMenuItem;
|
|
tbDebug: TToolBar;
|
|
tbRun: TToolButton;
|
|
tbStepInto: TToolButton;
|
|
tbStepOver: TToolButton;
|
|
tbSeparator1: TToolButton;
|
|
tbStepOut: TToolButton;
|
|
tbSeparator2: TToolButton;
|
|
tbToggleBreakpoint: TToolButton;
|
|
tbRunTill: TToolButton;
|
|
tbSeparator3: TToolButton;
|
|
tbRunUnhandled: TToolButton;
|
|
View1: TMenuItem;
|
|
Stacktrace1: TMenuItem;
|
|
ScrollBox1: TScrollBox;
|
|
lblRegisters: TLabel;
|
|
sRegisters: TShape;
|
|
lblFlags: TLabel;
|
|
sFlags: TShape;
|
|
lblSpecial: TLabel;
|
|
sSpecial: TShape;
|
|
miDebugRun: TMenuItem;
|
|
Threadlist1: TMenuItem;
|
|
Assemble1: TMenuItem;
|
|
N3: TMenuItem;
|
|
miDebugBreak: TMenuItem;
|
|
Extra1: TMenuItem;
|
|
Reservememory1: TMenuItem;
|
|
Savedisassemledoutput1: TMenuItem;
|
|
Savememoryregion1: TMenuItem;
|
|
Loadmemolryregion1: TMenuItem;
|
|
N4: TMenuItem;
|
|
OpenMemory: TOpenDialog;
|
|
Debugstrings1: TMenuItem;
|
|
CreateThread1: TMenuItem;
|
|
MemoryRegions1: TMenuItem;
|
|
FillMemory1: TMenuItem;
|
|
Disectwindow1: TMenuItem;
|
|
SaveDialog1: TSaveDialog;
|
|
Heaps1: TMenuItem;
|
|
N5: TMenuItem;
|
|
N6: TMenuItem;
|
|
EnumeratedllsandSymbols1: TMenuItem;
|
|
InjectDLL1: TMenuItem;
|
|
OpenDllDialog: TOpenDialog;
|
|
AutoInject1: TMenuItem;
|
|
Dissectcode1: TMenuItem;
|
|
N7: TMenuItem;
|
|
N8: TMenuItem;
|
|
Findstaticpointers1: TMenuItem;
|
|
Scanforcodecaves1: TMenuItem;
|
|
Changestateofregisteratthislocation1: TMenuItem;
|
|
miTogglebreakpoint: TMenuItem;
|
|
Breakpointlist1: TMenuItem;
|
|
Makepagewritable1: TMenuItem;
|
|
Dissectdata1: TMenuItem;
|
|
N10: TMenuItem;
|
|
miShowSymbols: TMenuItem;
|
|
miDissectData: TMenuItem;
|
|
N11: TMenuItem;
|
|
N12: TMenuItem;
|
|
miShowModuleAddresses: TMenuItem;
|
|
miUserdefinedSymbols: TMenuItem;
|
|
Kerneltools1: TMenuItem;
|
|
Allocatenonpagedmemory1: TMenuItem;
|
|
Getaddress1: TMenuItem;
|
|
Search2: TMenuItem;
|
|
Assemblycode1: TMenuItem;
|
|
Findmemory1: TMenuItem;
|
|
Driverlist1: TMenuItem;
|
|
Plugins1: TMenuItem;
|
|
Sericedescriptortable1: TMenuItem;
|
|
N13: TMenuItem;
|
|
Cut1: TMenuItem;
|
|
Pastefromclipboard1: TMenuItem;
|
|
N14: TMenuItem;
|
|
Setsymbolsearchpath1: TMenuItem;
|
|
miKernelmodeSymbols: TMenuItem;
|
|
Breakandtraceinstructions1: TMenuItem;
|
|
GDTlist1: TMenuItem;
|
|
IDTlist1: TMenuItem;
|
|
Newwindow1: TMenuItem;
|
|
Follow1: TMenuItem;
|
|
Copytoclipboard1: TMenuItem;
|
|
copyBytes: TMenuItem;
|
|
copyOpcodes: TMenuItem;
|
|
copyBytesAndOpcodes: TMenuItem;
|
|
DissectPEheaders1: TMenuItem;
|
|
Back1: TMenuItem;
|
|
Showvaluesofstaticaddresses1: TMenuItem;
|
|
Findoutwhataddressesthisinstructionaccesses1: TMenuItem;
|
|
DisplayType1: TMenuItem;
|
|
N15: TMenuItem;
|
|
dispBytes: TMenuItem;
|
|
dispWords: TMenuItem;
|
|
dispDwords: TMenuItem;
|
|
dispFloat: TMenuItem;
|
|
dispDouble: TMenuItem;
|
|
dispInts: TMenuItem;
|
|
Jumplines1: TMenuItem;
|
|
Showjumplines1: TMenuItem;
|
|
Onlyshowjumplineswithinrange1: TMenuItem;
|
|
Watchmemoryallocations1: TMenuItem;
|
|
Continueanddetachdebugger1: TMenuItem;
|
|
N16: TMenuItem;
|
|
Panel3: TPanel;
|
|
Splitter3: TSplitter;
|
|
pnlStacktrace: TPanel;
|
|
pmStacktrace: TPopupMenu;
|
|
All1: TMenuItem;
|
|
Modulesonly1: TMenuItem;
|
|
Nonsystemmodulesonly1: TMenuItem;
|
|
lvStacktraceData: TListView;
|
|
N17: TMenuItem;
|
|
Maxstacktracesize1: TMenuItem;
|
|
Splitter2: TSplitter;
|
|
Referencedstrings1: TMenuItem;
|
|
N18: TMenuItem;
|
|
stacktrace2: TMenuItem;
|
|
miDebugExecuteTillReturn: TMenuItem;
|
|
zflabel: TLabel;
|
|
procedure Debug1Click(Sender: TObject);
|
|
procedure FormActivate(Sender: TObject);
|
|
procedure GotoBookmarkClick(Sender: TObject);
|
|
procedure Makepagewritable1Click(Sender: TObject);
|
|
procedure memorypopupPopup(Sender: TObject);
|
|
procedure MenuItem10Click(Sender: TObject);
|
|
procedure miClearCacheClick(Sender: TObject);
|
|
procedure miSearchForAccessibleStringsClick(Sender: TObject);
|
|
procedure MenuItem12Click(Sender: TObject);
|
|
procedure MenuItem14Click(Sender: TObject);
|
|
procedure MenuItem8Click(Sender: TObject);
|
|
procedure miArchChangeClick(Sender: TObject);
|
|
procedure miCR3SwitcherClick(Sender: TObject);
|
|
procedure miDBVMFindoutwhataddressesthisinstructionaccessesClick(Sender: TObject);
|
|
procedure MenuItem4Click(Sender: TObject);
|
|
procedure miIPTLogClick(Sender: TObject);
|
|
procedure miOpenInDissectDataClick(Sender: TObject);
|
|
procedure miShowRelativeDisassemblerClick(Sender: TObject);
|
|
procedure miShowSectionAddressesClick(Sender: TObject);
|
|
procedure miUndoLastEditClick(Sender: TObject);
|
|
procedure miFollowInHexviewClick(Sender: TObject);
|
|
procedure miSetSpecificBreakpointClick(Sender: TObject);
|
|
procedure miSetBreakpointClick(Sender: TObject);
|
|
procedure miCodeFilterClick(Sender: TObject);
|
|
procedure miDBVMActivateCloakClick(Sender: TObject);
|
|
procedure miDBVMDisableCloakClick(Sender: TObject);
|
|
procedure miHideToolbarClick(Sender: TObject);
|
|
procedure miUltimapClick(Sender: TObject);
|
|
procedure MenuItem17Click(Sender: TObject);
|
|
procedure MenuItem18Click(Sender: TObject);
|
|
procedure miLoadTraceClick(Sender: TObject);
|
|
procedure miWatchMemoryPageAccessClick(Sender: TObject);
|
|
procedure miUserWriteIntegerClick(Sender: TObject);
|
|
procedure miUltimap2Click(Sender: TObject);
|
|
procedure miWatchListClick(Sender: TObject);
|
|
procedure miCompareStructuresClick(Sender: TObject);
|
|
procedure miAddRefClick(Sender: TObject);
|
|
procedure miBreakOnExceptionsClick(Sender: TObject);
|
|
procedure miChangeProtectionClick(Sender: TObject);
|
|
procedure miExceptionIgnoreListClick(Sender: TObject);
|
|
procedure miExceptionRegionAutoAddAllocsClick(Sender: TObject);
|
|
procedure miExceptionRegionManageListClick(Sender: TObject);
|
|
procedure miHVBackClick(Sender: TObject);
|
|
procedure miHVFollowClick(Sender: TObject);
|
|
procedure miDebugSetAddressClick(Sender: TObject);
|
|
procedure miGNUAssemblerClick(Sender: TObject);
|
|
procedure miBinutilsSelectClick(Sender: TObject);
|
|
procedure miRunUnhandledClick(Sender: TObject);
|
|
procedure miShowRelativeClick(Sender: TObject);
|
|
procedure miSVCopyClick(Sender: TObject);
|
|
procedure miUnexpectedExceptionBreakOptionClick(Sender: TObject);
|
|
procedure pmRegistersPopup(Sender: TObject);
|
|
procedure pmStacktracePopup(Sender: TObject);
|
|
procedure RegisterViewResize(Sender: TObject);
|
|
procedure SetBookmarkClick(Sender: TObject);
|
|
procedure miTextEncodingClick(Sender: TObject);
|
|
procedure miReferencedFunctionsClick(Sender: TObject);
|
|
procedure miShowIndisassemblerClick(Sender: TObject);
|
|
procedure miCopyBytesOnlyClick(Sender: TObject);
|
|
procedure miDissectData2Click(Sender: TObject);
|
|
procedure miPointerSpiderClick(Sender: TObject);
|
|
procedure miSelectCurrentFunctionClick(Sender: TObject);
|
|
procedure miDataBreakPointMenuClick(Sender: TObject);
|
|
procedure miWatchAccessClick(Sender: TObject);
|
|
procedure miWatchWriteClick(Sender: TObject);
|
|
procedure miBreakAndTraceClick(Sender: TObject);
|
|
procedure MenuItem9Click(Sender: TObject);
|
|
procedure miAddESPClick(Sender: TObject);
|
|
procedure miConditionalBreakClick(Sender: TObject);
|
|
procedure miDeleteBPClick(Sender: TObject);
|
|
procedure miDisassemblyAutodetectClick(Sender: TObject);
|
|
procedure miFindWhatAccessesClick(Sender: TObject);
|
|
procedure miFindWhatWritesClick(Sender: TObject);
|
|
procedure miSepClick(Sender: TObject);
|
|
procedure miShowInHexviewClick(Sender: TObject);
|
|
procedure miTextPreferencesClick(Sender: TObject);
|
|
procedure miDebugEventsClick(Sender: TObject);
|
|
procedure miLuaEngineClick(Sender: TObject);
|
|
procedure miPagingClick(Sender: TObject);
|
|
procedure miUserdefinedCommentClick(Sender: TObject);
|
|
procedure miUserDefinedHeaderClick(Sender: TObject);
|
|
procedure Panel5Click(Sender: TObject);
|
|
procedure RegisterMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure miLockRowsizeClick(Sender: TObject);
|
|
procedure Showdebugtoolbar1Click(Sender: TObject);
|
|
procedure Splitter1Moved(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure Goto1Click(Sender: TObject);
|
|
procedure FormResize(Sender: TObject);
|
|
procedure Splitter2Moved(Sender: TObject);
|
|
procedure Timer2Timer(Sender: TObject);
|
|
procedure miReplacewithnopsClick(Sender: TObject);
|
|
|
|
|
|
|
|
procedure FControl1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure FControl1KeyPress(Sender: TObject; var Key: Char);
|
|
procedure Gotoaddress1Click(Sender: TObject);
|
|
procedure Search1Click(Sender: TObject);
|
|
procedure Change1Click(Sender: TObject);
|
|
procedure Addthisaddresstothelist1Click(Sender: TObject);
|
|
procedure miAddToTheCodelistClick(Sender: TObject);
|
|
procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
|
|
var Accept: Boolean);
|
|
procedure ScrollBar2Scroll(Sender: TObject; ScrollCode: TScrollCode;
|
|
var ScrollPos: Integer);
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure miDebugRunClick(Sender: TObject);
|
|
procedure miDebugStepClick(Sender: TObject);
|
|
procedure miDebugStepOverClick(Sender: TObject);
|
|
procedure miDebugRunTillClick(Sender: TObject);
|
|
procedure Stacktrace1Click(Sender: TObject);
|
|
procedure Threadlist1Click(Sender: TObject);
|
|
procedure Assemble1Click(Sender: TObject);
|
|
procedure HexEditKeyPress(Sender: TObject; var Key: Char);
|
|
procedure HexEditExit(Sender: TObject);
|
|
procedure HexEditKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure RegisterLabelDblClick(Sender: TObject);
|
|
procedure miDebugBreakClick(Sender: TObject);
|
|
procedure Reservememory1Click(Sender: TObject);
|
|
procedure Savememoryregion1Click(Sender: TObject);
|
|
procedure Loadmemolryregion1Click(Sender: TObject);
|
|
procedure HexEditDblClick(Sender: TObject);
|
|
procedure Debugstrings1Click(Sender: TObject);
|
|
procedure TextEditExit(Sender: TObject);
|
|
procedure TextEditKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure CreateThread1Click(Sender: TObject);
|
|
procedure MemoryRegions1Click(Sender: TObject);
|
|
procedure TextEditKeyPress(Sender: TObject; var Key: Char);
|
|
procedure FillMemory1Click(Sender: TObject);
|
|
procedure Disectwindow1Click(Sender: TObject);
|
|
procedure Savedisassemledoutput1Click(Sender: TObject);
|
|
procedure Heaps1Click(Sender: TObject);
|
|
procedure EnumeratedllsandSymbols1Click(Sender: TObject);
|
|
procedure InjectDLL1Click(Sender: TObject);
|
|
procedure AutoInject1Click(Sender: TObject);
|
|
procedure Dissectcode1Click(Sender: TObject);
|
|
procedure Createjumptocodecave1Click(Sender: TObject);
|
|
procedure Findstaticpointers1Click(Sender: TObject);
|
|
procedure Scanforcodecaves1Click(Sender: TObject);
|
|
procedure Changestateofregisteratthislocation1Click(Sender: TObject);
|
|
procedure miTogglebreakpointClick(Sender: TObject);
|
|
procedure Breakpointlist1Click(Sender: TObject);
|
|
procedure Dissectdata1Click(Sender: TObject);
|
|
procedure miShowSymbolsClick(Sender: TObject);
|
|
procedure miDissectDataClick(Sender: TObject);
|
|
procedure miShowModuleAddressesClick(Sender: TObject);
|
|
procedure miUserdefinedSymbolsClick(Sender: TObject);
|
|
procedure Allocatenonpagedmemory1Click(Sender: TObject);
|
|
procedure Getaddress1Click(Sender: TObject);
|
|
procedure Findmemory1Click(Sender: TObject);
|
|
procedure Assemblycode1Click(Sender: TObject);
|
|
procedure Driverlist1Click(Sender: TObject);
|
|
procedure Sericedescriptortable1Click(Sender: TObject);
|
|
procedure MBCanvasMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure Cut1Click(Sender: TObject);
|
|
procedure Pastefromclipboard1Click(Sender: TObject);
|
|
procedure Setsymbolsearchpath1Click(Sender: TObject);
|
|
procedure miKernelmodeSymbolsClick(Sender: TObject);
|
|
procedure Breakandtraceinstructions1Click(Sender: TObject);
|
|
procedure debuggerpopupPopup(Sender: TObject);
|
|
procedure GDTlist1Click(Sender: TObject);
|
|
procedure IDTlist1Click(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure Newwindow1Click(Sender: TObject);
|
|
procedure Follow1Click(Sender: TObject);
|
|
procedure copyBytesAndOpcodesClick(Sender: TObject);
|
|
procedure DissectPEheaders1Click(Sender: TObject);
|
|
procedure Back1Click(Sender: TObject);
|
|
procedure Showvaluesofstaticaddresses1Click(Sender: TObject);
|
|
procedure Findoutwhataddressesthisinstructionaccesses1Click(
|
|
Sender: TObject);
|
|
procedure sbShowFloatsClick(Sender: TObject);
|
|
procedure ScriptConsole1Click(Sender: TObject);
|
|
procedure DisplayTypeClick(Sender: TObject);
|
|
procedure Showjumplines1Click(Sender: TObject);
|
|
procedure Onlyshowjumplineswithinrange1Click(Sender: TObject);
|
|
procedure View1Click(Sender: TObject);
|
|
procedure Watchmemoryallocations1Click(Sender: TObject);
|
|
procedure Maxstacktracesize1Click(Sender: TObject);
|
|
procedure All1Click(Sender: TObject);
|
|
procedure Modulesonly1Click(Sender: TObject);
|
|
procedure Nonsystemmodulesonly1Click(Sender: TObject);
|
|
procedure Referencedstrings1Click(Sender: TObject);
|
|
procedure stacktrace2Click(Sender: TObject);
|
|
procedure miDebugExecuteTillReturnClick(Sender: TObject);
|
|
procedure lvStacktraceDataData(Sender: TObject; Item: TListItem);
|
|
procedure lvStacktraceDataDblClick(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
|
|
hasBeenShown: boolean;
|
|
|
|
R8Label: TLabel;
|
|
R9Label: TLabel;
|
|
R10Label: TLabel;
|
|
R11Label: TLabel;
|
|
R12Label: TLabel;
|
|
R13Label: TLabel;
|
|
R14Label: TLabel;
|
|
R15Label: TLabel;
|
|
|
|
xlabel: array [16..31] of tlabel;
|
|
|
|
|
|
|
|
|
|
posloadedfromreg: boolean;
|
|
displaytype: TDisplayType;
|
|
|
|
|
|
editing: boolean;
|
|
editing2: boolean;
|
|
|
|
srow,scolumn: integer;
|
|
|
|
|
|
memorylabelcount: integer;
|
|
addresslabelcount: integer;
|
|
addresslabel: array of TLabel;
|
|
memorylabel: array of TLabel; //hex
|
|
memoryLabelA: array of TLabel; //ascii
|
|
MemoryLabelVerticalLines: integer; //number of rows
|
|
MemoryLabelHorizontalLines: Integer; //the number of lines
|
|
|
|
addressestext: array of string[8];
|
|
memorytext: array of string[2];
|
|
memorystring: array of string;
|
|
lengthof8bytes: Integer;
|
|
|
|
// x:tno
|
|
|
|
lines: integer;
|
|
oldlines: integer;
|
|
Highlightcolor: Tcolor;
|
|
|
|
fAccessedRegisterColor: TColor;
|
|
fChangedRegisterColor: TColor;
|
|
|
|
numberofaddresses: integer;
|
|
|
|
|
|
part: integer;
|
|
|
|
|
|
lastmodulelistupdate: integer;
|
|
|
|
disassemblerHistory: TStringList;
|
|
memorybrowserHistory: TStringList;
|
|
assemblerHistory: TStringList;
|
|
|
|
|
|
|
|
lastspecialwidth: integer;
|
|
FShowValues: boolean;
|
|
FShowDebugPanels: boolean;
|
|
FStacktraceSize: integer;
|
|
|
|
strace: Tstringlist;
|
|
|
|
lastBreakpointCondition: record
|
|
script: string;
|
|
easy: boolean;
|
|
end;
|
|
|
|
bookmarks: array [0..9] of record
|
|
addressString: string;
|
|
lastAddress: ptruint;
|
|
setMi: TMenuItem;
|
|
gotoMi: TMenuItem;
|
|
end;
|
|
|
|
currentBinutils: Tbinutils;
|
|
|
|
StackReference: ptruint;
|
|
|
|
adjustedsize: boolean;
|
|
registerpanelfont: TFont;
|
|
|
|
overridebreakpointmethod: boolean;
|
|
preferedF5BreakpointMethod: TBreakpointMethod;
|
|
|
|
followRegister: PContextElement_register;
|
|
|
|
fcr3: qword;
|
|
fcr3switcher: TfrmCR3Switcher;
|
|
|
|
procedure ShowDebugToolbar;
|
|
procedure HideDebugToolbar;
|
|
|
|
procedure cr3switcherCR3Change(sender: TObject);
|
|
procedure SetStacktraceSize(size: integer);
|
|
procedure setShowDebugPanels(state: boolean);
|
|
function getShowValues: boolean;
|
|
procedure setShowValues(newstate: boolean);
|
|
|
|
|
|
procedure disassemblerviewDblClick(Sender: TObject);
|
|
procedure setHexviewAddress(a: ptrUint);
|
|
function getHexviewAddress:ptrUint;
|
|
procedure hexviewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ApplyFollowRegister;
|
|
procedure setCR3(newcr3: qword);
|
|
function ReadProcessMemory(hProcess: THandle; lpBaseAddress, lpBuffer: Pointer; nSize: size_t; var lpNumberOfBytesRead: PTRUINT): BOOL;
|
|
|
|
procedure setCaption(c: string);
|
|
function getCaption: string;
|
|
|
|
public
|
|
{ Public declarations }
|
|
FSymbolsLoaded: Boolean;
|
|
|
|
|
|
|
|
thhandle: Thandle;
|
|
|
|
disassemblerview: TDisassemblerview;
|
|
hexview: THexview;
|
|
|
|
context: pointer;
|
|
contexthandler: TContextInfo;
|
|
|
|
|
|
laststack: pbytearray;
|
|
|
|
disassembler: boolean;
|
|
cancelsearch: boolean;
|
|
|
|
ischild: boolean; //determines if it's the main memorybrowser or a child
|
|
// backlist: TStack;
|
|
|
|
frmiptlog: TfrmIPTLogDisplay;
|
|
|
|
showdebugpaneltimer: TTimer;
|
|
|
|
procedure showDebugPaneltimertimer(sender: TObject);
|
|
|
|
procedure setRegisterPanelFont(f: TFont);
|
|
|
|
procedure FindwhatThiscodeAccesses(address: ptrUint);
|
|
procedure DBVMFindwhatThiscodeAccesses(address: ptrUint);
|
|
|
|
procedure AssemblePopup(x: string);
|
|
|
|
procedure plugintype1click(sender:tobject);
|
|
procedure plugintype6click(sender:tobject);
|
|
procedure setcodeanddatabase;
|
|
procedure GetEntryPointAndDataBase(var code: ptrUint; var data: ptrUint);
|
|
property showvalues: boolean read getShowValues write setShowValues;
|
|
property showDebugPanels: boolean read fShowDebugPanels write setShowDebugPanels;
|
|
property stacktraceSize: integer read FStacktraceSize write SetStacktraceSize;
|
|
property memoryaddress: ptrUint read getHexviewAddress write setHexviewAddress;
|
|
procedure reloadStacktrace;
|
|
function GetReturnaddress: ptrUint;
|
|
|
|
procedure OnMemoryViewerRunning;
|
|
|
|
procedure UpdateDebugContext(threadhandle: THandle; threadid: dword; changeSelection: boolean=true; _debuggerthread: TDebuggerthread=nil);
|
|
procedure miLockOnClick(Sender: TObject);
|
|
procedure miLockMemviewClick(sender: TObject);
|
|
|
|
procedure miDifferenceClick(Sender: TObject);
|
|
procedure miStopDifferenceClick(Sender: TObject);
|
|
procedure Scrollboxscroll(sender: TObject);
|
|
|
|
procedure createcr3switcher;
|
|
property cr3switcher: TfrmCR3Switcher read fcr3switcher;
|
|
published
|
|
//support for old scripts that reference these
|
|
property Run1: TMenuItem read miDebugRun;
|
|
property Step1: TMenuItem read miDebugStep;
|
|
property StepOver1: TMenuItem read miDebugStepOver;
|
|
property Executetillreturn1: TMenuItem read miDebugExecuteTillReturn;
|
|
property RunTill1: TMenuItem read miDebugRunTill;
|
|
property miSetAddress: TMenuItem read miDebugSetAddress;
|
|
property Setbreakpoint1: TMenuItem read miDebugToggleBreakpoint;
|
|
property Showsymbols1: TMenuItem read miShowSymbols;
|
|
property Kernelmodesymbols1: TMenuItem read miKernelmodeSymbols;
|
|
property Showmoduleaddresses1: TMenuItem read miShowModuleAddresses;
|
|
property Symbolhandler1: TMenuItem read miUserdefinedSymbols;
|
|
property AccessedRegisterColor: TColor read faccessedRegisterColor write faccessedRegisterColor;
|
|
property ChangedRegisterColor: TColor read fChangedRegisterColor write fChangedRegisterColor;
|
|
property CR3: QWORD read fCR3 write setCR3;
|
|
property Caption: string read getCaption write setCaption;
|
|
end;
|
|
|
|
var
|
|
MemoryBrowser: TMemoryBrowser;
|
|
mbchildcount: integer; //global so all other children can increase it as well
|
|
|
|
|
|
MemoryBrowsers: TList; //contains a list of all the memorybrowsers
|
|
|
|
|
|
|
|
implementation
|
|
|
|
uses Valuechange, MainUnit, debugeventhandler, findwindowunit,
|
|
frmstacktraceunit, frmBreakThreadUnit, FormDebugStringsUnit,
|
|
frmDissectWindowUnit, frmEnumerateDLLsUnit, frmThreadlistunit,
|
|
formmemoryregionsunit, frmHeapsUnit, frmFindstaticsUnit,
|
|
frmModifyRegistersUnit, savedisassemblyfrm, frmBreakpointlistunit,
|
|
AdvancedOptionsUnit, frmautoinjectunit, formsettingsunit,
|
|
frmSaveMemoryRegionUnit, frmLoadMemoryunit, inputboxtopunit,
|
|
formAddToCodeList, frmFillMemoryUnit, frmCodecaveScannerUnit, FoundCodeUnit,
|
|
frmSelectionlistunit, symbolconfigunit, frmFloatingPointPanelUnit,
|
|
frmTracerUnit, dissectcodeunit, DriverList, formChangedAddresses, PEInfounit,
|
|
frmGDTunit, frmIDTunit, frmDisassemblyscanunit, ServiceDescriptorTables,
|
|
frmReferencedStringsUnit, frmReferencedFunctionsUnit, Structuresfrm,
|
|
StructuresFrm2, pointerscannerfrm, frmDebugEventsUnit, frmPagingUnit,
|
|
frmluaengineunit, disassemblerviewlinesunit, frmBreakpointConditionUnit,
|
|
frmStringMapUnit, frmStringPointerScanUnit, frmFilePatcherUnit,
|
|
frmUltimapUnit, frmUltimap2Unit, frmAssemblyScanUnit, MemoryQuery,
|
|
AccessedMemory, Parsers, GnuAssembler, frmEditHistoryUnit, frmWatchlistUnit,
|
|
vmxfunctions, frmstructurecompareunit, globals, UnexpectedExceptionsHelper,
|
|
frmExceptionRegionListUnit, frmExceptionIgnoreListUnit, frmcodefilterunit,
|
|
frmDBVMWatchConfigUnit, DBK32functions, DPIHelper, DebuggerInterface,
|
|
DebuggerInterfaceAPIWrapper, BreakpointTypeDef, CustomTypeHandler,
|
|
frmSourceDisplayUnit, sourcecodehandler, tcclib, mainunit2, GDBServerDebuggerInterface
|
|
{$ifdef ONEBYTEJUMPS}, autoassemblerexeptionhandler{$endif};
|
|
|
|
|
|
resourcestring
|
|
rsUnlinkFromOtherHexview = 'Unlink from other hexview';
|
|
rsLinkWithOtherHexview = 'Link with other hexview';
|
|
rsStopShowingTheDifference = 'Stop showing the difference';
|
|
rsShowDifference = 'Show difference';
|
|
rsBetween = 'Between %s';
|
|
rsHowLongShouldAChangeBeShown = 'How long should a change be shown?';
|
|
rsChangeDisplayFader = 'Change display fader';
|
|
rsGotoAddress = 'Goto Address';
|
|
rsFillInTheAddressYouWantToGoTo = 'Fill in the address you want to go to';
|
|
rsMemoryViewerRunning = 'Memory Viewer - Running';
|
|
rsCheatEngineSingleLingeAssembler = 'Single-line assembler';
|
|
rsTypeYourAssemblerCodeHereAddress = 'Type your assembler code here: (address=%s)';
|
|
rsTheGeneratedCodeIsByteSLongButTheSelectedOpcodeIsB = 'The generated code is %s byte(s) long, but the selected opcode is %s byte(s) long! Do you want to replace the '
|
|
+'incomplete opcode(s) with NOP''s?';
|
|
rsIDonTUnderstandWhatYouMeanWith = 'I don''t understand what you mean with %s';
|
|
rsChangeRegister = 'Change register';
|
|
rsWhatIsTheNewValueOf = 'What is the new value of %s?';
|
|
rs0Or1 = '(0 or 1)';
|
|
rsIsNotAValidValue = '%s is not a valid value';
|
|
rsAllocateMemory = 'Allocate memory';
|
|
rsHowMuchMemoryDoYouWantToAddToThisProcess = 'How much memory do you want to add to this process?';
|
|
rsHowMuchIs = 'How much is %s?';
|
|
rsErrorAllocatingMemory = 'Error allocating memory!';
|
|
rsAtLeastBytesHaveBeenAllocatedAtDoYouWantToGoThereN = 'At least %s bytes have been allocated at %s%sDo you want to go there now?';
|
|
rsCreateRemoteThread = 'Create remote thread';
|
|
rsWhatWillBeTheStartaddressOfThisThread = 'What will be the startaddress of this thread?';
|
|
rsPleaseEnterAValidHexadecimalAddres = 'Please enter a valid hexadecimal addres';
|
|
rsYouWantToGiveAnAdditional32BitParameterWillShowUpI = 'You want to give an additional 32-bit parameter? (Will show up in (R)/(E)BX)';
|
|
rsPleaseEnterAValidHexadecimalValue = 'Please enter a valid hexadecimal value';
|
|
rsPleaseTargetAProcessFirst = 'Please target a process first';
|
|
rsPleaseTargetAnotherProcess = 'Start another version of '+strCheatEngine+' and attach to that instead';
|
|
rsDoYouWantToExecuteAFunctionOfTheDll = 'Do you want to execute a function of the dll?';
|
|
rsInjectDll = 'Inject dll';
|
|
rsSelectTheFunctionYouWantToExecute = 'Select the function you want to execute';
|
|
rsDLLInjected = 'DLL Injected';
|
|
rsHowMuchMemoryDoYouWishToAllocate = 'How much memory do you wish to allocate?';
|
|
rsAtLeastBytesHaveBeenAllocatedAtGoThereNow = 'At least %s bytes have been allocated at %s. Go there now?';
|
|
rsGetKernelAddress = 'Get kernel address';
|
|
rsGiveTheNameOfTheFunctionYouWantToFindCaseSensitive = 'Give the name of the function you want to find (Case sensitive,certain words can cause blue screens)';
|
|
rsAssemblyScan = 'Assembly scan';
|
|
rsInputTheAssemblyCodeToFindWilcardsSupported = 'Input the assembly code to find. Wildcards( * ) supported.';
|
|
rsSymbolHandler = 'Symbol handler';
|
|
rsPleaseSpecifyTheNewSymbolSearchpathSeperatesPaths = 'Please specify the new symbol searchpath (; separates paths)';
|
|
rsMemoryBrowser = 'MemoryBrowser';
|
|
rsReturnAddress = 'Return Address';
|
|
rsParameters = 'Parameters';
|
|
rsAddress = 'Address';
|
|
rsValue = 'Value';
|
|
rsStacktrace = 'Stacktrace';
|
|
rsNewSize = 'New size';
|
|
rsMaxStacktraceSize = 'Max stacktrace size';
|
|
rsNeedToRunDissectCode = 'You will need to run the dissect code routine first before this window is usable. Run it now?';
|
|
rsMemoryViewerCurrentlyDebuggingThread = 'Memory Viewer - Currently debugging thread %s';
|
|
rsRestoreWithOrginalCode = 'Restore with original code';
|
|
rsReplaceWithCodeThatDoesNothing = 'Replace with code that does nothing';
|
|
rsComment = 'Comment';
|
|
rsCommentFor = 'Comment for %s';
|
|
rsHeaderFor = 'Header for %s';
|
|
rsSShowsTheAutoguessValue = '(%s shows the autoguess value)';
|
|
rsMBBookmark = 'Bookmark %d';
|
|
rsMBBookmark2 = 'Bookmark %d: %s';
|
|
rsMBCreationOfTheRemoteThreadFailed = 'Creation of the remote thread failed';
|
|
rsMBThreadCreated = 'Thread Created';
|
|
rsBecauseOfUnhandledExeption = 'Because of unhandled exception %s';
|
|
rsSomethingHappened = 'something happened';
|
|
rsSetBreakpoint = 'Set breakpoint';
|
|
rsRemoveBreakpoint = 'Remove breakpoint';
|
|
rsInjectDYLIB = 'Inject DYLIB';
|
|
rsSetCustomAlignment = 'Set custom alignment';
|
|
|
|
//property functions:
|
|
function TMemoryBrowser.getShowValues: boolean;
|
|
begin
|
|
result:=FShowValues;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.setShowValues(newstate: boolean);
|
|
begin
|
|
Showvaluesofstaticaddresses1.checked:=newstate;
|
|
FShowValues:=newstate;
|
|
if disassemblerview<>nil then
|
|
disassemblerview.setCommentsTab(FShowValues);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.setShowDebugPanels(state: boolean);
|
|
var
|
|
oldstackwidth: integer;
|
|
oldpanel3width: integer;
|
|
|
|
cw: integer;
|
|
ew: integer;
|
|
begin
|
|
|
|
oldstackwidth:=pnlStacktrace.Width;
|
|
oldpanel3width:=panel3.width;
|
|
|
|
|
|
FShowDebugPanels:=state;
|
|
|
|
|
|
registerview.Visible:=state;
|
|
pnlStacktrace.Visible:=state;
|
|
|
|
splitter2.Visible:=state;
|
|
splitter3.Visible:=state;
|
|
|
|
pnlStacktrace.width:=oldstackwidth;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.SetStacktraceSize(size: integer);
|
|
var x: ptrUint;
|
|
begin
|
|
if (context=nil) or (contexthandler=nil) then exit;
|
|
FStacktraceSize:=size;
|
|
|
|
if laststack<>nil then
|
|
freememandnil(laststack);
|
|
|
|
laststack:=getmem(size);
|
|
readprocessmemory(processhandle, pointer(contexthandler.StackPointerRegister^.getValue(context)), laststack, size, x);
|
|
|
|
reloadStacktrace;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.setCaption(c: string);
|
|
var cr3pos, cr3posend: integer;
|
|
begin
|
|
cr3pos:=pos(' (CR3 ',c);
|
|
if (fcr3<>0) and (cr3pos=0) then //add the statement which CR3 this is
|
|
c:=c+' (CR3 '+inttohex(fcr3,8)+')';
|
|
|
|
|
|
if (fcr3=0) and (cr3pos<>0) then //delete it
|
|
begin
|
|
cr3posend:=Pos(')',c,cr3pos+1);
|
|
if cr3posend>0 then
|
|
c:=copy(c,1,cr3pos-1)+copy(c,cr3posend+1);
|
|
end;
|
|
|
|
inherited caption:=c;
|
|
end;
|
|
|
|
function TMemoryBrowser.getCaption: string;
|
|
begin
|
|
result:=inherited caption;
|
|
end;
|
|
|
|
//^^^^
|
|
|
|
|
|
function TMemoryBrowser.ReadProcessMemory(hProcess: THandle; lpBaseAddress, lpBuffer: Pointer; nSize: size_t; var lpNumberOfBytesRead: PTRUINT): BOOL;
|
|
begin
|
|
if fcr3=0 then
|
|
result:={$ifdef windows}newkernelhandler.{$endif}{$ifdef darwin}macport.{$endif}ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead)
|
|
{$ifdef windows}
|
|
else
|
|
result:=ReadProcessMemoryCR3(fcr3,lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead){$endif};
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.Splitter1Moved(Sender: TObject);
|
|
begin
|
|
disassemblerview.Update;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miLockRowsizeClick(Sender: TObject);
|
|
var
|
|
rs: string;
|
|
waslocked: boolean;
|
|
newsize: integer;
|
|
begin
|
|
waslocked:=hexview.LockedRowSize<>0;
|
|
|
|
|
|
hexview.LockRowsize; //fills in lockedRowSize
|
|
rs:=inttostr(hexview.LockedRowSize);
|
|
|
|
if InputQuery('Alignment','Enter the custom alignment (<=0 is automatic)', rs) then
|
|
begin
|
|
try
|
|
newsize:=StrToInt(rs);
|
|
if newsize<=0 then newsize:=0;
|
|
|
|
hexview.LockedRowSize:=newsize;
|
|
except
|
|
if waslocked=false then
|
|
hexview.UnlockRowsize;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if waslocked=false then
|
|
hexview.UnlockRowsize;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.ShowDebugToolbar;
|
|
begin
|
|
tbDebug.Visible:=true;
|
|
tbDebug.Tag:=0;
|
|
Showdebugtoolbar1.Checked:=true;
|
|
showDebugPanels:=true;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.HideDebugToolbar;
|
|
begin
|
|
tbDebug.Visible:=false;
|
|
Showdebugtoolbar1.Checked:=false;
|
|
showDebugPanels:=false;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Showdebugtoolbar1Click(Sender: TObject);
|
|
begin
|
|
if tbDebug.Visible=false then ShowDebugToolbar
|
|
else HideDebugToolbar;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.RegisterMouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var s: string;
|
|
i: integer;
|
|
begin
|
|
if button = mbright then
|
|
begin
|
|
if (sender is TLabel) then
|
|
begin
|
|
s:=trim(tlabel(sender).Caption);
|
|
i:=pos(' ',s);
|
|
if i>0 then //should always be true
|
|
begin
|
|
s:=copy(s,i+1,length(s));
|
|
|
|
clipboard.AsText:=s;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugEventsClick(Sender: TObject);
|
|
begin
|
|
if frmDebugEvents=nil then
|
|
frmDebugEvents:=tfrmDebugEvents.create(application);
|
|
|
|
frmDebugEvents.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miLuaEngineClick(Sender: TObject);
|
|
begin
|
|
//start lua engine window
|
|
if frmLuaEngine=nil then
|
|
frmLuaEngine:=TfrmLuaEngine.create(MemoryBrowser); //main mb
|
|
|
|
frmLuaEngine.show;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miPagingClick(Sender: TObject);
|
|
begin
|
|
TfrmPaging.create(application).show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUserdefinedCommentClick(Sender: TObject);
|
|
var
|
|
s: tstringlist;
|
|
begin
|
|
s:=tstringlist.create;
|
|
try
|
|
s.text:=dassemblercomments.comments[disassemblerview.SelectedAddress];
|
|
if multilineinputquery(Format(rsCommentFor, [inttohex(disassemblerview.SelectedAddress, 8)]), Format(rsCommentFor, [inttohex(disassemblerview.SelectedAddress, 8)])+' '+rsSShowsTheAutoguessValue, s) then
|
|
dassemblercomments.comments[disassemblerview.SelectedAddress]:=utf8toansi(s.text);
|
|
finally
|
|
s.free;
|
|
end;
|
|
|
|
disassemblerview.Refresh;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUserDefinedHeaderClick(Sender: TObject);
|
|
var
|
|
s: tstringlist;
|
|
begin
|
|
s:=tstringlist.create;
|
|
try
|
|
s.text:=ansitoutf8(dassemblercomments.commentHeader[disassemblerview.SelectedAddress]);
|
|
if multilineinputquery(rsHeaderFor, Format(rsCommentFor, [inttohex(disassemblerview.SelectedAddress, 8)])+' '+rsSShowsTheAutoguessValue, s) then
|
|
dassemblercomments.commentHeader[disassemblerview.SelectedAddress]:=utf8toansi(s.text);
|
|
finally
|
|
s.free;
|
|
end;
|
|
|
|
disassemblerview.Refresh;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Panel5Click(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miLockOnClick(Sender: TObject);
|
|
begin
|
|
hexview.unlock;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miLockMemviewClick(sender: TObject);
|
|
begin
|
|
hexview.Lock(TMemoryBrowser(MemoryBrowsers[(sender as TMenuItem).tag]).hexview);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDifferenceClick(Sender: TObject);
|
|
begin
|
|
hexview.ShowDifference(TMemoryBrowser(MemoryBrowsers[(sender as TMenuItem).tag]).hexview);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miStopDifferenceClick(Sender: TObject);
|
|
begin
|
|
hexview.EndDifferenceView;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.memorypopupPopup(Sender: TObject);
|
|
var
|
|
m: TMemorybrowser;
|
|
mi: menus.tmenuitem;
|
|
i,j: integer;
|
|
|
|
islocked: boolean;
|
|
a,a2: ptruint;
|
|
hasbp: boolean;
|
|
|
|
mbi: TMEMORYBASICINFORMATION;
|
|
|
|
|
|
begin
|
|
miClearCache.visible:=(CurrentDebuggerInterface<>nil) and (CurrentDebuggerInterface is TGDBServerDebuggerInterface) and GDBReadProcessMemory;
|
|
|
|
|
|
//update customtypes
|
|
|
|
|
|
for i:=0 to customTypes.Count-1 do
|
|
begin
|
|
j:=dispDouble.MenuIndex+1+i;
|
|
if j<DisplayType1.Count then
|
|
mi:=displayType1.Items[j]
|
|
else
|
|
begin
|
|
mi:=tmenuitem.create(memorypopup);
|
|
mi.OnClick:=DisplayTypeClick;
|
|
mi.AutoCheck:=true;
|
|
mi.RadioItem:=true;
|
|
mi.GroupIndex:=3;
|
|
DisplayType1.Add(mi);
|
|
end;
|
|
|
|
mi.caption:=TCustomType(customtypes[i]).name;
|
|
mi.tag:=$1000+i;
|
|
end;
|
|
|
|
//delete the entries that are too many
|
|
while DisplayType1.Count>dispDouble.MenuIndex+customTypes.Count+1 do
|
|
DisplayType1.Delete(dispDouble.MenuIndex+customTypes.Count+1);
|
|
|
|
|
|
miShowDifference.clear;
|
|
miLock.Clear;
|
|
|
|
islocked:=hexview.isLocked;
|
|
if isLocked then
|
|
begin
|
|
miLock.OnClick:=miLockOnClick;
|
|
miLock.caption:=rsUnlinkFromOtherHexview;
|
|
end
|
|
else
|
|
begin
|
|
miLock.OnClick:=nil;
|
|
miLock.caption:=rsLinkWithOtherHexview;
|
|
end;
|
|
|
|
if hexview.isShowingDifference then
|
|
begin
|
|
miShowDifference.caption:=rsStopShowingTheDifference;
|
|
miShowDifference.onclick:=miStopDifferenceClick;
|
|
end
|
|
else
|
|
begin
|
|
miShowDifference.caption:=rsShowDifference;
|
|
miShowDifference.onclick:=nil;
|
|
end;
|
|
|
|
miLock.enabled:=MemoryBrowsers.count>1;
|
|
|
|
for i:=0 to MemoryBrowsers.count-1 do
|
|
begin
|
|
m:=Memorybrowsers[i];
|
|
if m<>self then
|
|
begin
|
|
if not hexview.isShowingDifference then
|
|
begin
|
|
miClearCache:=TMenuItem.Create(miShowDifference);
|
|
miClearCache.Caption:=Format(rsBetween, [m.Caption]);
|
|
miClearCache.OnClick:=miDifferenceClick;
|
|
miClearCache.tag:=i;
|
|
miShowDifference.Add(miClearCache);
|
|
end;
|
|
|
|
if not islocked then
|
|
begin
|
|
miClearCache:=TMenuItem.Create(miLock);
|
|
miClearCache.caption:=m.caption;
|
|
miClearCache.OnClick:=miLockMemviewClick;
|
|
miClearCache.tag:=i;
|
|
miLock.add(miClearCache);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
if (hexview.hasSelection) then
|
|
begin
|
|
hexview.GetSelectionRange(a,a2);
|
|
|
|
hasbp:=(debuggerthread<>nil) and (debuggerthread.isBreakpoint(a,a2)<>nil);
|
|
miDataBreakPointMenu.visible:=(not ischild) and (not hasbp);
|
|
miWatchWrite.visible:=not hasbp;
|
|
miWatchAccess.visible:=not hasbp;
|
|
MenuItem7.visible:=not hasbp;
|
|
miBreakAndTrace.visible:=not hasbp;
|
|
miDeleteBP.visible:=hasbp;
|
|
|
|
miHVFollow.Visible:=hexview.CanFollow;
|
|
Addthisaddresstothelist1.visible:=true;
|
|
end
|
|
else
|
|
begin
|
|
miDataBreakPointMenu.visible:=false;
|
|
miWatchWrite.visible:=false;
|
|
miWatchAccess.visible:=false;
|
|
MenuItem7.visible:=false;
|
|
miBreakAndTrace.visible:=false;
|
|
miDeleteBP.visible:=false;
|
|
|
|
Addthisaddresstothelist1.visible:=false;
|
|
end;
|
|
|
|
miHVBack.visible:=hexview.hasBackList;
|
|
miShowRelative.checked:=hexview.UseRelativeBase;
|
|
|
|
|
|
|
|
miChangeProtectionRWE.checked:=false;
|
|
miChangeProtectionRE.checked:=false;
|
|
miChangeProtectionRW.checked:=false;
|
|
miChangeProtectionR.checked:=false;
|
|
if VirtualQueryEx(processhandle, pointer(hexview.Address), mbi, sizeof(mbi))=sizeof(mbi) then
|
|
begin
|
|
miChangeProtectionRWE.checked:=((mbi.Protect and PAGE_EXECUTE_READWRITE)=PAGE_EXECUTE_READWRITE) or ((mbi.Protect and PAGE_EXECUTE_WRITECOPY)=PAGE_EXECUTE_WRITECOPY);
|
|
miChangeProtectionRE.checked:=((mbi.Protect and PAGE_EXECUTE)=PAGE_EXECUTE) or ((mbi.Protect and PAGE_EXECUTE_READ)=PAGE_EXECUTE_READ);
|
|
miChangeProtectionRW.checked:=((mbi.Protect and PAGE_READWRITE)=PAGE_READWRITE) or ((mbi.Protect and PAGE_WRITECOPY)=PAGE_WRITECOPY);
|
|
miChangeProtectionR.checked:=((mbi.Protect and PAGE_READONLY)=PAGE_READONLY);
|
|
end;
|
|
|
|
//
|
|
miWatchBPHardware.enabled:=(CurrentDebuggerInterface=nil) or (dbcHardwareBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities);
|
|
miWatchBPException.enabled:=(CurrentDebuggerInterface=nil) or (dbcSoftwareBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities);
|
|
miWatchBPDBVM.enabled:=(CurrentDebuggerInterface=nil) or (dbcExceptionBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities);
|
|
miWatchBPDBVM.visible:={$ifdef windows}hasEPTSupport{$else}false{$endif};
|
|
|
|
if hexview.LockedRowSize<>0 then
|
|
miLockRowsize.caption:=rsSetCustomAlignment+' ('+inttostr(hexview.LockedRowSize)+')'
|
|
else
|
|
miLockRowsize.caption:=rsSetCustomAlignment;
|
|
|
|
miChangeProtectionRWE.enabled:=SystemSupportsWritableExecutableMemory;
|
|
miChangeProtectionRWE.visible:=SystemSupportsWritableExecutableMemory;
|
|
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.MenuItem10Click(Sender: TObject);
|
|
begin
|
|
if frmStringMap=nil then
|
|
frmStringMap:=TfrmStringMap.Create(application);
|
|
|
|
frmStringMap.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miClearCacheClick(Sender: TObject);
|
|
begin
|
|
if (CurrentDebuggerInterface is TGDBServerDebuggerInterface) then
|
|
TGDBServerDebuggerInterface(CurrentDebuggerInterface).ClearRPMCachePage(hexview.Address);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miSearchForAccessibleStringsClick(Sender: TObject);
|
|
begin
|
|
if frmStringPointerscan=nil then
|
|
frmStringpointerscan:=Tfrmstringpointerscan.create(MemoryBrowser);
|
|
|
|
frmStringpointerscan.rbStringscan.Checked:=true;
|
|
frmStringpointerscan.edtBase.text:=inttohex(hexview.address,8);
|
|
|
|
frmStringpointerscan.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MenuItem12Click(Sender: TObject);
|
|
var f: Tfrmfilepatcher;
|
|
begin
|
|
f:=tfrmfilepatcher.create(self);
|
|
f.showmodal;
|
|
f.free;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.MenuItem14Click(Sender: TObject);
|
|
begin
|
|
EnableWindowsSymbols(true);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MenuItem8Click(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemorybrowser.setCR3(newcr3: qword);
|
|
var oldcr3: qword;
|
|
begin
|
|
oldcr3:=fcr3;
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4120;
|
|
|
|
fcr3:=newcr3;
|
|
disassemblerview.cr3:=fcr3;
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4121;
|
|
hexview.cr3:=fcr3;
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4122;
|
|
|
|
if (newcr3<>oldcr3) then
|
|
begin
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4123;
|
|
createcr3switcher;
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4124;
|
|
fcr3switcher.addCR3ToList(newcr3);
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4125;
|
|
fcr3switcher.Show;
|
|
if debuggerthread<>nil then debuggerthread.execlocation:=4126;
|
|
end;
|
|
|
|
caption:=caption;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.cr3switcherCR3Change(sender: TObject);
|
|
begin
|
|
//cr3 changed, notify the disassembler and hexview
|
|
cr3:=cr3switcher.cr3;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.createcr3switcher;
|
|
begin
|
|
if fcr3switcher=nil then
|
|
begin
|
|
fcr3switcher:=TfrmCR3Switcher.Create(self);
|
|
fcr3switcher.OnCR3Change:=cr3switcherCR3Change;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miCR3SwitcherClick(Sender: TObject);
|
|
begin
|
|
//the cr3 switcher is unique for each memview window
|
|
createcr3switcher;
|
|
fcr3switcher.Show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDBVMFindoutwhataddressesthisinstructionaccessesClick(Sender: TObject);
|
|
begin
|
|
DBVMFindwhatThiscodeAccesses(disassemblerview.SelectedAddress);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MenuItem4Click(Sender: TObject);
|
|
begin
|
|
if tbDebug.Visible=true then HideDebugToolbar;
|
|
tbDebug.Tag:=-1;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miIPTLogClick(Sender: TObject);
|
|
var log: pointer;
|
|
logsize: integer;
|
|
begin
|
|
{$IFDEF WINDOWS}
|
|
log:=nil;
|
|
if (debuggerthread<>nil) and (debuggerthread.CurrentThread<>nil) then
|
|
begin
|
|
//broken state
|
|
if debuggerthread.CurrentThread.getLastIPTLog(log,logsize)=false then
|
|
begin
|
|
if useintelptfordebug=false then
|
|
begin
|
|
if messagedlg('This will require the IPT feature to be enabled in the debugger. Activate it now? (You will need a new break to record a log)', mtConfirmation, [mbyes,mbno],0)=mryes then
|
|
begin
|
|
useintelptfordebug:=true;
|
|
debuggerthread.initIntelPTTracing;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if debuggerthread.initIntelPTTracing then
|
|
messagedlg('Error retrieving the IPT log. Try again later', mtError, [mbok],0)
|
|
else
|
|
messagedlg('Error activating the IPT log', mtError, [mbok],0)
|
|
end;
|
|
exit;
|
|
end;
|
|
|
|
if frmiptlog=nil then
|
|
begin
|
|
frmiptlog:=TfrmIPTLogDisplay.Create(MemoryBrowser);
|
|
frmiptlog.OnClose:=nil;
|
|
end;
|
|
|
|
frmiptlog.show;
|
|
if log<>nil then
|
|
begin
|
|
frmiptlog.loadlog(debuggerthread.CurrentThread.ThreadId.ToHexString+'-'+GetTickCount.ToHexString,log,logsize, contexthandler.InstructionPointerRegister^.getValue(context));
|
|
freemem(log);
|
|
end;
|
|
|
|
end;
|
|
{$ENDIF}
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miOpenInDissectDataClick(Sender: TObject);
|
|
begin
|
|
//create it
|
|
with tfrmstructures2.create(application) do
|
|
begin
|
|
initialaddress:=hexview.SelectionStart;
|
|
show;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowRelativeDisassemblerClick(Sender: TObject);
|
|
begin
|
|
if miShowRelativeDisassembler.checked then
|
|
begin
|
|
if disassemblerview.SelectedAddress<>0 then
|
|
begin
|
|
disassemblerview.RelativeBase:=disassemblerview.SelectedAddress;
|
|
disassemblerview.UseRelativeBase:=true;
|
|
end
|
|
else
|
|
begin
|
|
disassemblerview.RelativeBase:=disassemblerview.TopAddress;
|
|
disassemblerview.UseRelativeBase:=true;
|
|
end;
|
|
end
|
|
else
|
|
disassemblerview.UseRelativeBase:=false;
|
|
|
|
disassemblerview.update;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.miUndoLastEditClick(Sender: TObject);
|
|
begin
|
|
if logWrites then
|
|
begin
|
|
undowrite(disassemblerview.SelectedAddress);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.ApplyFollowRegister;
|
|
begin
|
|
if (followRegister<>nil) and (context<>nil) then
|
|
hexview.address:=followRegister^.getValue(context);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miFollowInHexviewClick(Sender: TObject);
|
|
begin
|
|
if miFollowInHexview.checked then
|
|
followRegister:=PContextElement_register(pmRegisters.PopupComponent.Tag)
|
|
else
|
|
followRegister:=nil;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miSetSpecificBreakpointClick(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miSetBreakpointClick(Sender: TObject);
|
|
var bpm: TBreakpointMethod;
|
|
begin
|
|
if startdebuggerifneeded(true) then
|
|
begin
|
|
case tmenuitem(sender).tag of
|
|
0: bpm:=bpmDebugRegister;
|
|
1: bpm:=bpmInt3;
|
|
2: bpm:=bpmException;
|
|
3: bpm:=bpmDBVM;
|
|
end;
|
|
|
|
overridebreakpointmethod:=true;
|
|
preferedF5BreakpointMethod:=bpm;
|
|
|
|
try
|
|
DebuggerThread.SetOnExecuteBreakpoint(disassemblerview.SelectedAddress, bpm);
|
|
disassemblerview.Update;
|
|
except
|
|
on e:exception do MessageDlg(e.message,mtError,[mbok],0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miCodeFilterClick(Sender: TObject);
|
|
begin
|
|
if frmcodefilter=nil then
|
|
frmcodefilter:=tfrmcodefilter.create(application);
|
|
|
|
frmcodefilter.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDBVMActivateCloakClick(Sender: TObject);
|
|
var
|
|
PA,VA: qword;
|
|
begin
|
|
{$ifdef windows}
|
|
if isRunningDBVM and hasEPTSupport and (not hasCloakedRegionInRange(disassemblerview.SelectedAddress,1,VA,PA)) then
|
|
begin
|
|
VA:=disassemblerview.SelectedAddress;
|
|
|
|
if GetPhysicalAddress(processhandle,pointer(VA),PA) then
|
|
dbvm_cloak_activate(PA,VA)
|
|
else
|
|
MessageDlg('Failed obtaining the physical address of this memory', mtError, [mbok],0);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDBVMDisableCloakClick(Sender: TObject);
|
|
var PA,VA: Qword;
|
|
begin
|
|
{$ifdef windows}
|
|
if isRunningDBVM and hasEPTSupport and (hasCloakedRegionInRange(disassemblerview.SelectedAddress,1,VA,PA)) then
|
|
dbvm_cloak_deactivate(PA);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miHideToolbarClick(Sender: TObject);
|
|
begin
|
|
if tbDebug.Visible=true then HideDebugToolbar;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUltimapClick(Sender: TObject);
|
|
begin
|
|
if frmUltimap=nil then
|
|
frmUltimap:=TfrmUltimap.create(application);
|
|
|
|
frmUltimap.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MenuItem17Click(Sender: TObject);
|
|
begin
|
|
//build a structure using a registered template and the current data stream
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MenuItem18Click(Sender: TObject);
|
|
begin
|
|
TfrmMemoryViewEx.create(self).show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miLoadTraceClick(Sender: TObject);
|
|
var t: Tfrmtracer;
|
|
begin
|
|
t:=TFrmTracer.create(self,false,true);
|
|
|
|
try
|
|
t.miLoad.Click;
|
|
except
|
|
on e: exception do
|
|
begin
|
|
t.free; //not needed anymore
|
|
messagedlg(e.Message, mterror, [mbok],0);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
t.show;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miWatchMemoryPageAccessClick(Sender: TObject);
|
|
begin
|
|
if frmAccessedMemory=nil then
|
|
frmAccessedMemory:=TfrmAccessedMemory.Create(application);
|
|
|
|
frmAccessedMemory.Show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUserWriteIntegerClick(Sender: TObject);
|
|
begin
|
|
if frmEditHistory=nil then
|
|
frmEditHistory:=tfrmEditHistory.create(application);
|
|
|
|
frmEditHistory.show;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUltimap2Click(Sender: TObject);
|
|
begin
|
|
if frmUltimap2=nil then
|
|
frmUltimap2:=TfrmUltimap2.create(application);
|
|
|
|
frmUltimap2.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miWatchListClick(Sender: TObject);
|
|
begin
|
|
if frmWatchlist=nil then
|
|
frmWatchlist:=tfrmWatchlist.create(Application);
|
|
|
|
frmWatchlist.UpdateContext(context);
|
|
frmWatchlist.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miCompareStructuresClick(Sender: TObject);
|
|
begin
|
|
if frmStructureCompare=nil then
|
|
frmStructureCompare:=tfrmStructureCompare.create(application);
|
|
|
|
frmStructureCompare.show;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.miDebugSetAddressClick(Sender: TObject);
|
|
begin
|
|
if (debuggerthread<>nil) and (debuggerthread.isWaitingToContinue) then
|
|
begin
|
|
debuggerthread.CurrentThread.context.{$ifdef cpu32}eip{$else}Rip{$endif}:=disassemblerview.SelectedAddress;
|
|
debuggerthread.CurrentThread.setContext;
|
|
debuggerthread.CurrentThread.UpdateMemoryBrowserContext;
|
|
UpdateDebugContext(debuggerthread.CurrentThread.Handle, debuggerthread.CurrentThread.ThreadId);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miGNUAssemblerClick(Sender: TObject);
|
|
var gnua: TfrmAutoInject;
|
|
begin
|
|
gnua:=TfrmAutoInject.Create(self);
|
|
gnua.ScriptMode:=smGnuAssembler;
|
|
gnua.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miBinutilsSelectClick(Sender: TObject);
|
|
var id: integer;
|
|
begin
|
|
if (sender is TMenuItem) then
|
|
begin
|
|
id:=tmenuitem(sender).tag;
|
|
if (id<0) or (id>=binutilslist.count) then
|
|
begin
|
|
defaultBinutils:=nil;
|
|
miDisassemblerType.Enabled:=true;
|
|
end
|
|
else
|
|
begin
|
|
defaultBinutils:=TBinUtils(binutilslist[id]);
|
|
miDisassemblerType.Enabled:=false;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miRunUnhandledClick(Sender: TObject);
|
|
begin
|
|
if debuggerthread<>nil then
|
|
debuggerthread.continueDebugging(co_run, 0, false);
|
|
|
|
OnMemoryViewerRunning;
|
|
caption:=rsMemoryViewerRunning;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowRelativeClick(Sender: TObject);
|
|
begin
|
|
if miShowRelative.checked then
|
|
begin
|
|
if hexview.HasSelection then
|
|
begin
|
|
hexview.RelativeBase:=hexview.SelectionStart;
|
|
hexview.UseRelativeBase:=true;
|
|
end
|
|
else
|
|
begin
|
|
hexview.RelativeBase:=hexview.TopAddress;
|
|
hexview.UseRelativeBase:=true;
|
|
end;
|
|
end
|
|
else
|
|
hexview.UseRelativeBase:=false;
|
|
|
|
hexview.update;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miSVCopyClick(Sender: TObject);
|
|
var
|
|
i,j: integer;
|
|
s: tstringlist;
|
|
str: string;
|
|
begin
|
|
s:=tstringlist.create;
|
|
try
|
|
|
|
for i:=0 to lvStacktraceData.Items.Count-1 do
|
|
begin
|
|
if lvStacktraceData.Items[i].Selected then
|
|
begin
|
|
str:=PadRight(lvStacktraceData.items[i].caption,20);
|
|
|
|
for j:=0 to lvStacktraceData.items[i].SubItems.Count-1 do
|
|
str:=str+' - '+PadRight(lvStacktraceData.items[i].SubItems[j],20);
|
|
|
|
s.add(str);
|
|
end;
|
|
|
|
end;
|
|
|
|
clipboard.AsText:=s.Text;
|
|
|
|
finally
|
|
s.free;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUnexpectedExceptionBreakOptionClick(Sender: TObject);
|
|
begin
|
|
case TMenuItem(Sender).tag of
|
|
0: UnexpectedExceptionAction:=ueaIgnore;
|
|
1: UnexpectedExceptionAction:=ueaBreak;
|
|
2: UnexpectedExceptionAction:=ueaBreakIfInRegion;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.pmRegistersPopup(Sender: TObject);
|
|
begin
|
|
miFollowInHexview.checked:=(followRegister<>nil) and (pmRegisters.PopupComponent<>nil) and (pmRegisters.PopupComponent.Tag=ptruint(followRegister));
|
|
end;
|
|
|
|
procedure TMemoryBrowser.pmStacktracePopup(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
x: ptruint;
|
|
s: string;
|
|
haserror: boolean=true;
|
|
begin
|
|
if processhandler.is64Bit then
|
|
begin
|
|
miAddESP.Caption:='(rsp+*)';
|
|
miAddEBP.Caption:='(rbp+*)';
|
|
end else
|
|
begin
|
|
miAddESP.Caption:='(esp+*)';
|
|
miAddEBP.Caption:='(ebp+*)';
|
|
end;
|
|
|
|
if lvStacktraceData.Selected<>nil then
|
|
begin
|
|
s:=lvStacktraceData.Selected.Caption;
|
|
i:=pos('(', s);
|
|
if i>0 then
|
|
s:=copy(s,1,i-1);
|
|
|
|
x:=symhandler.getAddressFromName(s,false,haserror);
|
|
|
|
if not haserror then
|
|
miAddRef.caption:=format('(ref+*) Ref will be %x',[x]);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.RegisterViewResize(Sender: TObject);
|
|
begin
|
|
{$ifndef darwin}
|
|
if scrollbox1.VertScrollBar.IsScrollBarVisible then
|
|
sbShowFloats.Left:=scrollbox1.VertScrollBar.ClientSizeWithBar-sbShowFloats.Width
|
|
else
|
|
sbShowFloats.Left:=scrollbox1.VertScrollBar.ClientSizeWithoutBar-sbShowFloats.Width;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miAddRefClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
s: string;
|
|
haserror: boolean=true;
|
|
x: ptruint;
|
|
begin
|
|
if lvStacktraceData.Selected<>nil then
|
|
begin
|
|
s:=lvStacktraceData.Selected.Caption;
|
|
i:=pos('(', s);
|
|
if i>0 then
|
|
s:=copy(s,1,i-1);
|
|
|
|
x:=symhandler.getAddressFromName(s,false,haserror);
|
|
|
|
if not haserror then
|
|
begin
|
|
StackReference:=x;
|
|
reloadStacktrace;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
miAddESP.Checked:=true;
|
|
reloadStacktrace;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miBreakOnExceptionsClick(Sender: TObject);
|
|
var n: TNotifyEvent;
|
|
begin
|
|
miExceptionRegionSeperator.Visible:=UnexpectedExceptionAction in [ueaBreak, ueaBreakIfInRegion];
|
|
miExceptionRegionAutoAddAllocs.Visible:=UnexpectedExceptionAction=ueaBreakIfInRegion;
|
|
miExceptionRegionManageList.Visible:=UnexpectedExceptionAction=ueaBreakIfInRegion;
|
|
miExceptionIgnoreList.visible:=UnexpectedExceptionAction in [ueaBreak, ueaBreakIfInRegion];
|
|
|
|
n:=miExceptionRegionAutoAddAllocs.OnClick;
|
|
miExceptionRegionAutoAddAllocs.OnClick:=nil;
|
|
miExceptionRegionAutoAddAllocs.checked:=allocsAddToUnexpectedExceptionList;
|
|
miExceptionRegionAutoAddAllocs.OnClick:=n;
|
|
|
|
miUnexpectedExceptionBreakNever.checked:=UnexpectedExceptionAction=ueaIgnore;
|
|
miUnexpectedExceptionBreakAlways.checked:=UnexpectedExceptionAction=ueaBreak;
|
|
miUnexpectedExceptionBreakIfInRegion.checked:=UnexpectedExceptionAction=ueaBreakIfInRegion;
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miChangeProtectionClick(Sender: TObject);
|
|
var
|
|
protection: dword;
|
|
oldprotect: dword;
|
|
|
|
l: integer;
|
|
begin
|
|
|
|
case (sender as TMenuItem).Tag of
|
|
0: protection:=PAGE_EXECUTE_READWRITE;
|
|
1: protection:=PAGE_EXECUTE_READ;
|
|
2: protection:=PAGE_READWRITE;
|
|
3: protection:=PAGE_READONLY;
|
|
else
|
|
protection:=PAGE_EXECUTE_READWRITE; //never
|
|
end;
|
|
|
|
l:=max(1, hexview.SelectionStop-hexview.SelectionStart+1);
|
|
|
|
//OutputDebugString(format('start=%d stop=%x l=%d',[hexview.SelectionStart, hexview.SelectionStop, l]));
|
|
|
|
if hexview.HasSelection then
|
|
VirtualProtectEx(processhandle, pointer(hexview.SelectionStart),l,protection, oldprotect)
|
|
else
|
|
VirtualProtectEx(processhandle, pointer(hexview.Address),l,protection, oldprotect)
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miExceptionIgnoreListClick(Sender: TObject);
|
|
begin
|
|
if frmExceptionIgnoreList=nil then
|
|
frmExceptionIgnoreList:=tfrmExceptionIgnoreList.Create(self);
|
|
|
|
frmExceptionIgnoreList.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miExceptionRegionAutoAddAllocsClick(Sender: TObject);
|
|
var n: TNotifyEvent;
|
|
begin
|
|
if frmExceptionRegionList<>nil then
|
|
begin
|
|
n:=frmExceptionRegionList.cbAutoAddAllocs.OnChange;
|
|
frmExceptionRegionList.cbAutoAddAllocs.OnChange:=nil;
|
|
frmExceptionRegionList.cbAutoAddAllocs.Checked:=miExceptionRegionAutoAddAllocs.checked;
|
|
frmExceptionRegionList.cbAutoAddAllocs.OnChange:=n;
|
|
end;
|
|
|
|
allocsAddToUnexpectedExceptionList:=miExceptionRegionAutoAddAllocs.checked;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miExceptionRegionManageListClick(Sender: TObject);
|
|
begin
|
|
if frmExceptionRegionList=nil then
|
|
frmExceptionRegionList:=tfrmExceptionRegionList.Create(self);
|
|
|
|
frmExceptionRegionList.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miHVBackClick(Sender: TObject);
|
|
begin
|
|
hexview.back;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miHVFollowClick(Sender: TObject);
|
|
begin
|
|
hexview.follow;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.SetBookmarkClick(Sender: TObject);
|
|
var
|
|
id: integer;
|
|
begin
|
|
if (sender=nil) or (not (sender is TMenuItem)) then exit;
|
|
id:=TMenuItem(Sender).Tag;
|
|
|
|
if (id<0) or (id>9) then exit;
|
|
|
|
if disassemblerview.SelectedAddress=bookmarks[id].lastAddress then
|
|
begin
|
|
//delete
|
|
bookmarks[id].addressString:='';
|
|
bookmarks[id].lastAddress:=0;
|
|
bookmarks[id].setMi.caption:=format(rsMBBookmark, [id]);
|
|
bookmarks[id].gotoMi.caption:=bookmarks[id].setMi.caption;
|
|
end
|
|
else
|
|
begin
|
|
//update
|
|
bookmarks[id].addressString:=symhandler.getNameFromAddress(disassemblerview.SelectedAddress);
|
|
bookmarks[id].lastAddress:=disassemblerview.SelectedAddress;
|
|
bookmarks[id].setMi.Caption:=format(rsMBBookmark2, [id, bookmarks[id].addressString]);
|
|
bookmarks[id].gotoMi.Caption:=bookmarks[id].setMi.caption;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.GotoBookmarkClick(Sender: TObject);
|
|
var
|
|
err: boolean;
|
|
id: integer;
|
|
newaddress: ptruint;
|
|
s: string;
|
|
begin
|
|
if (sender=nil) or (not (sender is TComponent)) then exit;
|
|
id:=TComponent(Sender).Tag;
|
|
|
|
if (id<0) or (id>9) then exit;
|
|
if bookmarks[id].addressString='' then exit;
|
|
|
|
s:=bookmarks[id].addressString;
|
|
newaddress:=symhandler.getAddressFromName(s, false, err);
|
|
if err then
|
|
newaddress:=bookmarks[id].lastAddress;
|
|
|
|
disassemblerview.SelectedAddress:=newaddress;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.Makepagewritable1Click(Sender: TObject);
|
|
begin
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FormActivate(Sender: TObject);
|
|
begin
|
|
disassemblerview.LastFormActiveEvent:=getTickCount64;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Debug1Click(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miTextEncodingClick(Sender: TObject);
|
|
begin
|
|
if miTextEncodingAscii.checked then
|
|
hexview.CharEncoding:=ceAscii
|
|
else
|
|
if miTextEncodingCodePage.checked then
|
|
hexview.CharEncoding:=ceCodepage
|
|
else
|
|
if miTextEncodingUTF8.checked then
|
|
hexview.CharEncoding:=ceUtf8
|
|
else
|
|
hexview.CharEncoding:=ceUtf16;
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.miCopyBytesOnlyClick(Sender: TObject);
|
|
var start, stop: ptruint;
|
|
l,i: integer;
|
|
x: string;
|
|
x2: ptrUint;
|
|
buf: pbytearray;
|
|
|
|
result: string;
|
|
begin
|
|
//Unrelated to the copy bytes. This indicates the user just wants and AOB
|
|
start:=minX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
stop:=maxX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
|
|
//adjust stop to go AFTER the instruction
|
|
disassemble(stop, x);
|
|
|
|
l:=stop-start;
|
|
|
|
if l<65535 then //not going to do more than that
|
|
begin
|
|
getmem(buf, l);
|
|
try
|
|
if readprocessmemory(processhandle, pointer(start), buf, l, x2) then
|
|
begin
|
|
result:='';
|
|
for i:=0 to l-1 do
|
|
result:=result+inttohex(buf[i],2)+' ';
|
|
|
|
Clipboard.AsText:=copy(result,1,length(result)-1);
|
|
end;
|
|
finally
|
|
freememandnil(buf);
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDissectData2Click(Sender: TObject);
|
|
begin
|
|
if frmStructures2.count>0 then
|
|
begin
|
|
// TfrmStructures2(frmStructures2[0]).edtAddress.Text:=inttohex(memorybrowser.memoryaddress,8);
|
|
TfrmStructures2(frmStructures2[0]).show;
|
|
end
|
|
else
|
|
begin
|
|
//create it
|
|
with tfrmstructures2.create(application) do
|
|
begin
|
|
initialaddress:=memoryaddress;
|
|
show;
|
|
|
|
if initialaddress=0 then //address 0 would normally NOT add a new address, but this is a user specified address, so do it anyhow
|
|
addColumn;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miPointerSpiderClick(Sender: TObject);
|
|
begin
|
|
if frmStringPointerscan=nil then
|
|
frmStringpointerscan:=Tfrmstringpointerscan.create(application);
|
|
|
|
frmStringpointerscan.rbDatascan.Checked:=true;
|
|
frmStringpointerscan.edtBase.text:=inttohex(hexview.address,8);
|
|
|
|
frmStringpointerscan.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miSelectCurrentFunctionClick(Sender: TObject);
|
|
var start,stop: ptrUint;
|
|
pa, a: ptruint;
|
|
|
|
d: TDisassembler;
|
|
s: string;
|
|
infloop: integer;
|
|
begin
|
|
//disassemble the code and find the last address
|
|
// parametervaluetype:=dvtaddress;
|
|
d:=TDisassembler.create;
|
|
try
|
|
start:=disassemblerview.SelectedAddress;
|
|
|
|
|
|
|
|
|
|
//find stop:
|
|
stop:=start;
|
|
a:=stop;
|
|
|
|
infloop:=0;
|
|
while infloop<100000 do
|
|
begin
|
|
inc(infloop);
|
|
|
|
pa:=a;
|
|
d.disassemble(a,s);
|
|
|
|
if (length(d.LastDisassembleData.Bytes)>=2) and (d.LastDisassembleData.Bytes[0]=0) and (d.LastDisassembleData.Bytes[1]=0) then
|
|
begin
|
|
stop:=pa;
|
|
break;
|
|
end;
|
|
|
|
|
|
if (d.LastDisassembleData.opcode='??') or (d.LastDisassembleData.opcode='ret') or (d.LastDisassembleData.opcode='int 3') or (d.LastDisassembleData.opcode='nop') then //found the end
|
|
begin
|
|
stop:=pa;
|
|
break;
|
|
end;
|
|
|
|
if (d.LastDisassembleData.isjump) and (not d.LastDisassembleData.iscall) then
|
|
begin
|
|
//adjust the current address to point
|
|
if d.LastDisassembleData.parameterValueType=dvtAddress then //direct address
|
|
begin
|
|
if isAddress(d.LastDisassembleData.parameterValue) then
|
|
begin
|
|
if d.LastDisassembleData.parameterValue < start then
|
|
begin
|
|
start:=d.LastDisassembleData.parameterValue;
|
|
continue;
|
|
end;
|
|
|
|
if d.LastDisassembleData.parameterValue > pa then
|
|
begin
|
|
stop:=d.LastDisassembleData.parameterValue;
|
|
a:=stop;
|
|
continue;
|
|
end;
|
|
|
|
if (d.LastDisassembleData.parameterValue <= a) and (d.LastDisassembleData.opcode='jmp') then //an unconditonal jump that jumps back and no conditonal jump encountered that went after this. Meaning: Infinite loop
|
|
begin
|
|
stop:=pa;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
//find start
|
|
infloop:=0;
|
|
|
|
pa:=start;
|
|
d.disassemble(pa,s); //start from next one in case it's started from the begin
|
|
|
|
while infloop<100000 do
|
|
begin
|
|
inc(infloop);
|
|
|
|
|
|
a:=previousopcode(pa);
|
|
pa:=a;
|
|
d.disassemble(a,s);
|
|
|
|
//look for 00 , 00 (add [eax],al is an 100% completely useless instruction)
|
|
if (length(d.LastDisassembleData.Bytes)>=2) and (d.LastDisassembleData.Bytes[0]=0) and (d.LastDisassembleData.Bytes[1]=0) then
|
|
begin
|
|
start:=a;
|
|
break;
|
|
end;
|
|
|
|
|
|
//look for ret, int3 or nop
|
|
if (d.LastDisassembleData.opcode='??') or (d.LastDisassembleData.opcode='ret') or (d.LastDisassembleData.opcode='int 3') then
|
|
begin
|
|
start:=a; //start from next instruction
|
|
break;
|
|
end;
|
|
|
|
if processhandler.is64Bit then
|
|
begin
|
|
//looks for sub rsp,xxxx on an address that is dividable by 0x10
|
|
|
|
if (pa mod $10 = 0) and (d.LastDisassembleData.opcode='sub') then
|
|
begin
|
|
if pos('rsp,', lowercase(d.LastDisassembleData.parameters))>0 then
|
|
begin
|
|
start:=pa;
|
|
break;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
//look for push ebp
|
|
if (d.LastDisassembleData.opcode='push') then
|
|
begin
|
|
if lowercase(d.LastDisassembleData.parameters)='ebp' then
|
|
begin
|
|
start:=pa;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
finally
|
|
d.free;
|
|
end;
|
|
|
|
disassemblerview.SelectedAddress:=start;
|
|
disassemblerview.SelectedAddress2:=stop;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDataBreakPointMenuClick(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miWatchAccessClick(Sender: TObject);
|
|
var
|
|
a,a2: ptruint;
|
|
bpm: TBreakpointMethod;
|
|
begin
|
|
try
|
|
if (startdebuggerifneeded(true)) and (hexview.hasSelection) then
|
|
begin
|
|
hexview.GetSelectionRange(a,a2);
|
|
|
|
bpm:=bpmDebugRegister;
|
|
if miWatchBPException.checked then
|
|
bpm:=bpmException
|
|
else
|
|
if miWatchBPDBVM.checked then
|
|
bpm:=bpmDBVM;
|
|
|
|
DebuggerThread.SetOnAccessBreakpoint(a, 1+(a2-a), bpm);
|
|
hexview.Update;
|
|
end;
|
|
except
|
|
on e: exception do
|
|
messagedlg(e.message, mtError, [mbOK], 0);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miWatchWriteClick(Sender: TObject);
|
|
var
|
|
a,a2: ptruint;
|
|
bpm: TBreakpointMethod;
|
|
begin
|
|
try
|
|
if (startdebuggerifneeded(true)) and (hexview.hasSelection) then
|
|
begin
|
|
hexview.GetSelectionRange(a,a2);
|
|
|
|
bpm:=bpmDebugRegister;
|
|
if miWatchBPException.checked then
|
|
bpm:=bpmException
|
|
else
|
|
if miWatchBPDBVM.checked then
|
|
bpm:=bpmDBVM;
|
|
|
|
|
|
DebuggerThread.SetOnWriteBreakpoint(a, 1+(a2-a),bpm);
|
|
hexview.Update;
|
|
end;
|
|
except
|
|
on e: exception do
|
|
messagedlg(e.message, mtError, [mbOK], 0);
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miBreakAndTraceClick(Sender: TObject);
|
|
var
|
|
bpm: TBreakpointMethod;
|
|
begin
|
|
bpm:=bpmDebugRegister;
|
|
if miWatchBPException.checked then
|
|
bpm:=bpmException
|
|
else
|
|
if miWatchBPDBVM.checked then
|
|
bpm:=bpmDBVM;
|
|
|
|
TFrmTracer.createWithBreakpointMethodSet(self,true,false,bpm).show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MenuItem9Click(Sender: TObject);
|
|
var stime: string;
|
|
begin
|
|
stime:=inttostr(hexview.fadetimer);
|
|
if InputQuery(rsHowLongShouldAChangeBeShown, rsChangeDisplayFader, stime) then
|
|
hexview.fadeTimer:=strtoint(stime);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miAddESPClick(Sender: TObject);
|
|
begin
|
|
reloadStacktrace;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.miConditionalBreakClick(Sender: TObject);
|
|
var
|
|
script: string;
|
|
easy: boolean;
|
|
bp: PBreakpoint;
|
|
begin
|
|
bp:=debuggerthread.isBreakpoint(disassemblerview.SelectedAddress);
|
|
if bp<>nil then
|
|
begin
|
|
inc(bp.referencecount);
|
|
try
|
|
with TfrmBreakpointCondition.create(self) do
|
|
begin
|
|
script:=debuggerthread.getbreakpointcondition(bp, easy);
|
|
|
|
if script='' then
|
|
begin
|
|
script:=lastBreakpointCondition.script;
|
|
easy:=lastBreakpointCondition.easy;
|
|
|
|
if script='' then
|
|
easy:=true;
|
|
end;
|
|
|
|
if easy then
|
|
edtEasy.text:=script
|
|
else
|
|
mComplex.text:=script;
|
|
|
|
|
|
|
|
rbEasy.Checked:=easy;
|
|
rbComplex.checked:=not easy;
|
|
|
|
if showmodal=mrok then
|
|
begin
|
|
easy:=rbEasy.checked;
|
|
if easy then
|
|
script:=edtEasy.text
|
|
else
|
|
script:=mComplex.text;
|
|
|
|
lastBreakpointCondition.script:=script;
|
|
lastBreakpointCondition.easy:=easy;
|
|
|
|
debuggerthread.setbreakpointcondition(bp, easy, script);
|
|
end;
|
|
|
|
free;
|
|
end;
|
|
|
|
finally
|
|
dec(bp.referencecount);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDeleteBPClick(Sender: TObject);
|
|
var bp: PBreakpoint;
|
|
a,a2: ptruint;
|
|
begin
|
|
if (debuggerthread<>nil) then
|
|
begin
|
|
hexview.GetSelectionRange(a,a2);
|
|
|
|
debuggerthread.lockbplist;
|
|
try
|
|
repeat
|
|
bp:=debuggerthread.isBreakpoint(a,a2);
|
|
if bp<>nil then
|
|
debuggerthread.RemoveBreakpoint(bp);
|
|
until bp=nil;
|
|
|
|
finally
|
|
debuggerthread.unlockbplist;
|
|
end;
|
|
hexview.update;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miArchChangeClick(Sender: TObject);
|
|
begin
|
|
if miArchAutodetect.checked then
|
|
visibleDisassembler.architecture:=darchAutoDetect
|
|
else
|
|
if miArchX86.checked then
|
|
visibleDisassembler.architecture:=darchX86
|
|
else
|
|
visibleDisassembler.architecture:=darchArm;
|
|
|
|
disassemblerview.Update;
|
|
|
|
if ssCtrl in GetKeyShiftState then
|
|
begin
|
|
case visibleDisassembler.architecture of
|
|
darchX86: processhandler.SystemArchitecture:=archX86;
|
|
darchArm: processhandler.SystemArchitecture:=archArm;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDisassemblyAutodetectClick(Sender: TObject);
|
|
begin
|
|
if miDisassemblyAutodetect.checked then
|
|
visibleDisassembler.is64bitOverride:=false
|
|
else
|
|
if miDisassembly32.checked then
|
|
begin
|
|
visibleDisassembler.is64bitOverride:=true;
|
|
visibleDisassembler.is64bitOverridestate:=false
|
|
end
|
|
else
|
|
begin
|
|
visibleDisassembler.is64bitOverride:=true;
|
|
visibleDisassembler.is64bitOverridestate:=true;
|
|
end;
|
|
|
|
defaultDisassembler.is64bitOverride:=visibleDisassembler.is64bitoverride;
|
|
defaultDisassembler.is64bitOverridestate:=visibleDisassembler.is64bitOverridestate;
|
|
|
|
disassemblerview.update;
|
|
|
|
if ssCtrl in GetKeyShiftState then
|
|
begin
|
|
if miDisassembly32.checked then
|
|
processhandler.is64Bit:=false
|
|
else
|
|
processhandler.is64Bit:=true;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miFindWhatAccessesClick(Sender: TObject);
|
|
var
|
|
a,a2: ptruint;
|
|
bpm: TBreakpointMethod;
|
|
begin
|
|
if (startdebuggerifneeded(true)) and (hexview.hasSelection) then
|
|
begin
|
|
hexview.GetSelectionRange(a,a2);
|
|
|
|
bpm:=bpmDebugRegister;
|
|
if miWatchBPException.checked then
|
|
bpm:=bpmException
|
|
else
|
|
if miWatchBPDBVM.checked then
|
|
bpm:=bpmDBVM;
|
|
|
|
|
|
DebuggerThread.FindWhatAccesses(a,1+(a2-a), bpm);
|
|
hexview.Update;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miFindWhatWritesClick(Sender: TObject);
|
|
var
|
|
a,a2: ptruint;
|
|
bpm: TBreakpointMethod;
|
|
begin
|
|
if (startdebuggerifneeded(true)) and (hexview.hasSelection) then
|
|
begin
|
|
hexview.GetSelectionRange(a,a2);
|
|
|
|
bpm:=bpmDebugRegister;
|
|
if miWatchBPException.checked then
|
|
bpm:=bpmException
|
|
else
|
|
if miWatchBPDBVM.checked then
|
|
bpm:=bpmDBVM;
|
|
|
|
|
|
DebuggerThread.FindWhatWrites(a,1+(a2-a), bpm);
|
|
hexview.Update;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miSepClick(Sender: TObject);
|
|
begin
|
|
hexview.bytesPerSeperator:=TMenuItem(sender).Tag;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowInHexviewClick(Sender: TObject);
|
|
begin
|
|
hexview.address:=PContextElement_register(pmRegisters.PopupComponent.Tag)^.getValue(context);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miTextPreferencesClick(Sender: TObject);
|
|
var
|
|
x: TfrmMemviewPreferences;
|
|
i: TDisassemblerViewColorsState;
|
|
reg: tregistry;
|
|
fd: TFontData;
|
|
begin
|
|
|
|
with TfrmMemviewPreferences.create(self) do
|
|
begin
|
|
fd:=Graphics.GetFontData(disassemblerview.font.handle);
|
|
fontdialog1.font.Name:=fd.Name;
|
|
fontdialog1.font.height:=fd.height;
|
|
fontdialog1.font.Pitch:=fd.Pitch;
|
|
fontdialog1.font.Style:=fd.Style;
|
|
fontdialog1.font.CharSet:=fd.CharSet;
|
|
fontdialog1.font.Quality:=fd.Quality;
|
|
fontdialog1.font.Orientation:=fd.Orientation;
|
|
|
|
btnFont.Caption:=fontdialog1.Font.Name+' '+inttostr(fontdialog1.Font.Size);
|
|
|
|
|
|
|
|
//FontDialog2.Font.Assign(hexview.HexFont);
|
|
fd:=Graphics.GetFontData(hexview.HexFont.handle);
|
|
fontdialog2.font.Name:=fd.Name;
|
|
fontdialog2.font.height:=fd.height;
|
|
fontdialog2.font.Pitch:=fd.Pitch;
|
|
fontdialog2.font.Style:=fd.Style;
|
|
fontdialog2.font.CharSet:=fd.CharSet;
|
|
fontdialog2.font.Quality:=hexview.HexFont.Quality;
|
|
|
|
fontdialog2.font.Orientation:=fd.Orientation;
|
|
cbFontQuality.ItemIndex:=integer(hexview.HexFont.Quality);
|
|
btnHexFont.Caption:=fontdialog2.Font.Name+' '+inttostr(fontdialog2.Font.Size);
|
|
|
|
fd:=Graphics.GetFontData(scrollbox1.Font.Reference.Handle);
|
|
fontdialog3.font.Name:=fd.Name;
|
|
fontdialog3.font.height:=fd.height;
|
|
fontdialog3.font.Pitch:=fd.Pitch;
|
|
fontdialog3.font.Style:=fd.Style;
|
|
fontdialog3.font.CharSet:=fd.CharSet;
|
|
fontdialog3.font.Quality:=scrollbox1.Font.Quality;
|
|
fontdialog3.font.Orientation:=fd.Orientation;
|
|
btnRegisterViewFont.Caption:=fontdialog3.Font.Name+' '+inttostr(fontdialog3.Font.Size);
|
|
|
|
|
|
//set the current colors
|
|
colors:=disassemblerview.colors;
|
|
|
|
//and now apply those colors
|
|
cbColorGroupChange(cbColorGroup);
|
|
|
|
lblCall.font.color:=disassemblerview.jlCallColor;
|
|
lblUnconditionalJump.font.color:=disassemblerview.jlUnconditionalJumpColor;
|
|
lblConditionalJump.font.color:=disassemblerview.jlconditionalJumpColor;
|
|
jlThickness:=disassemblerview.jlThickness;
|
|
jlSpacing:=disassemblerview.jlSpacing;
|
|
spaceAboveLines:=disassemblerview.spaceAboveLines;
|
|
spaceBelowLines:=disassemblerview.spaceBelowLines;
|
|
hexSpaceBetweenLines:=hexview.spaceBetweenLines;
|
|
cbShowStatusBar.checked:=hexview.statusbar.Visible;
|
|
|
|
{$ifdef USELAZFREETYPE}
|
|
cbOriginalRenderingSystem.checked:=UseOriginalRenderingSystem;
|
|
{$endif}
|
|
|
|
cbCenterDisassemblerWhenOutsideView.checked:=disassemblerview.CenterOnAddressChangeOutsideView;
|
|
|
|
|
|
lblHexNormal.font.color:=hexview.normalFontColor;
|
|
lblHexNormal.color:=hexview.normalBackgroundColor;
|
|
lblHexStatic.font.color:=hexview.staticFontColor;
|
|
lblHexStatic.color:=hexview.staticBackgroundColor;
|
|
lblHexHighlighted.font.color:=hexview.highlightedFontColor;
|
|
lblHexHighlighted.color:=hexview.highlightedBackgroundColor;
|
|
lblHexEditing.font.color:=hexview.EditingFontColor;
|
|
lblHexEditing.color:=hexview.EditingBackgroundColor;
|
|
lblHexSecondaryEditing.font.color:=hexview.SecondaryEditingFontColor;
|
|
lblHexSecondaryEditing.color:=hexview.SecondaryEditingBackgroundColor;
|
|
lblHexBreakpoint.font.color:=hexview.BreakpointFontColor;
|
|
lblHexBreakpoint.color:=hexview.BreakpointBackgroundColor;
|
|
lblHexDifferent.font.color:=hexview.DifferentFontColor;
|
|
lblHexDifferent.color:=hexview.DifferentBackgroundColor;
|
|
|
|
lblHexTopLine.Font.color:=hexview.toplinecolor;
|
|
lblHexSeperator.Font.color:=hexview.seperatorColor;
|
|
lblHexCursor.Font.color:=hexview.cursorcolor;
|
|
lblHexFadeColor.font.color:=hexview.normalFontColor;
|
|
lblHexFadeColor.color:=hexview.fadecolor;
|
|
|
|
lblRegHighLightChange.color:=fChangedRegisterColor;
|
|
lblRegHighLightAccess.color:=fAccessedRegisterColor;
|
|
|
|
|
|
|
|
if showmodal=mrok then
|
|
begin
|
|
//set the colors and save to registry
|
|
{$ifdef USELAZFREETYPE}
|
|
UseOriginalRenderingSystem:=cbOriginalRenderingSystem.checked;
|
|
{$endif}
|
|
disassemblerview.Font.assign(fontdialog1.Font);
|
|
disassemblerview.Font.style:=[];
|
|
disassemblerview.colors:=colors;
|
|
disassemblerview.jlCallColor:=lblCall.font.color;
|
|
disassemblerview.jlUnconditionalJumpColor:=lblUnconditionalJump.font.color;
|
|
disassemblerview.jlconditionalJumpColor:=lblConditionalJump.font.color;
|
|
disassemblerview.spaceAboveLines:=spaceAboveLines;
|
|
disassemblerview.spaceBelowLines:=spaceBelowLines;
|
|
|
|
disassemblerview.jlThickness:=jlThickness;
|
|
disassemblerview.jlSpacing:=jlSpacing;
|
|
|
|
disassemblerview.CenterOnAddressChangeOutsideView:=cbCenterDisassemblerWhenOutsideView.checked;
|
|
|
|
|
|
|
|
hexview.HexFont:=fontdialog2.Font;
|
|
|
|
hexview.normalFontColor:=lblHexNormal.font.color;
|
|
hexview.normalBackgroundColor:=lblHexNormal.color;
|
|
hexview.staticFontColor:=lblHexStatic.font.color;
|
|
hexview.staticBackgroundColor:=lblHexStatic.color;
|
|
hexview.highlightedFontColor:=lblHexHighlighted.font.color;
|
|
hexview.highlightedBackgroundColor:=lblHexHighlighted.color;
|
|
hexview.EditingFontColor:= lblHexEditing.font.color;
|
|
hexview.EditingBackgroundColor:=lblHexEditing.color;
|
|
hexview.SecondaryEditingFontColor:= lblHexSecondaryEditing.font.color;
|
|
hexview.SecondaryEditingBackgroundColor:=lblHexSecondaryEditing.color;
|
|
hexview.BreakpointFontColor:= lblHexBreakpoint.font.color;
|
|
hexview.BreakpointBackgroundColor:=lblHexBreakpoint.color;
|
|
hexview.DifferentFontColor:=lblHexDifferent.font.color;
|
|
hexview.DifferentBackgroundColor:=lblHexDifferent.color;
|
|
|
|
hexview.toplinecolor:=lblHexTopLine.Font.color;
|
|
hexview.seperatorColor:=lblHexSeperator.Font.color;
|
|
hexview.cursorcolor:=lblHexCursor.Font.color;
|
|
hexview.fadecolor:=lblHexFadeColor.color;
|
|
|
|
fChangedRegisterColor:=lblRegHighLightChange.color;
|
|
fAccessedRegisterColor:=lblRegHighLightAccess.color;
|
|
|
|
|
|
hexview.spaceBetweenLines:=hexSpaceBetweenLines;
|
|
hexview.statusbar.Visible:=cbShowStatusBar.checked;
|
|
hexview.OnResize(hexview);
|
|
|
|
scrollbox1.Font:=fontdialog3.font;
|
|
setRegisterPanelFont(fontdialog3.font);
|
|
|
|
|
|
|
|
free;
|
|
end
|
|
else
|
|
begin
|
|
free;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
disassemblerview.reinitialize;
|
|
|
|
//save to the registry
|
|
{$ifdef USELAZFREETYPE}
|
|
cereg.writeBool('OriginalRenderingSystem', UseOriginalRenderingSystem);
|
|
{$endif}
|
|
|
|
reg:=Tregistry.Create;
|
|
try
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Disassemblerview '+inttostr(screen.PixelsPerInch)+darkmodestring+'\',true) then
|
|
begin
|
|
reg.{$ifdef windows}WriteBinaryData{$else}WriteString{$endif}('colors', {$ifndef windows}bintohexs({$endif}disassemblerview.colors, sizeof(disassemblerview.colors)){$ifndef windows}){$endif};
|
|
|
|
reg.WriteInteger('AccessedRegisterColor', integer(fAccessedRegisterColor));
|
|
reg.WriteInteger('ChangedRegisterColor', integer(fChangedRegisterColor));
|
|
|
|
reg.WriteInteger('jlCallColor', integer(disassemblerview.jlCallColor));
|
|
reg.WriteInteger('jlUnconditionalJumpColor', integer(disassemblerview.jlUnconditionalJumpColor));
|
|
reg.WriteInteger('jlConditionalJumpColor', integer(disassemblerview.jlconditionalJumpColor));
|
|
|
|
reg.writeInteger('spaceAboveLines', disassemblerview.SpaceAboveLines);
|
|
reg.writeInteger('spaceBelowLines', disassemblerview.SpaceBelowLines);
|
|
reg.writeInteger('jlThickness', disassemblerview.jlThickness);
|
|
reg.writeInteger('jlSpacing', disassemblerview.jlSpacing);
|
|
|
|
|
|
reg.WriteBool('CenterOnAddressChangeOutsideView', disassemblerview.CenterOnAddressChangeOutsideView);
|
|
end;
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Disassemblerview '+inttostr(screen.PixelsPerInch)+'\Font'+darkmodestring,true) then
|
|
SaveFontToRegistry(disassemblerview.font, reg);
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Hexview '+inttostr(screen.PixelsPerInch),true) then
|
|
begin
|
|
reg.writeInteger('spaceBetweenLines', hexview.spaceBetweenLines);
|
|
reg.WriteBool('showStatusBar', hexview.statusbar.Visible);
|
|
end;
|
|
|
|
if reg.openkey('\Software\'+strCheatEngine+'\Hexview'+darkmodestring,true) then
|
|
begin
|
|
reg.{$ifdef windows}WriteBinaryData{$else}WriteString{$endif}('colors', {$ifndef windows}bintohexs({$endif}hexview.colors, sizeof(hexview.colors)){$ifndef windows}){$endif};
|
|
reg.WriteInteger('SeperaterColor', hexview.fseperatorColor);
|
|
reg.WriteInteger('CursorColor', hexview.fcursorcolor);
|
|
reg.WriteInteger('TopLineColor', hexview.ftoplinecolor);
|
|
reg.WriteInteger('FadeColor', hexview.ffadeColor);
|
|
end;
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Hexview '+inttostr(screen.PixelsPerInch)+'\Font'+darkmodestring,true) then
|
|
SaveFontToRegistry(hexview.hexfont, reg);
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\RegisterView '+inttostr(screen.PixelsPerInch)+'\Font'+darkmodestring,true) then
|
|
SaveFontToRegistry(scrollbox1.Font, reg);
|
|
|
|
finally
|
|
reg.free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FormShow(Sender: TObject);
|
|
var
|
|
w: integer;
|
|
addressSize: integer;
|
|
byteSize: integer;
|
|
opcodeSize: integer;
|
|
|
|
lineheight: integer;
|
|
begin
|
|
registerpanelfont.assign(scrollbox1.Font);
|
|
|
|
|
|
if posloadedfromreg=false then
|
|
begin
|
|
autosize:=false;
|
|
w:=0;
|
|
addressSize:=canvas.TextWidth('XXXXXXXXXXXXXXXX '); //address
|
|
byteSize:=canvas.TextWidth('XX XX XX XX XX XX XX XX '); ///bytes
|
|
opcodeSize:=canvas.TextWidth('XXXX XXX,[XXXXXXXXXXXXXXXX+XXX*X] ');
|
|
disassemblerview.setheaderWidth(0,addressSize);
|
|
disassemblerview.setheaderWidth(1,byteSize);
|
|
disassemblerview.setheaderWidth(2,opcodeSize);
|
|
|
|
lineheight:=canvas.TextHeight('jxZyYqQ');
|
|
|
|
|
|
width:=max(mainform.width, addressSize+byteSize+opcodeSize+2*addressSize);
|
|
height:=ScaleY(600,96);
|
|
|
|
panel1.height:= clientheight div 2;
|
|
|
|
disassemblerview.setheaderWidth(3,max(32,disassemblerview.width-(disassemblerview.getheaderWidth(0)+disassemblerview.getheaderWidth(1)+disassemblerview.getheaderWidth(2))-32));
|
|
|
|
position:=poDesigned;
|
|
position:=poScreenCenter;
|
|
|
|
posloadedfromreg:=true;
|
|
end;
|
|
|
|
if disassemblerview<>nil then
|
|
disassemblerview.Update;
|
|
|
|
|
|
Sericedescriptortable1.visible:=not Is64bitOS;
|
|
GDTlist1.Visible:=not is64bitos;
|
|
IDTlist1.Visible:=not is64bitos;
|
|
|
|
scrollbox1.Font.Height:=GetFontData(font.handle).height;
|
|
if scrollbox1.Font.Height>-13 then
|
|
scrollbox1.Font.Height:=-13;
|
|
|
|
if hexview<>nil then
|
|
hexview.statusbar.Height:=Canvas.TextHeight('BLAy9qrSTt')+3+hexview.statusbar.BorderWidth;
|
|
|
|
if adjustedsize=false then
|
|
begin
|
|
tbDebug.ButtonHeight:=scaley(tbDebug.ButtonHeight, DesignTimePPI);
|
|
|
|
//tbDebug.ButtonHeight:=trunc(tbDebug.ButtonHeight*fontmultiplication);
|
|
////dpihelper.AdjustToolbar(tbDebug);
|
|
|
|
adjustedsize:=true;
|
|
end;
|
|
|
|
{$ifdef darwin}
|
|
//need to adjust the formsize to trigger a repaint
|
|
BoundsRect:=BoundsRect;
|
|
{$endif}
|
|
|
|
HasBeenShown:=true;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.disassemblerviewDblClick(Sender: TObject);
|
|
var m: TPoint;
|
|
a: ptruint;
|
|
lni: PLineNumberInfo;
|
|
f: TfrmSourceDisplay;
|
|
begin
|
|
//find what column is clicked
|
|
|
|
m:=disassemblerview.ScreenToClient(mouse.cursorpos);
|
|
|
|
a:=disassemblerview.getReferencedByLineAtPos(m);
|
|
if a<>0 then
|
|
begin
|
|
disassemblerview.SelectedAddress:=a;
|
|
exit;
|
|
end;
|
|
|
|
lni:=disassemblerview.getSourceCodeAtPos(m);
|
|
if lni<>nil then
|
|
begin
|
|
f:=getSourceViewForm(lni);
|
|
if f<>nil then
|
|
f.show();
|
|
exit;
|
|
end;
|
|
|
|
if m.x>(disassemblerview.getheaderWidth(0)+disassemblerview.getheaderWidth(1)+disassemblerview.getheaderWidth(2)) then
|
|
begin
|
|
miUserdefinedComment.click; //comment click
|
|
exit;
|
|
end;
|
|
|
|
assemble1.Click;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FormCreate(Sender: TObject);
|
|
var x: array of integer;
|
|
reg: tregistry;
|
|
f: TFont;
|
|
i: integer;
|
|
c: tcolor;
|
|
begin
|
|
|
|
|
|
registerpanelfont:=tfont.Create;
|
|
|
|
MemoryBrowsers.Add(self);
|
|
|
|
bookmarks[0].setMi:=miSetBookmark0;
|
|
bookmarks[1].setMi:=miSetBookmark1;
|
|
bookmarks[2].setMi:=miSetBookmark2;
|
|
bookmarks[3].setMi:=miSetBookmark3;
|
|
bookmarks[4].setMi:=miSetBookmark4;
|
|
bookmarks[5].setMi:=miSetBookmark5;
|
|
bookmarks[6].setMi:=miSetBookmark6;
|
|
bookmarks[7].setMi:=miSetBookmark7;
|
|
bookmarks[8].setMi:=miSetBookmark8;
|
|
bookmarks[9].setMi:=miSetBookmark9;
|
|
|
|
bookmarks[0].gotoMi:=miGotoBookmark0;
|
|
bookmarks[1].gotoMi:=miGotoBookmark1;
|
|
bookmarks[2].gotoMi:=miGotoBookmark2;
|
|
bookmarks[3].gotoMi:=miGotoBookmark3;
|
|
bookmarks[4].gotoMi:=miGotoBookmark4;
|
|
bookmarks[5].gotoMi:=miGotoBookmark5;
|
|
bookmarks[6].gotoMi:=miGotoBookmark6;
|
|
bookmarks[7].gotoMi:=miGotoBookmark7;
|
|
bookmarks[8].gotoMi:=miGotoBookmark8;
|
|
bookmarks[9].gotoMi:=miGotoBookmark9;
|
|
|
|
|
|
scrollbox1.Font:=mainform.font;
|
|
scrollbox1.Font.name:='Courier New';
|
|
scrollbox1.Font.Size:=13;
|
|
|
|
|
|
displaytype:=dtByte;
|
|
|
|
strace:=tstringlist.create;
|
|
|
|
disassembler:=true;
|
|
|
|
disassemblerview:=TDisassemblerview.Create(self);
|
|
disassemblerview.font:=mainform.font;
|
|
disassemblerview.Align:=alClient;
|
|
disassemblerview.Parent:=panel5;
|
|
disassemblerview.PopupMenu:=debuggerpopup;
|
|
disassemblerview.OnKeyDown:=FControl1keydown;
|
|
disassemblerview.OnDblClick:=disassemblerviewDblClick;
|
|
disassemblerview.TopAddress:=$00400000;
|
|
disassemblerview.name:='DisassemblerView';
|
|
|
|
if GetFontData(disassemblerview.font.handle).height>-13 then
|
|
disassemblerview.font.height:=-13;
|
|
|
|
hexview:=THexview.create(self);
|
|
hexview.Align:=alClient;
|
|
hexview.parent:=panel3;
|
|
hexview.popupmenu:=memorypopup;
|
|
|
|
hexview.OnKeyDown:=hexviewKeyDown;
|
|
hexview.Name:='HexadecimalView';
|
|
|
|
|
|
|
|
//load from the registry
|
|
{$ifdef USELAZFREETYPE};
|
|
UseOriginalRenderingSystem:=cereg.readBool('OriginalRenderingSystem');
|
|
{$endif}
|
|
|
|
f:=TFont.create;
|
|
reg:=Tregistry.Create;
|
|
try
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Disassemblerview '+inttostr(screen.PixelsPerInch)+'\Font'+darkmodestring,false) then
|
|
begin
|
|
LoadFontFromRegistry(f, reg);
|
|
disassemblerview.font:=f;
|
|
end;
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Disassemblerview '+inttostr(screen.PixelsPerInch)+darkmodestring+'\',false) then
|
|
begin
|
|
if reg.ValueExists('colors') then
|
|
begin
|
|
{$ifdef windows}
|
|
reg.ReadBinaryData('colors', disassemblerview.colors, sizeof(disassemblerview.colors));
|
|
{$else}
|
|
HexToBin(pchar(reg.ReadString('colors')),pchar(@disassemblerview.colors),sizeof(disassemblerview.colors));
|
|
{$endif}
|
|
end;
|
|
|
|
|
|
if reg.ValueExists('AccessedRegisterColor') then
|
|
fAccessedRegisterColor:=tcolor(reg.ReadInteger('AccessedRegisterColor'));
|
|
|
|
if reg.ValueExists('ChangedRegisterColor') then
|
|
fChangedRegisterColor:=tcolor(reg.ReadInteger('ChangedRegisterColor'));
|
|
|
|
if reg.ValueExists('jlCallColor') then
|
|
disassemblerview.jlCallColor:=tcolor(reg.ReadInteger('jlCallColor'));
|
|
|
|
if reg.ValueExists('jlUnconditionalJumpColor') then
|
|
disassemblerview.jlUnconditionalJumpColor:=tcolor(reg.ReadInteger('jlUnconditionalJumpColor'));
|
|
|
|
if reg.ValueExists('jlConditionalJumpColor') then
|
|
disassemblerview.jlConditionalJumpColor:=tcolor(reg.ReadInteger('jlConditionalJumpColor'));
|
|
|
|
if reg.ValueExists('spaceAboveLines') then
|
|
disassemblerview.spaceAboveLines:=reg.ReadInteger('spaceAboveLines');
|
|
|
|
if reg.ValueExists('spaceBelowLines') then
|
|
disassemblerview.spaceBelowLines:=reg.ReadInteger('spaceBelowLines');
|
|
|
|
if reg.ValueExists('jlThickness') then
|
|
disassemblerview.jlThickness:=reg.ReadInteger('jlThickness');
|
|
|
|
if reg.ValueExists('jlSpacing') then
|
|
disassemblerview.jlSpacing:=reg.ReadInteger('jlSpacing');
|
|
|
|
if reg.ValueExists('CenterOnAddressChangeOutsideView') then
|
|
disassemblerview.CenterOnAddressChangeOutsideView:=reg.ReadBool('CenterOnAddressChangeOutsideView');
|
|
|
|
disassemblerview.reinitialize;
|
|
end;
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Hexview '+inttostr(screen.PixelsPerInch),false) then
|
|
begin
|
|
if reg.ValueExists('spaceBetweenLines') then
|
|
hexview.spaceBetweenLines:=reg.ReadInteger('spaceBetweenLines');
|
|
|
|
if reg.ValueExists('showStatusBar') then
|
|
hexview.statusbar.Visible:=reg.ReadBool('showStatusBar');
|
|
|
|
end;
|
|
|
|
if reg.openkey('\Software\'+strCheatEngine+'\Hexview'+darkmodestring,true) then
|
|
begin
|
|
if reg.ValueExists('colors') then
|
|
begin
|
|
{$ifdef windows}
|
|
reg.ReadBinaryData('colors', hexview.colors, sizeof(hexview.colors));
|
|
{$else}
|
|
HexToBin(pchar(reg.ReadString('colors')),pchar(@hexview.colors),sizeof(hexview.colors));
|
|
{$endif}
|
|
end;
|
|
|
|
if reg.ValueExists('SeperaterColor') then hexview.fseperatorColor:=reg.ReadInteger('SeperaterColor');
|
|
if reg.ValueExists('CursorColor') then hexview.fcursorcolor:=reg.ReadInteger('CursorColor');
|
|
if reg.ValueExists('TopLineColor') then hexview.ftoplinecolor:=reg.ReadInteger('TopLineColor');
|
|
if reg.ValueExists('FadeColor') then hexview.ffadeColor:=reg.ReadInteger('FadeColor');
|
|
end;
|
|
|
|
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\Hexview '+inttostr(screen.PixelsPerInch)+'\Font'+darkmodestring,false) then
|
|
begin
|
|
LoadFontFromRegistry(f, reg);
|
|
hexview.hexfont:=f;
|
|
end;
|
|
|
|
if reg.OpenKey('\Software\'+strCheatEngine+'\RegisterView '+inttostr(screen.PixelsPerInch)+'\Font'+darkmodestring,false) then
|
|
begin
|
|
LoadFontFromRegistry(f, reg);
|
|
// scrollbox1.Font:=f;
|
|
|
|
setRegisterPanelFont(f);
|
|
end
|
|
else
|
|
begin
|
|
f.assign(scrollbox1.font);
|
|
f.size:=12;
|
|
setRegisterPanelFont(f);
|
|
end;
|
|
|
|
|
|
finally
|
|
f.free;
|
|
reg.free;
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memoryaddress:=$00400000;
|
|
memorylabelcount:=0;
|
|
|
|
Highlightcolor:=clHighlight;
|
|
|
|
disassemblerHistory:=TStringList.create;
|
|
memorybrowserHistory:=TStringList.create;
|
|
assemblerHistory:=TStringList.create;
|
|
|
|
showvalues:=true;
|
|
sbShowFloats.left:=scrollbox1.Clientwidth-sbShowFloats.width;
|
|
|
|
FStacktraceSize:=4096;
|
|
|
|
|
|
|
|
setlength(x, 0);
|
|
|
|
if loadformposition(self,x) then
|
|
begin
|
|
disassemblerview.setheaderWidth(0,x[0]);
|
|
disassemblerview.setheaderWidth(1,x[1]);
|
|
disassemblerview.setheaderWidth(2,x[2]);
|
|
disassemblerview.setheaderWidth(3,x[3]);
|
|
|
|
if length(x)>=6 then
|
|
begin
|
|
panel1.height:=x[4];
|
|
registerview.width:=x[5];
|
|
end;
|
|
|
|
if length(x)>=8 then
|
|
begin
|
|
miShowSymbols.checked:=x[6]=1;
|
|
miShowModuleAddresses.checked:=(x[7] and 1)=1;
|
|
miShowSectionAddresses.checked:=(x[7] and 2)=2;
|
|
|
|
|
|
symhandler.showsymbols:=miShowSymbols.Checked;
|
|
symhandler.showmodules:=miShowModuleAddresses.Checked;
|
|
symhandler.showsections:=miShowSectionAddresses.checked;
|
|
end;
|
|
|
|
if length(x)>=10 then
|
|
begin
|
|
if x[9]<>0 then
|
|
hexview.LockedRowSize:=x[9];
|
|
end;
|
|
|
|
if length(x)>=11 then
|
|
begin
|
|
miKernelmodeSymbols.checked:=x[10]=1;
|
|
symhandler.kernelsymbols:=miKernelmodeSymbols.Checked;
|
|
end;
|
|
|
|
if length(x)>=12 then
|
|
pnlStacktrace.Width:=x[11];
|
|
|
|
setlength(x,0);
|
|
posloadedfromreg:=true;
|
|
end;
|
|
|
|
|
|
scrollbox1.OnVScroll:=Scrollboxscroll;
|
|
|
|
disassemblerview.reinitialize;
|
|
followRegister:=nil;
|
|
|
|
{$ifdef darwin}
|
|
InjectDLL1.Caption:=rsInjectDYLIB;
|
|
miChangeProtectionRWE.enabled:=false; //impossible to set , execute can not go together with write
|
|
miChangeProtectionRWE.visible:=false;
|
|
{$endif}
|
|
|
|
if ShouldAppsUseDarkMode() then
|
|
begin
|
|
fAccessedRegisterColor:=clBlue;
|
|
fChangedRegisterColor:=clred;
|
|
end
|
|
else
|
|
begin
|
|
fAccessedRegisterColor:=clAqua;
|
|
fChangedRegisterColor:=clred;
|
|
end;
|
|
|
|
lblRegisters.font.color:=clWindowtext;
|
|
sRegisters.pen.color:=clWindowtext;
|
|
|
|
lblFlags.font.color:=clWindowtext;
|
|
sFlags.pen.color:=clWindowtext;
|
|
|
|
lblSpecial.font.color:=clWindowtext;
|
|
sSpecial.Pen.color:=clWindowtext;
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Scrollboxscroll(sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Goto1Click(Sender: TObject);
|
|
var newaddress: string;
|
|
canceled: boolean;
|
|
old: ptruint;
|
|
begin
|
|
old:=hexview.SelectionStart;
|
|
if old=0 then old:=memoryaddress;
|
|
|
|
newaddress:=inputboxtop(rsGotoAddress, rsFillInTheAddressYouWantToGoTo, IntTohex(old, 8), true, canceled, memorybrowserHistory);
|
|
|
|
if(canceled)then
|
|
exit;
|
|
|
|
try
|
|
hexview.address:=getaddress(newaddress);
|
|
except
|
|
try
|
|
hexview.address:=symhandler.getAddressFromName(newaddress);
|
|
except
|
|
on e: exception do
|
|
begin
|
|
MessageDlg(e.message, mtError,[mbok],0);
|
|
exit;
|
|
end
|
|
end;
|
|
end;
|
|
|
|
if old<>hexview.address then
|
|
hexview.history.Push(pointer(old));
|
|
|
|
hexview.SetFocus;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FormResize(Sender: TObject);
|
|
begin
|
|
|
|
if disassemblerview<>nil then
|
|
disassemblerview.Update;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Splitter2Moved(Sender: TObject);
|
|
begin
|
|
//caption:=inttostr(registerview.width);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Timer2Timer(Sender: TObject);
|
|
var
|
|
mm: TMemoryManager;
|
|
h: THeapStatus;
|
|
rollover: integer;
|
|
timetaken: qword;
|
|
before, after,diff: int64;
|
|
begin
|
|
if Visible then
|
|
begin
|
|
try
|
|
GetMemoryManager(mm);
|
|
|
|
timetaken:=GetTickCount64;
|
|
|
|
|
|
if hexview<>nil then
|
|
begin
|
|
//before:=mm.GetHeapStatus().TotalAllocated;
|
|
hexview.update;
|
|
// after:=mm.GetHeapStatus().TotalAllocated;
|
|
// diff:=after-before;
|
|
// outputdebugstring(gettickcount64.tostring+':hexview.update: before='+before.ToHexString(1)+' after='+after.ToHexString(1)+' diff='+diff.tostring);
|
|
|
|
end;
|
|
|
|
|
|
if disassemblerview<>nil then
|
|
begin
|
|
// before:=mm.GetHeapStatus().TotalAllocated;
|
|
disassemblerview.Update;
|
|
// after:=mm.GetHeapStatus().TotalAllocated;
|
|
// diff:=after-before;
|
|
// outputdebugstring(gettickcount64.tostring+':disassemblerview.update: before='+before.ToHexString(1)+' after='+after.ToHexString(1)+' diff='+diff.tostring);
|
|
|
|
end;
|
|
|
|
//refresh the modulelist
|
|
if processhandler.isNetwork then
|
|
rollover:=250
|
|
else
|
|
rollover:=50;
|
|
|
|
lastmodulelistupdate:=(lastmodulelistupdate+1) mod rollover;
|
|
if lastmodulelistupdate=0 then
|
|
if symhandler<>nil then
|
|
begin
|
|
//before:=mm.GetHeapStatus().TotalAllocated;
|
|
symhandler.loadmodulelist;
|
|
//after:=mm.GetHeapStatus().TotalAllocated;
|
|
//diff:=after-before;
|
|
//outputdebugstring(gettickcount64.tostring+':symhandler.loadmodulelist: before='+before.ToHexString(1)+' after='+after.ToHexString(1)+' diff='+diff.tostring);
|
|
end;
|
|
|
|
timetaken:=GetTickCount64-timetaken;
|
|
if (timetaken>timer2.interval) and (timer2.interval<5000) then
|
|
begin
|
|
timer2.enabled:=false;
|
|
timer2.interval:=timer2.interval+100; //this system can't handle the current speed
|
|
timer2.enabled:=true;
|
|
end;
|
|
|
|
if (timetaken<timer2.interval) and (timer2.Interval>200) then
|
|
timer2.interval:=max(250,timer2.interval-100);
|
|
|
|
except
|
|
on e:exception do
|
|
begin
|
|
outputdebugstring('memorybrowser timer2 error: '+e.message);
|
|
timer2.enabled:=false;
|
|
MessageDlg('Error in memview update timer:'+e.message, mtError,[mbok],0);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miReplacewithnopsClick(Sender: TObject);
|
|
var codelength: dword;
|
|
written: dword;
|
|
bla:string;
|
|
i,j: integer;
|
|
nops: array of byte;
|
|
a,a2: ptrUint;
|
|
original: dword;
|
|
|
|
mbi : _MEMORY_BASIC_INFORMATION;
|
|
//set the protectionlabel
|
|
e: boolean;
|
|
begin
|
|
a:=disassemblerview.SelectedAddress;
|
|
|
|
for i:=0 to AdvancedOptions.count-1 do
|
|
begin
|
|
if AdvancedOptions.code[i]<>nil then
|
|
begin
|
|
a2:=symhandler.getAddressFromName(AdvancedOptions.code[i].symbolname,false,e);
|
|
if not e then
|
|
begin
|
|
if InRangeX(disassemblerview.SelectedAddress, a2, a2+length(AdvancedOptions.code[i].actualopcode)-1 ) then
|
|
begin
|
|
for j:=0 to AdvancedOptions.count-1 do
|
|
AdvancedOptions.Selected[j]:=false;
|
|
|
|
AdvancedOptions.Selected[i]:=true;
|
|
AdvancedOptions.lvCodelist.ItemIndex:=i;
|
|
|
|
if AdvancedOptions.code[i].changed then
|
|
AdvancedOptions.miRestoreWithOriginal.OnClick(AdvancedOptions.miRestoreWithOriginal)
|
|
else
|
|
AdvancedOptions.miReplaceWithNops.onclick(AdvancedOptions.miReplaceWithNops);
|
|
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
//still here so add it to the codelist
|
|
|
|
disassemble(a,bla);
|
|
codelength:=a-disassemblerview.SelectedAddress;
|
|
|
|
if advancedoptions.AddToCodeList(disassemblerview.SelectedAddress,codelength,true) then
|
|
begin
|
|
setlength(nops,codelength);
|
|
for i:=0 to codelength-1 do
|
|
nops[i]:=$90; // $90=nop
|
|
|
|
zeromemory(@mbi,sizeof(mbi));
|
|
Virtualqueryex(processhandle,pointer(disassemblerview.SelectedAddress),mbi,sizeof(mbi));
|
|
|
|
// get old security and set new security (not needed in win9x but nt doesnt even allow writeprocessmemory to do this
|
|
original:=0;
|
|
|
|
RewriteCode(processhandle,disassemblerview.SelectedAddress,@nops[0],codelength);
|
|
hexview.update;
|
|
disassemblerview.Update;;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.hexviewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
var a: qword;
|
|
psize: integer;
|
|
gotoaddress: qword;
|
|
x: ptruint;
|
|
begin
|
|
if shift=[ssCtrl] then
|
|
begin
|
|
case key of
|
|
vk_space: //ctrl+space
|
|
begin
|
|
if hexview.HasSelection then
|
|
begin
|
|
psize:=1+hexview.SelectionStop-hexview.selectionstart;
|
|
if psize>=4 then
|
|
begin
|
|
key:=0;
|
|
if psize>8 then psize:=8;
|
|
|
|
if ReadProcessMemory(processhandle, pointer(hexview.SelectionStart), @gotoaddress, processhandler.pointersize,x) then
|
|
disassemblerview.SelectedAddress:=gotoaddress;
|
|
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
disassemblerview.SelectedAddress:=memoryaddress;
|
|
key:=0;
|
|
end;
|
|
|
|
ord('G'):
|
|
begin
|
|
goto1.click; //ctrl+g
|
|
key:=0;
|
|
end;
|
|
|
|
ord('C'):
|
|
begin
|
|
Cut1.OnClick(Cut1); //ctrl+c
|
|
key:=0;
|
|
end;
|
|
|
|
ord('V'):
|
|
begin
|
|
Pastefromclipboard1.OnClick(Pastefromclipboard1); //ctrl+v
|
|
key:=0;
|
|
end;
|
|
|
|
ord('F'):
|
|
begin
|
|
search1.OnClick(self);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if shift=[] then
|
|
begin
|
|
if key=vk_f3 then
|
|
begin
|
|
if findwindow<>nil then //easy way to find out if there was a scan before
|
|
begin
|
|
findwindow.editStart.Text:=inttohex(memoryaddress+1,8);
|
|
findwindow.firstscan:=false;
|
|
findwindow.btnOK.Click;
|
|
end else
|
|
begin
|
|
search1.OnClick(self);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
//key control for the disassembler
|
|
procedure TMemoryBrowser.FControl1KeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var rct: trect;
|
|
ignore: string;
|
|
i: integer;
|
|
|
|
a,b: ptrUint;
|
|
begin
|
|
//if shift is not pressed and it's a up,down,left or right, then disable multiline section
|
|
case key of
|
|
vk_delete:
|
|
miReplacewithnops.Click;
|
|
|
|
|
|
vk_return:
|
|
begin
|
|
//assembler input
|
|
if shift = [] then
|
|
assemble1.Click;
|
|
end;
|
|
|
|
vk_space:
|
|
begin
|
|
key:=0;
|
|
if shift=[] then
|
|
follow1.Click
|
|
else
|
|
if shift = [ssShift] then
|
|
back1.click
|
|
else
|
|
if shift = [ssCtrl] then
|
|
memoryaddress:=disassemblerview.SelectedAddress;
|
|
end;
|
|
|
|
VK_BACK:
|
|
begin
|
|
key:=0;
|
|
back1.click; //backspace and shift+space
|
|
end;
|
|
|
|
ORD('A')..ORD('Z') , ORD('0')..ORD('9'):
|
|
begin
|
|
if key=ORD('C') then
|
|
begin
|
|
if shift = [ssCtrl] then //ctrl C
|
|
begin
|
|
|
|
//open the copy window asking what exactly to copy
|
|
with tfrmSavedisassembly.create(self) do
|
|
begin
|
|
a:=minX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
b:=maxX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
|
|
|
|
disassemble(b); //b gets increased with size of selected instruction
|
|
edit1.Text:=inttohex(a,8);
|
|
edit2.Text:=inttohex(b-1,8);
|
|
copymode:=true;
|
|
showmodal;
|
|
free;
|
|
exit;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
if key=ORD('G') then
|
|
begin
|
|
if ssCtrl in shift then
|
|
begin
|
|
gotoaddress1.Click;
|
|
disassemblerview.Update;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if (key=ORD('Z')) and (ssCtrl in shift) then
|
|
undoLastWrite;
|
|
|
|
if (ssalt in shift) or (ssctrl in shift) then exit;
|
|
|
|
try
|
|
assemblepopup(lowercase(chr(key)));
|
|
except
|
|
on e:exception do
|
|
begin
|
|
MessageDlg(e.message, mtError,[mbok],0);
|
|
exit;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
disassemblerview.Update;
|
|
|
|
//key:=0;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FControl1KeyPress(Sender: TObject; var Key: Char);
|
|
begin
|
|
//key:=chr(0);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Gotoaddress1Click(Sender: TObject);
|
|
var newaddress: string;
|
|
oldoptions: dword;
|
|
canceled: boolean;
|
|
oldAddress: ptrUint;
|
|
begin
|
|
newaddress:=InputBoxTop(rsGotoAddress, rsFillInTheAddressYouWantToGoTo, IntTohex(disassemblerview.SelectedAddress, 8), true, canceled, memorybrowserHistory);
|
|
|
|
if(canceled)then
|
|
exit;
|
|
|
|
try
|
|
try
|
|
disassemblerview.SelectedAddress:=symhandler.getaddressfromname(newaddress);
|
|
except
|
|
disassemblerview.SelectedAddress:=getaddress(newaddress);
|
|
end;
|
|
except
|
|
on e:exception do
|
|
MessageDlg(e.Message,mtError,[mbok],0);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Search1Click(Sender: TObject);
|
|
begin
|
|
|
|
if findwindow=nil then findwindow:=TFindwindow.create(self);
|
|
findwindow.firstscan:=true;
|
|
findwindow.editStart.text:=inttohex(hexview.SelectionStart,8);
|
|
|
|
findwindow.ShowModal;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Change1Click(Sender: TObject);
|
|
begin
|
|
hexview.changeSelected;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Addthisaddresstothelist1Click(Sender: TObject);
|
|
var i: integer;
|
|
ad: ptrUint;
|
|
begin
|
|
//this will add the selected recdord to the list
|
|
hexview.AddSelectedAddressToCheatTable;
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miAddToTheCodelistClick(Sender: TObject);
|
|
var {start,stop: string;
|
|
a,b: dword;
|
|
i: integer;}
|
|
|
|
desc: string;
|
|
|
|
begin
|
|
|
|
frmAddToCodeList:=TfrmAddToCodeList.create(self);
|
|
frmAddToCodeList.addtocodelist:=true;
|
|
frmAddToCodeList.fromaddress:=disassemblerview.SelectedAddress;
|
|
frmAddToCodeList.toaddress:=disassemblerview.SelectedAddress;
|
|
disassemble(frmAddToCodeList.toaddress,desc);
|
|
dec(frmAddToCodeList.toaddress);
|
|
frmAddToCodeList.showmodal;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Splitter1CanResize(Sender: TObject;
|
|
var NewSize: Integer; var Accept: Boolean);
|
|
begin
|
|
|
|
if newsize<80 then
|
|
begin
|
|
newsize:=80;
|
|
accept:=false;
|
|
end;
|
|
|
|
if newsize>memorybrowser.Height-80 then
|
|
begin
|
|
newsize:=memorybrowser.Height-80;
|
|
accept:=false;
|
|
end;
|
|
accept:=true;
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.ScrollBar2Scroll(Sender: TObject;
|
|
ScrollCode: TScrollCode; var ScrollPos: Integer);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FormClose(Sender: TObject;
|
|
var Action: TCloseAction);
|
|
begin
|
|
if ischild then
|
|
begin
|
|
//do stuff particulary for the children
|
|
action:=cafree;
|
|
end
|
|
else
|
|
begin
|
|
//do stuff for the main debugger
|
|
if (debuggerthread<>nil) and (miDebugRun.enabled) then miDebugRun.click; //run if it was paused
|
|
|
|
|
|
if frmFloatingPointPanel<>nil then
|
|
frmFloatingPointPanel.Visible:=false;
|
|
|
|
if WindowState=wsMinimized then //for an unknown reason, the memoryview window can't be shown again if it was hidden minized
|
|
WindowState:=wsNormal;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugRunClick(Sender: TObject);
|
|
begin
|
|
if miDebugRun.Enabled then
|
|
begin
|
|
if debuggerthread<>nil then
|
|
debuggerthread.ContinueDebugging(co_run);
|
|
|
|
OnMemoryViewerRunning;
|
|
caption:=rsMemoryViewerRunning;
|
|
|
|
reloadstacktrace;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugStepClick(Sender: TObject);
|
|
begin
|
|
begin
|
|
if debuggerthread<>nil then
|
|
debuggerthread.ContinueDebugging(co_stepinto);
|
|
|
|
OnMemoryViewerRunning;
|
|
caption:=rsMemoryViewerRunning;
|
|
|
|
reloadstacktrace;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugStepOverClick(Sender: TObject);
|
|
var x: ptrUint;
|
|
i,j: integer;
|
|
s,s1,s2,temp:string;
|
|
int3: byte;
|
|
original,a,written:dword;
|
|
begin
|
|
debuggerthread.continueDebugging(co_stepover);
|
|
reloadstacktrace;
|
|
OnMemoryViewerRunning;
|
|
caption:=rsMemoryViewerRunning;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugRunTillClick(Sender: TObject);
|
|
var x: ptrUint;
|
|
i: integer;
|
|
temp:string;
|
|
int3: byte;
|
|
original,a,written:dword;
|
|
begin
|
|
begin
|
|
if debuggerthread<>nil then
|
|
debuggerthread.ContinueDebugging(co_runtill, disassemblerview.SelectedAddress);
|
|
|
|
OnMemoryViewerRunning;
|
|
caption:=rsMemoryViewerRunning;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Stacktrace1Click(Sender: TObject);
|
|
begin
|
|
if frmstacktrace=nil then
|
|
frmstacktrace:=tfrmstacktrace.create(application);
|
|
|
|
frmstacktrace.Show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Threadlist1Click(Sender: TObject);
|
|
begin
|
|
|
|
if frmThreadlist=nil then
|
|
frmThreadlist:=tfrmthreadlist.create(self);
|
|
|
|
frmThreadlist.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.AssemblePopup(x:string);
|
|
var assemblercode,desc,s: string;
|
|
totalbytes: TAssemblerBytes;
|
|
bytes: tassemblerbytes;
|
|
a,b,original,written:ptrUint;
|
|
originalsize:ptrUint;
|
|
replace: boolean;
|
|
c: word;
|
|
|
|
res: word;
|
|
i: integer;
|
|
canceled: boolean;
|
|
|
|
localdisassembler: TDisassembler;
|
|
bytelength: dword;
|
|
|
|
p: dword;
|
|
|
|
gnascript: tstringlist;
|
|
vpe: boolean;
|
|
|
|
address: ptruint;
|
|
|
|
oldbp: PBreakpoint=nil;
|
|
|
|
{$ifdef ONEBYTEJUMPS}
|
|
isjmp1: boolean;
|
|
jmp1target: ptruint;
|
|
{$endif}
|
|
begin
|
|
|
|
//make sure it doesnt have a breakpoint
|
|
address:=disassemblerview.SelectedAddress;
|
|
try
|
|
|
|
if debuggerthread<>nil then
|
|
begin
|
|
debuggerthread.lockbplist;
|
|
oldbp:=debuggerthread.isBreakpoint(Address);
|
|
|
|
if (oldbp<>nil) and (oldbp^.breakpointMethod<>bpmInt3) then
|
|
oldbp:=nil;
|
|
|
|
if oldbp=nil then
|
|
debuggerthread.unlockbplist; //no need to keep this lock
|
|
end;
|
|
|
|
|
|
originalsize:=Address;
|
|
|
|
localdisassembler:=TDisassembler.Create;
|
|
try
|
|
localdisassembler.disassemble(originalsize,desc);
|
|
assemblercode:=localdisassembler.LastDisassembleData.prefix+localdisassembler.LastDisassembleData.opcode+' '+localdisassembler.LastDisassembleData.parameters;
|
|
finally
|
|
localdisassembler.free;
|
|
end;
|
|
|
|
dec(originalsize,Address);
|
|
|
|
|
|
if x<>'' then assemblercode:=x;
|
|
|
|
// copy
|
|
|
|
assemblercode:=InputboxTop(rsCheatEngineSingleLingeAssembler, Format(rsTypeYourAssemblerCodeHereAddress, [inttohex(Address, 8)]), assemblercode, x='', canceled{$ifndef darwin},assemblerHistory{$endif});
|
|
if not canceled then
|
|
begin
|
|
|
|
if defaultBinutils<>nil then
|
|
begin
|
|
//use the gnuassembler for this
|
|
gnascript:=TStringList.create;
|
|
try
|
|
gnascript.add('.msection sline 0x'+inttohex(Address,8));
|
|
gnascript.Add(assemblercode);
|
|
gnuassemble(gnascript);
|
|
finally
|
|
gnascript.free;
|
|
end;
|
|
|
|
exit;
|
|
end;
|
|
|
|
|
|
{$ifdef ONEBYTEJUMPS}
|
|
s:=lowercase(trim(assemblercode));
|
|
if s.StartsWith('jmp1 ') then
|
|
begin
|
|
isjmp1:=true;
|
|
s:=copy(s,6);
|
|
|
|
jmp1target:=symhandler.getAddressFromName(s);
|
|
|
|
//still here, so the address is valid
|
|
assemblercode:='db cc';
|
|
end
|
|
else
|
|
isjmp1:=false;
|
|
{$endif}
|
|
|
|
|
|
if Assemble(assemblercode,Address,bytes) then
|
|
begin
|
|
if originalsize<>length(bytes) then
|
|
begin
|
|
if formsettings.replacewithnops.checked then
|
|
begin
|
|
if formsettings.askforreplacewithnops.checked then
|
|
begin
|
|
c:=messagedlg(Format(rsTheGeneratedCodeIsByteSLongButTheSelectedOpcodeIsB, [IntToStr(length(bytes)), IntToStr(originalsize)]), mtConfirmation, mbYesNoCancel, 0);
|
|
replace:=c=mryes;
|
|
if c=mrCancel then exit;
|
|
end else replace:=true;
|
|
|
|
if replace then
|
|
begin
|
|
while originalsize>length(bytes) do
|
|
begin
|
|
setlength(bytes,length(bytes)+1);
|
|
bytes[length(bytes)-1]:=$90;
|
|
end;
|
|
|
|
a:=Address+length(bytes);
|
|
|
|
b:=Address;
|
|
while b<a do disassemble(b,desc);
|
|
|
|
a:=b-Address;
|
|
while length(bytes)<a do
|
|
begin
|
|
setlength(bytes,length(bytes)+1);
|
|
bytes[length(bytes)-1]:=$90;
|
|
end;
|
|
end;
|
|
|
|
|
|
end;
|
|
end;
|
|
|
|
{$ifdef ONEBYTEJUMPS}
|
|
if isjmp1 then
|
|
begin
|
|
InitializeAutoAssemblerExceptionHandler;
|
|
AutoAssemblerExceptionHandlerAddChangeRIPEntry(address, jmp1target);
|
|
|
|
AutoAssemblerExceptionHandlerApplyChanges;
|
|
end;
|
|
{$endif}
|
|
//note to self, check the size of the current opcode and give the option to replace the missing or too many bytes with nops
|
|
//and put in a option to disable showing that message, and use a default action
|
|
|
|
// get old security and set new security (not needed in win9x but nt doesnt even allow writeprocessmemory to do this
|
|
original:=0;
|
|
|
|
bytelength:=length(bytes);
|
|
|
|
if oldbp<>nil then
|
|
debuggerthread.UnsetBreakpoint(oldbp);
|
|
|
|
a:=0;
|
|
if fcr3=0 then
|
|
begin
|
|
if SystemSupportsWritableExecutableMemory or SkipVirtualProtectEx then
|
|
vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(Address),bytelength,PAGE_EXECUTE_READWRITE,p)
|
|
else
|
|
begin
|
|
outputdebugstring('First making memory writable');
|
|
if processid<>GetCurrentProcessId then
|
|
begin
|
|
if (CurrentDebuggerInterface is TGDBServerDebuggerInterface) then
|
|
TGDBServerDebuggerInterface(CurrentDebuggerInterface).suspendProcess
|
|
else
|
|
ntsuspendProcess(processhandle);
|
|
end;
|
|
vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(Address),bytelength,PAGE_READWRITE,p)
|
|
end;
|
|
|
|
if (CurrentDebuggerInterface is TGDBServerDebuggerInterface) and GDBWriteProcessMemoryCodeOnly then
|
|
TGDBServerDebuggerInterface(CurrentDebuggerInterface).writeBytes(address, @bytes[0],bytelength)
|
|
else
|
|
WriteProcessMemoryWithCloakSupport(processhandle,pointer(Address),@bytes[0],bytelength,a);
|
|
|
|
if vpe then
|
|
begin
|
|
VirtualProtectEx(processhandle,pointer(Address),bytelength,p,p);
|
|
outputdebugstring('restoring back to the original protection: '+p.ToString);
|
|
end;
|
|
|
|
if (not (SystemSupportsWritableExecutableMemory or SkipVirtualProtectEx)) and (processid<>GetCurrentProcessId) then
|
|
begin
|
|
if (CurrentDebuggerInterface is TGDBServerDebuggerInterface) then
|
|
TGDBServerDebuggerInterface(CurrentDebuggerInterface).resumeProcess
|
|
else
|
|
ntresumeProcess(processhandle);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
{$ifdef windows}
|
|
WriteProcessMemoryCR3(fcr3, pointer(address),@bytes[0], bytelength,a);
|
|
{$endif}
|
|
end;
|
|
|
|
if (a>0) and (oldbp<>nil) then
|
|
begin
|
|
oldbp^.originalbyte:=bytes[0];
|
|
debuggerthread.SetBreakpoint(oldbp);
|
|
end;
|
|
|
|
hexview.update;
|
|
disassemblerview.Update;
|
|
|
|
{$ifdef darwin}
|
|
SetFocus;
|
|
disassemblerview.SetFocus;
|
|
{$endif}
|
|
end else raise exception.create(Format(rsIDonTUnderstandWhatYouMeanWith, [assemblercode]));
|
|
|
|
|
|
end;
|
|
|
|
|
|
finally
|
|
if oldbp<>nil then //still needs to be unlocked
|
|
debuggerthread.unlockbplist;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Assemble1Click(Sender: TObject);
|
|
begin
|
|
try
|
|
AssemblePopup('');
|
|
except
|
|
on e: exception do
|
|
MessageDlg(e.message, mtError, [mbok],0);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.HexEditKeyPress(Sender: TObject; var Key: Char);
|
|
begin
|
|
case key of
|
|
chr(8) : ;
|
|
chr(16) : ;
|
|
'A'..'F' : ;
|
|
'a'..'f' : key:=uppercase(key)[1];
|
|
'0'..'9' : ;
|
|
else key:=chr(0);
|
|
end;
|
|
|
|
if editing then key:=#0;
|
|
editing:=false;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.HexEditExit(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.HexEditKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
|
|
begin
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowIndisassemblerClick(Sender: TObject);
|
|
begin
|
|
if context<>nil then
|
|
disassemblerview.SelectedAddress:=PContextElement_register(pmRegisters.PopupComponent.Tag)^.getValue(context);
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.RegisterLabelDblClick(Sender: TObject);
|
|
var x: dword;
|
|
i: integer;
|
|
regname,input: string;
|
|
value: qword;
|
|
rbase: string;
|
|
context: PContext;
|
|
labeltext: string;
|
|
|
|
r: PContextElement_register;
|
|
|
|
begin
|
|
regname:='';
|
|
labeltext:=tlabel(sender).Caption;
|
|
|
|
if (debuggerthread<>nil) and (debuggerthread.isWaitingToContinue) then
|
|
begin
|
|
r:=PContextElement_register(tlabel(Sender).Tag);
|
|
regname:=r^.name;
|
|
|
|
input:=r^.getValueString(debuggerthread.CurrentThread.context);
|
|
if inputquery(rsChangeRegister, Format(rsWhatIsTheNewValueOf, [regname]), input) then
|
|
begin
|
|
if debuggerthread.CurrentThread<>nil then
|
|
begin
|
|
r^.setValue(debuggerthread.CurrentThread.context, input);
|
|
tlabel(Sender).caption:=padleft(regname, contexthandler.GeneralPurposeRegisterMaxCharCount)+' '+r^.getFullValueString(debuggerthread.CurrentThread.context);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugBreakClick(Sender: TObject);
|
|
//var threadhandle: thandle;
|
|
var
|
|
threadlist: TList;
|
|
needform: boolean;
|
|
threadhandle: thandle;
|
|
i: integer;
|
|
begin
|
|
if not startdebuggerifneeded then exit;
|
|
|
|
threadhandle:=0;
|
|
needform:=false;
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
if threadlist.count=1 then
|
|
begin
|
|
threadhandle:=TDebugThreadHandler(threadlist[0]).handle;
|
|
|
|
end
|
|
else
|
|
if threadlist.count>1 then
|
|
needform:=true
|
|
else exit; //no threads
|
|
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
|
|
if needform then
|
|
begin
|
|
//multiple threads!!! Ask user which one
|
|
frmbreakthread:=tfrmbreakthread.create(self);
|
|
if frmbreakthread.showmodal=mrOK then threadhandle:=frmbreakthread.threadhandle else
|
|
begin
|
|
frmbreakthread.free;
|
|
frmbreakthread:=nil;
|
|
exit;
|
|
end;
|
|
|
|
frmbreakthread.free;
|
|
frmbreakthread:=nil;
|
|
|
|
end;
|
|
|
|
if threadhandle<>0 then
|
|
begin
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
//find the thread with this handle and tell it to break
|
|
for i:=0 to threadlist.count-1 do
|
|
if TDebugThreadHandler(threadlist[i]).handle=threadhandle then
|
|
begin
|
|
TDebugThreadHandler(threadlist[i]).BreakThread;
|
|
exit;
|
|
end;
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Reservememory1Click(Sender: TObject);
|
|
var count: string;
|
|
memsize: dword;
|
|
baseaddress: pointer;
|
|
x: dword;
|
|
s: string;
|
|
begin
|
|
{$ifdef darwin}
|
|
count:=getPageSize.ToString;
|
|
{$else}
|
|
count:='4096';
|
|
{$endif}
|
|
try
|
|
if inputquery(rsAllocateMemory, rsHowMuchMemoryDoYouWantToAddToThisProcess, count) then
|
|
begin
|
|
try
|
|
memsize:=StrToInt(count);
|
|
except
|
|
raise exception.Create(Format(rsHowMuchIs, [count]));
|
|
end;
|
|
|
|
baseaddress:=nil;
|
|
|
|
if not SystemSupportsWritableExecutableMemory then
|
|
baseaddress:=VirtualAllocEx(processhandle,nil,memsize,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE)
|
|
else
|
|
baseaddress:=VirtualAllocEx(processhandle,nil,memsize,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE);
|
|
|
|
if baseaddress=nil then
|
|
raise exception.Create(rsErrorAllocatingMemory);
|
|
|
|
if allocsAddToUnexpectedExceptionList then
|
|
AddUnexpectedExceptionRegion(ptruint(baseaddress),memsize);
|
|
|
|
if (disassemblerview.SelectedAddress<>0) and (memsize>7) and (messagedlg(Format(rsAtLeastBytesHaveBeenAllocatedAtDoYouWantToGoThereN, [IntToStr(memsize), IntToHex(ptrUint(baseaddress), 8), #13
|
|
+#10]), mtConfirmation, [mbyes, mbno], 0)=mryes) then
|
|
disassemblerview.SelectedAddress:=ptrUint(baseaddress);
|
|
|
|
end;
|
|
|
|
except
|
|
on e: exception do
|
|
MessageDlg(e.message, mtError,[mbok],0);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Savememoryregion1Click(Sender: TObject);
|
|
{will save a cheat engine memory region file .CEM}
|
|
begin
|
|
if frmSaveMemoryRegion=nil then
|
|
frmSaveMemoryRegion:=TFrmSaveMemoryRegion.create(self);
|
|
|
|
if (disassemblerview.SelectedAddress <> disassemblerview.SelectedAddress2) then //disassembler view selection takes priority
|
|
begin
|
|
frmSaveMemoryRegion.editFrom.Text:=inttohex(minX(disassemblerview.SelectedAddress,disassemblerview.SelectedAddress2),8);
|
|
frmSaveMemoryRegion.editTo.Text:=inttohex(maxX(disassemblerview.SelectedAddress,disassemblerview.SelectedAddress2),8);
|
|
end
|
|
else if (hexview.SelectionStart <> hexview.SelectionStop) then
|
|
begin
|
|
frmSaveMemoryRegion.editFrom.Text:=inttohex(minX(hexview.SelectionStart,hexview.SelectionStop),8);
|
|
frmSaveMemoryRegion.editTo.Text:=inttohex(maxX(hexview.SelectionStart,hexview.SelectionStop),8);
|
|
end
|
|
else
|
|
begin
|
|
//leave blank
|
|
end;
|
|
|
|
frmSaveMemoryRegion.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Loadmemolryregion1Click(Sender: TObject);
|
|
begin
|
|
|
|
if openmemory.Execute then
|
|
begin
|
|
tfrmloadmemory.Create(self).Showmodal(openmemory.filename);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.HexEditDblClick(Sender: TObject);
|
|
begin
|
|
change1.Click;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Debugstrings1Click(Sender: TObject);
|
|
begin
|
|
{$ifndef net}
|
|
|
|
if startdebuggerifneeded then
|
|
formdebugstrings.show;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.TextEditExit(Sender: TObject);
|
|
var bt: byte;
|
|
aw: dword;
|
|
begin
|
|
end;
|
|
|
|
procedure TMemoryBrowser.TextEditKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
end;
|
|
|
|
procedure TMemoryBrowser.CreateThread1Click(Sender: TObject);
|
|
var startaddress: ptrUint;
|
|
parameter: ptrUint;
|
|
ThreadID: dword;
|
|
start:string;
|
|
param:string;
|
|
begin
|
|
start:=IntToHex(disassemblerview.SelectedAddress,8);
|
|
param:='0';
|
|
if not InputQuery(rsCreateRemoteThread, rsWhatWillBeTheStartaddressOfThisThread, start) then exit;
|
|
try
|
|
startaddress:=StrToQWordEx('$'+start);
|
|
except
|
|
raise exception.Create(rsPleaseEnterAValidHexadecimalAddres);
|
|
end;
|
|
|
|
if not InputQuery(rsCreateRemoteThread, rsYouWantToGiveAnAdditional32BitParameterWillShowUpI, param) then exit;
|
|
try
|
|
parameter:=StrToInt('$'+param);
|
|
except
|
|
raise exception.Create(rsPleaseEnterAValidHexadecimalValue);
|
|
end;
|
|
|
|
if CreateRemoteThread(processhandle,nil,0,pointer(startaddress),pointer(parameter),0,threadid)=0 then
|
|
MessageDlg(rsMBCreationOfTheRemoteThreadFailed, mterror,[mbok],0)
|
|
else
|
|
showmessage(rsMBThreadCreated);
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MemoryRegions1Click(Sender: TObject);
|
|
begin
|
|
formmemoryregions:=tformmemoryregions.Create(self);
|
|
formmemoryregions.show;
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.TextEditKeyPress(Sender: TObject; var Key: Char);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.FillMemory1Click(Sender: TObject);
|
|
begin
|
|
|
|
frmFillMemory:=TFrmFillMemory.create(self);
|
|
with frmFillMemory do
|
|
begin
|
|
edit1.Text:=IntToHex(disassemblerview.SelectedAddress,8);
|
|
edit2.Text:=IntToHex(disassemblerview.SelectedAddress+1,8);
|
|
frmFillMemory.showmodal;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Disectwindow1Click(Sender: TObject);
|
|
begin
|
|
|
|
{$ifndef net}
|
|
frmdissectWindow:=tfrmdissectWindow.create(self);
|
|
frmdissectWindow.showmodal;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Savedisassemledoutput1Click(Sender: TObject);
|
|
var x,y: string;
|
|
start,stop: ptrUint;
|
|
output: textfile;
|
|
|
|
begin
|
|
|
|
with tfrmSavedisassembly.create(self) do
|
|
begin
|
|
start:=minX(disassemblerview.SelectedAddress,disassemblerview.SelectedAddress2);
|
|
stop:=maxX(disassemblerview.SelectedAddress,disassemblerview.SelectedAddress2);
|
|
disassemble(stop);
|
|
edit1.Text:=inttohex(start,8);
|
|
edit2.Text:=inttohex(stop,8);
|
|
show;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Heaps1Click(Sender: TObject);
|
|
begin
|
|
if processid=0 then
|
|
begin
|
|
messagedlg(rsPleaseTargetAProcessFirst, mterror, [mbOK], 0);
|
|
exit;
|
|
end;
|
|
|
|
if processid=GetCurrentProcessId then
|
|
begin
|
|
messagedlg(rsPleaseTargetAnotherProcess, mterror, [mbOK], 0);
|
|
exit;
|
|
end;
|
|
|
|
|
|
if (frmMemoryAllocHandler<>nil) and (frmMemoryAllocHandler.hookedprocessid<>processid) then
|
|
freeandnil(frmMemoryAllocHandler);
|
|
|
|
if frmheaps=nil then
|
|
frmheaps:=tfrmheaps.create(self);
|
|
|
|
frmheaps.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.EnumeratedllsandSymbols1Click(Sender: TObject);
|
|
begin
|
|
symhandler.reinitialize;
|
|
|
|
if frmEnumerateDLLs=nil then
|
|
frmEnumerateDLLs:=tfrmEnumerateDLLs.create(application);
|
|
|
|
frmEnumerateDLLs.show;
|
|
frmEnumerateDLLs.enumerate;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.InjectDLL1Click(Sender: TObject);
|
|
var dll: string;
|
|
functionname: string;
|
|
dllList: tstringlist;
|
|
begin
|
|
|
|
functionname:='';
|
|
dll:='';
|
|
|
|
{$ifdef darwin}
|
|
OpenDllDialog.DefaultExt:='.dylib';
|
|
OpenDllDialog.Filter:='Dylib-files (*.dylib)|*.dylib|All files (*.*)|*.*';
|
|
{$endif}
|
|
|
|
if opendlldialog.Execute then
|
|
begin
|
|
dll:=utf8toansi(opendlldialog.Filename);
|
|
{$ifdef windows}
|
|
if MessageDlg(rsDoYouWantToExecuteAFunctionOfTheDll, mtConfirmation , [mbyes, mbno], 0)=mryes then
|
|
begin
|
|
dllList:=tstringlist.Create;
|
|
|
|
try
|
|
try
|
|
peinfo_getExportList(opendlldialog.filename, dllList);
|
|
|
|
with TfrmSelectionList.create(self,dllList) do
|
|
begin
|
|
caption:=rsInjectDll;
|
|
label1.caption:=rsSelectTheFunctionYouWantToExecute;
|
|
if showmodal=mrok then
|
|
if itemindex<>-1 then
|
|
functionname:=selected;
|
|
|
|
free;
|
|
end;
|
|
except
|
|
|
|
end;
|
|
finally
|
|
dllList.free;
|
|
end;
|
|
end;
|
|
{$else}
|
|
functionname:='';
|
|
{$endif}
|
|
|
|
try
|
|
InjectDll(dll,functionname);
|
|
symhandler.reinitialize(true);
|
|
showmessage(rsDLLInjected);
|
|
except
|
|
on e:exception do
|
|
MessageDlg(e.message,mtError,[mbok],0);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.AutoInject1Click(Sender: TObject);
|
|
begin
|
|
tfrmautoinject.create(self).show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Dissectcode1Click(Sender: TObject);
|
|
begin
|
|
|
|
{$ifndef net}
|
|
if frmdissectcode=nil then
|
|
frmdissectcode:=tfrmDissectcode.create(self);
|
|
|
|
if disassemblerview.SelectedAddress2<>disassemblerview.SelectedAddress then
|
|
begin
|
|
frmDissectCode.edtCustomRangeStart.text:=inttohex(MinX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2),8);
|
|
frmDissectCode.edtCustomRangeStop.text:=inttohex(MaxX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2),8);
|
|
end
|
|
else
|
|
begin
|
|
frmDissectCode.edtCustomRangeStart.text:='';
|
|
frmDissectCode.edtCustomRangeStop.text:='';
|
|
end;
|
|
|
|
frmdissectcode.Show;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Createjumptocodecave1Click(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Findstaticpointers1Click(Sender: TObject);
|
|
begin
|
|
|
|
{$ifndef net}
|
|
if frmfindstatics=nil then
|
|
frmfindstatics:=tfrmfindstatics.create(self);
|
|
|
|
frmfindstatics.show;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Scanforcodecaves1Click(Sender: TObject);
|
|
begin
|
|
|
|
if frmcodecavescanner=nil then
|
|
frmcodecavescanner:=tfrmCodecaveScanner.create(self);
|
|
|
|
frmCodecavescanner.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Changestateofregisteratthislocation1Click(
|
|
Sender: TObject);
|
|
begin
|
|
tfrmModifyRegisters.create(self,disassemblerview.SelectedAddress).showmodal;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miTogglebreakpointClick(Sender: TObject);
|
|
var
|
|
bpm: TBreakpointMethod;
|
|
b: byte;
|
|
PA: qword;
|
|
bo: integer;
|
|
begin
|
|
//first check if it's a cloaked dbvm bp, and if so, disable it
|
|
if dbvm_isBreakpoint(disassemblerview.SelectedAddress, PA, BO, b) then
|
|
begin
|
|
if bo=1 then //changeregonbp
|
|
begin
|
|
dbvm_cloak_removechangeregonbp(PA);
|
|
disassemblerview.Update;
|
|
exit;
|
|
end;
|
|
|
|
if bo=4 then //break and trace
|
|
begin
|
|
dbvm_cloak_traceonbp_remove(PA);
|
|
disassemblerview.Update;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
try
|
|
if startdebuggerifneeded(true) then
|
|
begin
|
|
if overridebreakpointmethod then
|
|
bpm:=preferedF5BreakpointMethod
|
|
else
|
|
bpm:=preferedBreakpointMethod;
|
|
|
|
DebuggerThread.ToggleOnExecuteBreakpoint(disassemblerview.SelectedAddress,bpm);
|
|
disassemblerview.Update;
|
|
|
|
ApplySourceCodeDebugUpdate;
|
|
|
|
end;
|
|
except
|
|
on e:exception do MessageDlg(e.message,mtError,[mbok],0);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Breakpointlist1Click(Sender: TObject);
|
|
begin
|
|
if frmbreakpointlist=nil then
|
|
begin
|
|
frmbreakpointlist:=tfrmBreakpointlist.create(self);
|
|
frmBreakpointlist.show;
|
|
end
|
|
else
|
|
frmbreakpointlist.bringtofront;
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.Dissectdata1Click(Sender: TObject);
|
|
begin
|
|
|
|
{$ifndef net}
|
|
with tfrmpointerscanner.create(self) do
|
|
show;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowSymbolsClick(Sender: TObject);
|
|
begin
|
|
symhandler.showsymbols:=miShowSymbols.Checked;
|
|
disassemblerview.Update;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowModuleAddressesClick(Sender: TObject);
|
|
begin
|
|
symhandler.showmodules:=miShowModuleAddresses.Checked;
|
|
disassemblerview.Update;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miShowSectionAddressesClick(Sender: TObject);
|
|
begin
|
|
symhandler.showsections:=miShowSectionAddresses.checked;
|
|
disassemblerview.Update;
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.miDissectDataClick(Sender: TObject);
|
|
begin
|
|
{
|
|
if length(frmStructures)>0 then
|
|
begin
|
|
frmStructures[0].edtAddress.Text:=inttohex(memorybrowser.memoryaddress,8);
|
|
frmStructures[0].Show;
|
|
end
|
|
else
|
|
begin
|
|
//create it
|
|
with tfrmstructures.create(self) do
|
|
begin
|
|
edtAddress.Text:=inttohex(memoryaddress,8);
|
|
applychanges(false);
|
|
show;
|
|
end;
|
|
end; }
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miUserdefinedSymbolsClick(Sender: TObject);
|
|
begin
|
|
if frmSymbolhandler=nil then
|
|
frmSymbolhandler:=TfrmSymbolhandler.create(self);
|
|
|
|
frmSymbolhandler.show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Allocatenonpagedmemory1Click(Sender: TObject);
|
|
var count: string;
|
|
memsize: integer;
|
|
baseaddress: pointer;
|
|
x: dword;
|
|
s: string;
|
|
begin
|
|
{$ifdef windows}
|
|
{$ifndef net}
|
|
count:='4096';
|
|
if inputquery(rsAllocateMemory, rsHowMuchMemoryDoYouWishToAllocate, count) then
|
|
begin
|
|
try
|
|
memsize:=StrToInt(count);
|
|
except
|
|
raise exception.Create(Format(rsHowMuchIs, [count]));
|
|
end;
|
|
|
|
baseaddress:=nil;
|
|
baseaddress:=KernelAlloc(memsize);
|
|
if baseaddress=nil then
|
|
raise exception.Create(rsErrorAllocatingMemory);
|
|
|
|
if messagedlg(Format(rsAtLeastBytesHaveBeenAllocatedAtGoThereNow, [IntToStr(memsize), IntToHex(ptrUint(baseaddress), 8)]), mtinformation, [mbyes, mbno], 0) = mryes then
|
|
disassemblerview.SelectedAddress:=ptrUint(baseaddress);
|
|
end;
|
|
{$endif}
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Getaddress1Click(Sender: TObject);
|
|
var p: pointer;
|
|
s: string;
|
|
ws: widestring;
|
|
pws: pwidechar;
|
|
begin
|
|
{$ifdef windows}
|
|
if inputquery(rsGetKernelAddress, rsGiveTheNameOfTheFunctionYouWantToFindCaseSensitive, s) then
|
|
begin
|
|
ws:=s;
|
|
pws:=@ws[1];
|
|
p:=GetKProcAddress(pws);
|
|
|
|
disassemblerview.SelectedAddress:=ptrUint(p);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Findmemory1Click(Sender: TObject);
|
|
begin
|
|
search1.Click;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Assemblycode1Click(Sender: TObject);
|
|
var
|
|
fromaddress: ptruint;
|
|
toaddress: ptruint;
|
|
|
|
|
|
begin
|
|
if frmAssemblyScan=nil then
|
|
frmAssemblyScan:=tfrmassemblyscan.create(self);
|
|
|
|
frmAssemblyScan.edtFrom.text:=inttohex(disassemblerview.TopAddress,8);
|
|
|
|
if processhandler.is64Bit then
|
|
frmAssemblyScan.edtTo.text:='FFFFFFFFFFFFFFFF'
|
|
else
|
|
frmAssemblyScan.edtTo.text:='FFFFFFFF';
|
|
|
|
|
|
if frmAssemblyScan.ShowModal=mrok then
|
|
begin
|
|
if frmAssemblyScan.mAssemblerSearch.lines.Count=0 then exit;
|
|
with TfrmDisassemblyscan.create(self) do
|
|
begin
|
|
startaddress:=frmAssemblyScan.startaddress;
|
|
stopaddress:=frmAssemblyScan.stopaddress;
|
|
stringstofind:=frmAssemblyScan.mAssemblerSearch.lines;
|
|
show;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Driverlist1Click(Sender: TObject);
|
|
begin
|
|
{$ifndef net}
|
|
|
|
with tfrmdriverlist.create(self) do
|
|
show;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.plugintype6click(sender:tobject);
|
|
var
|
|
x: TPluginfunctionType6;
|
|
selectedaddress: ptrUint;
|
|
begin
|
|
x:=TPluginfunctionType6(tmenuitem(sender).Tag);
|
|
if x<>nil then
|
|
begin
|
|
selectedaddress:=disassemblerview.SelectedAddress;
|
|
x.callback(@selectedaddress);
|
|
disassemblerview.SelectedAddress:=selectedaddress;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.plugintype1click(sender:tobject);
|
|
var x: TPluginfunctionType1;
|
|
address: ptrUint;
|
|
hexviewaddress: ptrUint;
|
|
seladdress: ptruint;
|
|
begin
|
|
x:=TPluginfunctionType1(tmenuitem(sender).Tag);
|
|
if x<>nil then
|
|
begin
|
|
address:=disassemblerview.TopAddress;
|
|
hexviewaddress:=memoryaddress;
|
|
seladdress:=disassemblerview.SelectedAddress;
|
|
if x.callback(@address,@seladdress,@hexviewaddress) then
|
|
begin
|
|
disassemblerview.TopAddress:=address;
|
|
disassemblerview.selectedaddress:=seladdress;
|
|
memoryaddress:=hexviewaddress;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Sericedescriptortable1Click(Sender: TObject);
|
|
begin
|
|
{$ifndef net}
|
|
|
|
if frmServiceDescriptorTables=nil then
|
|
frmServiceDescriptorTables:=TfrmServiceDescriptorTables.create(self);
|
|
|
|
frmServiceDescriptorTables.show;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.MBCanvasMouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Cut1Click(Sender: TObject);
|
|
begin
|
|
hexview.CopySelectionToClipboard;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Pastefromclipboard1Click(Sender: TObject);
|
|
begin
|
|
hexview.PasteFromClipboard;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Setsymbolsearchpath1Click(Sender: TObject);
|
|
var searchpath: string;
|
|
begin
|
|
searchpath:=symhandler.getsearchpath;
|
|
if inputquery(rsSymbolHandler, rsPleaseSpecifyTheNewSymbolSearchpathSeperatesPaths, searchpath) then
|
|
begin
|
|
symhandler.setsearchpath(searchpath);
|
|
|
|
symhandler.reinitialize(true);
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miKernelmodeSymbolsClick(Sender: TObject);
|
|
begin
|
|
{$ifndef net}
|
|
|
|
miKernelmodeSymbols.Checked:=not miKernelmodeSymbols.Checked;
|
|
|
|
symhandler.kernelsymbols:=miKernelmodeSymbols.Checked;
|
|
symhandler.reinitialize(true);
|
|
//symhandler.waitforsymbolsloaded(false);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Breakandtraceinstructions1Click(Sender: TObject);
|
|
var f: TFrmTracer;
|
|
begin
|
|
f:=TFrmTracer.create(self);
|
|
f.show;
|
|
f.miNewTrace.Click;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.debuggerpopupPopup(Sender: TObject);
|
|
var x: ptrUint;
|
|
i: integer;
|
|
a,a2: ptruint;
|
|
inadvancedoptions: boolean;
|
|
e: boolean;
|
|
VA,PA: QWORD;
|
|
BO: integer;
|
|
bpm: TBreakpointMethod;
|
|
b: byte;
|
|
dbvmbp: boolean;
|
|
|
|
bp: PBreakpoint=nil;
|
|
begin
|
|
|
|
Breakandtraceinstructions1.Enabled:=processhandle<>0;
|
|
miTogglebreakpoint.Enabled:=processhandle<>0;
|
|
Changestateofregisteratthislocation1.Enabled:=processhandle<>0;
|
|
Findoutwhataddressesthisinstructionaccesses1.enabled:=processhandle<>0;
|
|
|
|
follow1.visible:=isjumporcall(disassemblerview.SelectedAddress,x);
|
|
back1.Visible:=disassemblerview.hasbacklist;
|
|
|
|
pluginhandler.handledisassemblerContextPopup(disassemblerview.SelectedAddress);
|
|
|
|
miConditionalBreak.enabled:=(debuggerthread<>nil) and (debuggerthread.isBreakpoint(disassemblerview.SelectedAddress)<>nil);
|
|
miConditionalBreak.visible:=miConditionalBreak.enabled;
|
|
|
|
miDBVMActivateCloak.visible:={$ifdef windows}isRunningDBVM and hasEPTSupport and (not hasCloakedRegionInRange(disassemblerview.SelectedAddress, 1, VA,PA)){$else}false{$endif};
|
|
miDBVMActivateCloak.enabled:=miDBVMActivateCloak.visible;
|
|
|
|
miDBVMDisableCloak.visible:={$ifdef windows}isRunningDBVM and hasEPTSupport and (hasCloakedRegionInRange(disassemblerview.SelectedAddress, 1, VA,PA)){$else}false{$endif};
|
|
miDBVMDisableCloak.enabled:=miDBVMDisableCloak.visible;
|
|
|
|
miTogglebreakpoint.visible:=(not ischild);
|
|
|
|
if miTogglebreakpoint.visible then
|
|
begin
|
|
dbvmbp:=dbvm_isBreakpoint(disassemblerview.SelectedAddress,PA,BO,b);
|
|
if dbvmbp then
|
|
outputdebugstring('DBVMBP=true')
|
|
else
|
|
outputdebugstring('DBVMBP=false');
|
|
|
|
if (debuggerthread<>nil) then
|
|
bp:=debuggerthread.isBreakpoint(disassemblerview.SelectedAddress);
|
|
|
|
if ((debuggerthread=nil) or (bp=nil)) and (not dbvmbp) then
|
|
begin
|
|
if overridebreakpointmethod then
|
|
bpm:=preferedF5BreakpointMethod
|
|
else
|
|
bpm:=preferedBreakpointMethod;
|
|
|
|
miTogglebreakpoint.caption:=rsSetBreakpoint+' ('+breakpointMethodToString(bpm)+')';
|
|
|
|
Changestateofregisteratthislocation1.visible:=true; //setting of bp's is OK
|
|
miSetSpecificBreakpoint.visible:=true;
|
|
Breakandtraceinstructions1.visible:=true;
|
|
Findoutwhataddressesthisinstructionaccesses1.visible:=true;
|
|
end
|
|
else
|
|
begin
|
|
miTogglebreakpoint.caption:=rsRemoveBreakpoint;
|
|
Changestateofregisteratthislocation1.visible:=(bp<>nil) and (bp^.breakpointAction=bo_ChangeRegister);
|
|
miSetSpecificBreakpoint.visible:=false;
|
|
Breakandtraceinstructions1.visible:=false;
|
|
Findoutwhataddressesthisinstructionaccesses1.visible:=false;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Changestateofregisteratthislocation1.visible:=false;
|
|
miSetSpecificBreakpoint.visible:=false;
|
|
Breakandtraceinstructions1.visible:=false;
|
|
Findoutwhataddressesthisinstructionaccesses1.visible:=false;
|
|
end;
|
|
|
|
|
|
|
|
Changestateofregisteratthislocation1.enabled:=Changestateofregisteratthislocation1.visible;
|
|
|
|
|
|
inadvancedoptions:=false;
|
|
|
|
for i:=0 to AdvancedOptions.count-1 do
|
|
begin
|
|
if AdvancedOptions.code[i]<>nil then
|
|
begin
|
|
a:=symhandler.getAddressFromName(AdvancedOptions.code[i].symbolname,false,e);
|
|
if not e then
|
|
begin
|
|
if InRangeX(disassemblerview.SelectedAddress, a, a+length(AdvancedOptions.code[i].actualopcode)-1 ) then
|
|
begin
|
|
inadvancedoptions:=true;
|
|
|
|
if AdvancedOptions.code[i].changed then
|
|
begin
|
|
miReplacewithnops.caption:=rsRestoreWithOrginalCode;
|
|
miReplacewithnops.imageindex:=44;
|
|
end
|
|
else
|
|
begin
|
|
miReplacewithnops.caption:=rsReplaceWithCodeThatDoesNothing;
|
|
miReplacewithnops.imageindex:=42;
|
|
end;
|
|
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not inadvancedoptions then
|
|
miReplacewithnops.caption:=rsReplaceWithCodeThatDoesNothing;
|
|
|
|
miAddToTheCodelist.visible:=not inadvancedoptions;
|
|
|
|
miDBVMFindoutwhataddressesthisinstructionaccesses.visible:={$ifdef windows}isDBVMCapable and miSetSpecificBreakpoint.visible{$else}false{$endif};
|
|
miDBVMFindoutwhataddressesthisinstructionaccesses.enabled:=miDBVMFindoutwhataddressesthisinstructionaccesses.visible;
|
|
menuitem5.visible:=miDBVMFindoutwhataddressesthisinstructionaccesses.visible;
|
|
menuitem6.visible:=miDBVMFindoutwhataddressesthisinstructionaccesses.visible;
|
|
|
|
//
|
|
miSetBreakpointHW.enabled:=(CurrentDebuggerInterface=nil) or (dbcHardwareBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities);
|
|
miSetBreakpointSW.enabled:=((CurrentDebuggerInterface=nil) and (not formsettings.cbKDebug.Checked)) or ((CurrentDebuggerInterface<>nil) and (dbcSoftwareBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities));
|
|
miSetBreakpointPE.enabled:=((CurrentDebuggerInterface=nil) and (not formsettings.cbKDebug.Checked)) or ((CurrentDebuggerInterface<>nil) and (dbcExceptionBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities));
|
|
miSetBreakpointDBVMExec.enabled:=((CurrentDebuggerInterface=nil) and (formsettings.cbKDebug.Checked)) or ((CurrentDebuggerInterface<>nil) and (dbcDBVMBreakpoint in CurrentDebuggerInterface.DebuggerCapabilities));
|
|
|
|
miSetBreakpointDBVMExec.visible:={$ifdef windows}hasEPTSupport{$else}false{$endif};
|
|
|
|
|
|
if logWrites then
|
|
begin
|
|
a:=minX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
a2:=maxX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
|
|
if a2=a then
|
|
disassemble(a2);
|
|
|
|
miUndoLastEdit.visible:=hasAddressBeenChangedRange(a,a2);
|
|
end
|
|
else
|
|
miUndoLastEdit.visible:=false;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.GDTlist1Click(Sender: TObject);
|
|
begin
|
|
|
|
Tfrmgdtinfo.create(self).show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.IDTlist1Click(Sender: TObject);
|
|
begin
|
|
|
|
TfrmIDT.create(self).show;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.FormDestroy(Sender: TObject);
|
|
var
|
|
h0,h1,h2,h3: integer;
|
|
params: array of integer;
|
|
|
|
reg: TRegistry;
|
|
|
|
v: integer;
|
|
|
|
begin
|
|
MemoryBrowsers.Remove(self);
|
|
|
|
if strace<>nil then
|
|
strace.free;
|
|
|
|
if disassemblerHistory<>nil then
|
|
freeandnil(disassemblerHistory);
|
|
|
|
if memorybrowserhistory<>nil then
|
|
freeandnil(memorybrowserHistory);
|
|
|
|
if assemblerHistory<>nil then
|
|
freeandnil(assemblerHistory);
|
|
|
|
//save position of window and other stuff
|
|
//membrowser comes after formsettings so is destroyed before formsettings, so valid
|
|
if hasBeenShown then
|
|
begin
|
|
if self.disassemblerview<>nil then
|
|
begin
|
|
setlength(params,12);
|
|
//don't use [xx,xx,xx] crash
|
|
params[0]:=self.disassemblerview.getheaderwidth(0);
|
|
params[1]:=self.disassemblerview.getheaderwidth(1);
|
|
params[2]:=self.disassemblerview.getheaderwidth(2);
|
|
params[3]:=self.disassemblerview.getheaderwidth(3);
|
|
params[4]:=self.panel1.height;
|
|
params[5]:=self.registerview.width;
|
|
params[6]:=strtoint(BoolToStr(self.miShowSymbols.checked,'1','0'));
|
|
|
|
v:=0;
|
|
if self.miShowModuleAddresses.checked then v:=v or 1;
|
|
if self.miShowSectionAddresses.checked then v:=v or 2;
|
|
params[7]:=v;
|
|
//params[8]:=strtoint(BoolToStr(self.miLockRowsize.Checked,'1','0')); 7.4: obsolete
|
|
params[9]:=self.hexview.LockedRowSize;
|
|
params[10]:=strtoint(BoolToStr(self.Kernelmodesymbols1.checked,'1','0'));
|
|
|
|
params[11]:=pnlStacktrace.Width;
|
|
|
|
saveformposition(self,params);
|
|
end;
|
|
end;
|
|
|
|
if self.disassemblerview<>nil then
|
|
freeandnil(self.disassemblerview);
|
|
|
|
if self.hexview<>nil then
|
|
freeandnil(self.hexview);
|
|
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Newwindow1Click(Sender: TObject);
|
|
var
|
|
s: string;
|
|
ns: string;
|
|
i: integer;
|
|
begin
|
|
with tmemorybrowser.create(application) do
|
|
begin
|
|
inc(mbchildcount);
|
|
//name:=rsMemoryBrowser+inttostr(mbchildcount);
|
|
debug1.Visible:=false;
|
|
debug1.enabled:=false;
|
|
//registerview.Visible:=false;
|
|
//splitter2.Visible:=false;
|
|
sbShowFloats.Visible:=false;
|
|
miDebugToggleBreakpoint.visible:=false;
|
|
|
|
s:=name;
|
|
ns:='';
|
|
for i:=length(s) downto 1 do
|
|
begin
|
|
if s[i] in ['0'..'9'] then
|
|
ns:=s[i]+ns
|
|
else
|
|
break;
|
|
end;
|
|
|
|
caption:=caption+'* ('+ns+')';
|
|
|
|
Kerneltools1.enabled:=memorybrowser.Kerneltools1.enabled;
|
|
miCR3Switcher.visible:=Kerneltools1.Enabled;
|
|
ischild:=true;
|
|
show;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.Follow1Click(Sender: TObject);
|
|
{
|
|
will change the selected disassembler address to the address this instructions jump so if it is an jump instruction
|
|
}
|
|
var address: ptrUint;
|
|
begin
|
|
if isjumporcall(disassemblerview.SelectedAddress,address) then
|
|
disassemblerview.SelectedAddress:=address;
|
|
end;
|
|
|
|
|
|
|
|
procedure TMemoryBrowser.copyBytesAndOpcodesClick(Sender: TObject);
|
|
var a,b: ptrUint;
|
|
_tag: integer;
|
|
begin
|
|
|
|
|
|
_tag:=(sender as tmenuitem).Tag;
|
|
if _tag=0 then raise exception.create('Build environment corrupted');
|
|
|
|
with tfrmSavedisassembly.create(self) do
|
|
begin
|
|
|
|
a:=minX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
b:=maxX(disassemblerview.SelectedAddress, disassemblerview.SelectedAddress2);
|
|
|
|
disassemble(b); //b gets increased with size of selected instruction
|
|
edit1.Text:=inttohex(a,8);
|
|
edit2.Text:=inttohex(b-1,8);
|
|
copymode:=true;
|
|
|
|
cbAddress.checked:=not (_tag in [4,7]);
|
|
cbBytes.checked:=_tag in [1,2,4,6];
|
|
cbOpcode.checked:=_tag in [1,3,6,7];
|
|
cbComment.checked:=(_tag=1);
|
|
|
|
button1.click;
|
|
waittilldone;
|
|
|
|
free;
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.DissectPEheaders1Click(Sender: TObject);
|
|
begin
|
|
|
|
with TfrmPEInfo.create(self) do
|
|
show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.GetEntryPointAndDataBase(var code: ptrUint; var data: ptrUint);
|
|
var modulelist: tstringlist=nil;
|
|
base: ptrUint;
|
|
header: pointer=nil;
|
|
headersize: dword;
|
|
br: ptrUint;
|
|
d: ptruint;
|
|
sectionlist: Tstringlist;
|
|
i: integer;
|
|
begin
|
|
code:=$00400000;
|
|
data:=$00400000; //on failure
|
|
|
|
modulelist:=tstringlist.Create;
|
|
symhandler.getModuleList(modulelist);
|
|
outputdebugstring('Retrieved the module list');
|
|
|
|
if modulelist.Count>0 then
|
|
begin
|
|
base:=ptrUint(modulelist.Objects[0]);
|
|
data:=base;
|
|
code:=base;
|
|
|
|
outputdebugstring('Base='+inttohex(base,8));
|
|
|
|
|
|
getmem(header,4096);
|
|
try
|
|
if readprocessmemory(processhandle,pointer(base),header,4096,br) then
|
|
begin
|
|
headersize:=peinfo_getheadersize(header);
|
|
|
|
if headersize>0 then
|
|
begin
|
|
OutputDebugString('headersize='+inttostr(headersize));
|
|
if headersize>1024*512 then exit;
|
|
|
|
freememandnil(header);
|
|
getmem(header,headersize);
|
|
if not readprocessmemory(processhandle,pointer(base),header,headersize,br) then exit;
|
|
|
|
Outputdebugstring('calling peinfo_getEntryPoint');
|
|
code:=base+peinfo_getEntryPoint(header, headersize);
|
|
|
|
OutputDebugString('calling peinfo_getdatabase');
|
|
d:=peinfo_getdatabase(header, headersize);
|
|
if d=0 then
|
|
begin
|
|
{$ifndef darwin}
|
|
sectionlist:=TStringList.Create;
|
|
if peinfo_getSectionList(base,sectionList) then
|
|
begin
|
|
for i:=0 to sectionlist.count-1 do
|
|
begin
|
|
if sectionlist[i]='.data' then
|
|
data:=TSectionInfo(sectionlist.Objects[i]).virtualAddress;
|
|
|
|
TSectionInfo(sectionlist.Objects[i]).free;
|
|
end;
|
|
end;
|
|
|
|
sectionlist.free;
|
|
{$endif}
|
|
end
|
|
else
|
|
data:=base+d;
|
|
end;
|
|
|
|
|
|
end;
|
|
finally
|
|
if header<>nil then
|
|
freememandnil(header);
|
|
|
|
header:=nil;
|
|
end;
|
|
end;
|
|
modulelist.free;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.setcodeanddatabase;
|
|
var code,data: ptrUint;
|
|
begin
|
|
if processid=$ffffffff then //file instead of process
|
|
begin
|
|
code:=0;
|
|
data:=0;
|
|
end
|
|
else
|
|
GetEntryPointAndDataBase(code,data);
|
|
|
|
disassemblerview.SelectedAddress:=code;
|
|
memoryaddress:=data;
|
|
|
|
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.Back1Click(Sender: TObject);
|
|
begin
|
|
disassemblerview.GoBack;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Showvaluesofstaticaddresses1Click(
|
|
Sender: TObject);
|
|
begin
|
|
showvalues:=not showvalues;
|
|
end;
|
|
|
|
|
|
procedure TMemoryBrowser.FindwhatThiscodeAccesses(address: ptrUint);
|
|
begin
|
|
if not startdebuggerifneeded then exit;
|
|
if debuggerthread<>nil then
|
|
debuggerthread.FindWhatCodeAccesses(address);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.DBVMFindwhatThiscodeAccesses(address: ptruint);
|
|
const
|
|
IA32_VMX_BASIC_MSR=$480;
|
|
IA32_VMX_TRUE_PROCBASED_CTLS_MSR=$48e;
|
|
IA32_VMX_PROCBASED_CTLS_MSR=$482;
|
|
IA32_VMX_PROCBASED_CTLS2_MSR=$48b;
|
|
var
|
|
address2: ptrUint;
|
|
res: word;
|
|
id: integer;
|
|
|
|
frmchangedaddresses: tfrmchangedaddresses;
|
|
unlockaddress: qword;
|
|
canuseept: boolean;
|
|
|
|
s: string;
|
|
procbased1flags: dword;
|
|
i: integer;
|
|
begin
|
|
{$ifdef windows}
|
|
LoadDBK32;
|
|
canuseept:=hasEPTSupport;
|
|
|
|
|
|
if canuseept=false then
|
|
begin
|
|
messagedlg('This function requires that your CPU supports ''Extended Page Table (EPT)'' which your CPU lacks', mtError,[mbok],0);
|
|
exit;
|
|
end;
|
|
|
|
if loaddbvmifneeded('DBVM find routines needs DBVM for EPT page hooking. Loading DBVM can potentially cause a system freeze. Are you sure?') then
|
|
begin
|
|
if not loaddbvmifneeded then exit;
|
|
|
|
address2:=address;
|
|
s:=disassemble(address2);
|
|
|
|
//spawn a DBVM watch config screen where the user can select options like lock memory
|
|
if frmDBVMWatchConfigFindWhatCodeAccesses=nil then
|
|
frmDBVMWatchConfigFindWhatCodeAccesses:=TfrmDBVMExecuteWatchConfig.create(self);
|
|
|
|
frmDBVMWatchConfigFindWhatCodeAccesses.address:=address;
|
|
frmDBVMWatchConfigFindWhatCodeAccesses.rbExecuteAccess.checked:=true;
|
|
frmDBVMWatchConfigFindWhatCodeAccesses.gbAccessType.visible:=false;
|
|
|
|
frmDBVMWatchConfigFindWhatCodeAccesses.cbMultipleRIP.checked:=true;
|
|
frmDBVMWatchConfigFindWhatCodeAccesses.cbMultipleRIP.Visible:=false;
|
|
frmDBVMWatchConfigFindWhatCodeAccesses.cbWholePage.Visible:=false;
|
|
|
|
if frmDBVMWatchConfigFindWhatCodeAccesses.showmodal=mrok then
|
|
begin
|
|
if frmDBVMWatchConfigFindWhatCodeAccesses.LockPage then
|
|
unlockaddress:=LockMemory(processid, address and QWORD($fffffffffffff000),4096)
|
|
else
|
|
unlockaddress:=0;
|
|
|
|
id:=dbvm_watch_executes(frmDBVMWatchConfigFindWhatCodeAccesses.PhysicalAddress, address2-address, frmDBVMWatchConfigFindWhatCodeAccesses.Options, frmDBVMWatchConfigFindWhatCodeAccesses.MaxEntries);
|
|
|
|
if (id<>-1) then
|
|
begin
|
|
//spawn a frmchangedaddresses
|
|
frmchangedaddresses:=tfrmChangedAddresses.Create(application);
|
|
|
|
if frmDBVMWatchConfigFindWhatCodeAccesses.LockPage then
|
|
unlockaddress:=LockMemory(processid, address and QWORD($fffffffffffff000),4096)
|
|
else
|
|
unlockaddress:=0;
|
|
|
|
frmchangedaddresses.address:=address;
|
|
|
|
frmchangedaddresses.debuggerinterfacewatchid:=id;
|
|
frmchangedaddresses.dbvmwatch_unlock:=unlockaddress;
|
|
if defaultDisassembler.LastDisassembleData.isfloat then
|
|
frmchangedaddresses.cbDisplayType.ItemIndex:=3;
|
|
|
|
if uppercase(defaultDisassembler.LastDisassembleData.opcode)='RET' then
|
|
begin
|
|
if processhandler.is64Bit then
|
|
s:='[RSP]'
|
|
else
|
|
s:='[ESP]';
|
|
end
|
|
else
|
|
begin
|
|
i:=pos('[',s)+1;
|
|
if i<>0 then
|
|
s:=copy(s,i,pos(']',s)-i)
|
|
else
|
|
begin
|
|
//no [ ] part
|
|
if processhandler.is64Bit then
|
|
s:='RDI'
|
|
else
|
|
s:='EDI';
|
|
end;
|
|
end;
|
|
|
|
frmchangedaddresses.equation:=s;
|
|
|
|
frmchangedaddresses.show;
|
|
end
|
|
else
|
|
MessageDlg('dbvm_watch failed', mtError, [mbok],0);
|
|
|
|
end;
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Findoutwhataddressesthisinstructionaccesses1Click(
|
|
Sender: TObject);
|
|
begin
|
|
try
|
|
findWhatthisCodeAccesses(disassemblerview.SelectedAddress);
|
|
|
|
except
|
|
on e: Exception do
|
|
begin
|
|
MessageDlg(e.message, mtError, [mbOK], 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.sbShowFloatsClick(Sender: TObject);
|
|
var
|
|
x: tpoint;
|
|
z: trect;
|
|
newleft: integer;
|
|
begin
|
|
|
|
if frmFloatingPointPanel=nil then
|
|
frmFloatingPointPanel:=TfrmFloatingPointPanel.create(self);
|
|
|
|
|
|
newleft:=left+Width;
|
|
if newleft+frmFloatingPointPanel.Width>screen.Width then newleft:=screen.width-frmFloatingPointPanel.width;
|
|
|
|
frmFloatingPointPanel.Left:=newleft;
|
|
frmFloatingPointPanel.Top:=self.top+(self.ClientOrigin.y-self.top)-(frmFloatingPointPanel.ClientOrigin.y-frmFloatingPointPanel.top);
|
|
frmFloatingPointPanel.ClientHeight:=scrollbox1.Height;
|
|
|
|
frmFloatingPointPanel.SetContextPointer(debuggerthread.CurrentThread.context);
|
|
|
|
frmFloatingPointPanel.show;//pop to foreground
|
|
end;
|
|
|
|
procedure TMemoryBrowser.ScriptConsole1Click(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.DisplayTypeClick(Sender: TObject);
|
|
var x: tmenuitem;
|
|
begin
|
|
//vtByte, vtWord, vtDword, vtDwordDec, vtSingle, vtDouble
|
|
if (sender is TMenuItem) then
|
|
begin
|
|
x:=TMenuItem(sender);
|
|
case x.tag of
|
|
0: hexview.DisplayType:=dtByte;
|
|
1: hexview.DisplayType:=dtByteDec;
|
|
2: hexview.DisplayType:=dtWord;
|
|
3: hexview.DisplayType:=dtWordDec;
|
|
4: hexview.DisplayType:=dtDword;
|
|
5: hexview.DisplayType:=dtDwordDec;
|
|
6: hexview.DisplayType:=dtQword;
|
|
7: hexview.DisplayType:=dtQwordDec;
|
|
8: hexview.DisplayType:=dtsingle;
|
|
9: hexview.DisplayType:=dtDouble;
|
|
else
|
|
begin
|
|
if x.tag>=$1000 then
|
|
begin
|
|
hexview.CustomType:=TCustomType(customtypes[x.tag-$1000]); //always set first
|
|
hexview.DisplayType:=dtCustom;
|
|
end;
|
|
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Showjumplines1Click(Sender: TObject);
|
|
begin
|
|
showjumplines1.checked:=not showjumplines1.checked;
|
|
disassemblerview.showjumplines:=showjumplines1.checked;
|
|
|
|
Onlyshowjumplineswithinrange1.Enabled:=showjumplines1.checked;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Onlyshowjumplineswithinrange1Click(
|
|
Sender: TObject);
|
|
begin
|
|
Onlyshowjumplineswithinrange1.checked:=not Onlyshowjumplineswithinrange1.checked;
|
|
if Onlyshowjumplineswithinrange1.checked then
|
|
disassemblerview.ShowJumplineState:=jlsOnlyWithinRange
|
|
else
|
|
disassemblerview.ShowJumplineState:=jlsAll;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.View1Click(Sender: TObject);
|
|
begin
|
|
miIPTLog.visible:=systemSupportsIntelPT and not hideiptcapability;
|
|
miIPTLog.enabled:=debuggerthread<>nil;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Watchmemoryallocations1Click(Sender: TObject);
|
|
begin
|
|
if processid=0 then
|
|
begin
|
|
MessageDlg(rsPleaseTargetAProcessFirst, mtError,[mbok], 0);
|
|
exit;
|
|
end;
|
|
|
|
if processid=GetCurrentProcessId then
|
|
begin
|
|
MessageDlg(rsPleaseTargetAnotherProcess, mtError,[mbok], 0);
|
|
exit;
|
|
end;
|
|
|
|
|
|
if (frmMemoryAllocHandler<>nil) and (frmMemoryAllocHandler.hookedprocessid<>processid) then
|
|
freeandnil(frmMemoryAllocHandler);
|
|
|
|
|
|
if frmMemoryAllocHandler=nil then
|
|
frmMemoryAllocHandler:=TfrmMemoryAllocHandler.Create(self);
|
|
|
|
frmMemoryAllocHandler.Show;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.reloadStacktrace;
|
|
var s: pptrUintarray;
|
|
x: ptrUint;
|
|
|
|
i: integer;
|
|
address, bytes, details: string;
|
|
li: tlistitem;
|
|
c: TListcolumn;
|
|
|
|
refname: string;
|
|
refaddress: ptruint;
|
|
begin
|
|
|
|
lvStacktraceData.Items.BeginUpdate;
|
|
try
|
|
if stacktrace2.Checked then
|
|
begin
|
|
//setup view for stacktrace if it isn't setup yet
|
|
if lvStacktraceData.columns.Count=3 then
|
|
begin
|
|
lvstacktracedata.Columns.BeginUpdate;
|
|
try
|
|
lvstacktracedata.Columns.Clear;
|
|
c:=lvstacktracedata.Columns.Add;
|
|
c.Caption:=rsReturnAddress;
|
|
c.Width:=lvstacktracedata.Canvas.TextWidth('DDDDDDDD');
|
|
c.AutoSize:=true;
|
|
|
|
|
|
c:=lvstacktracedata.Columns.Add;
|
|
c.Caption:=rsParameters;
|
|
c.Width:=200;
|
|
c.AutoSize:=true;
|
|
|
|
finally
|
|
lvstacktracedata.Columns.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
if frmstacktrace=nil then
|
|
frmstacktrace:=tfrmstacktrace.create(self);
|
|
|
|
|
|
lvstacktracedata.Items.Count:=frmstacktrace.ListView1.Items.Count;
|
|
end
|
|
else
|
|
begin
|
|
//setup view for stackview if it isn't setup yet
|
|
if lvStacktraceData.columns.Count<>3 then
|
|
begin
|
|
lvstacktracedata.Columns.BeginUpdate;
|
|
try
|
|
lvstacktracedata.Columns.Clear;
|
|
c:=lvstacktracedata.Columns.Add;
|
|
c.Caption:=rsAddress;
|
|
c.Width:=80;
|
|
c:=lvstacktracedata.Columns.Add;
|
|
if processhandler.is64bit then
|
|
begin
|
|
c.Caption:='QWORD';
|
|
c.width:=160;
|
|
end
|
|
else
|
|
begin
|
|
c.Caption:='DWORD';
|
|
c.Width:=80;
|
|
end;
|
|
|
|
c:=lvstacktracedata.Columns.Add;
|
|
c.Caption:=rsValue;
|
|
c.Width:=100;
|
|
c.AutoSize:=true;
|
|
finally
|
|
lvstacktracedata.Columns.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
if all1.checked =false then
|
|
begin
|
|
//just get the list
|
|
getmem(s,FStacktraceSize);
|
|
try
|
|
|
|
readprocessmemory(processhandle, pointer(contexthandler.StackPointerRegister^.getValue(context)),s, FStacktraceSize,x);
|
|
strace.Clear;
|
|
|
|
if miAddESP.checked then
|
|
begin
|
|
refname:=lowercase(contexthandler.StackPointerRegister^.name);
|
|
refaddress:=contexthandler.StackPointerRegister^.getValue(context);
|
|
end
|
|
else
|
|
if (processhandler.SystemArchitecture=archX86) and miAddEBP.checked then
|
|
begin
|
|
refname:='rbp';
|
|
if not processhandler.is64Bit then
|
|
refname[1]:='e';
|
|
|
|
refaddress:=contexthandler.getRegister(refname)^.getValue(context);
|
|
end
|
|
else
|
|
if miAddRef.checked then
|
|
begin
|
|
refname:=' ';
|
|
refaddress:=StackReference;
|
|
end;
|
|
|
|
if processhandler.SystemArchitecture=archX86 then
|
|
ce_stacktrace(contexthandler.StackPointerRegister^.getValue(context), pcontext(context)^.{$ifdef cpu64}rbp{$else}ebp{$endif}, contexthandler.InstructionPointerRegister^.getValue(context), pbytearray(s),x, strace,false,Nonsystemmodulesonly1.checked or modulesonly1.Checked,Nonsystemmodulesonly1.checked,0,refaddress,refname);
|
|
|
|
|
|
lvstacktracedata.Items.Count:=strace.Count;
|
|
finally
|
|
freememandnil(s);
|
|
|
|
end;
|
|
end else
|
|
begin
|
|
lvstacktracedata.Items.Count:=(FStacktraceSize div processhandler.pointersize)-1;
|
|
end;
|
|
|
|
end;
|
|
finally
|
|
lvStacktraceData.Refresh;
|
|
lvStacktraceData.Items.EndUpdate;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Maxstacktracesize1Click(Sender: TObject);
|
|
var
|
|
s: string;
|
|
begin
|
|
s:=inttostr(stacktraceSize);
|
|
InputQuery(rsStacktrace, rsNewSize+':', s);
|
|
try
|
|
stacktraceSize:=strtoint(s);
|
|
Maxstacktracesize1.Caption:=rsMaxStacktraceSize+': '+inttostr(stacktracesize);
|
|
except
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.All1Click(Sender: TObject);
|
|
begin
|
|
all1.checked:=true;
|
|
Modulesonly1.Checked:=false;
|
|
Nonsystemmodulesonly1.Checked:=false;
|
|
stacktrace2.Checked:=false;
|
|
reloadstacktrace;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Modulesonly1Click(Sender: TObject);
|
|
begin
|
|
all1.checked:=false;
|
|
Modulesonly1.Checked:=true;
|
|
Nonsystemmodulesonly1.Checked:=false;
|
|
stacktrace2.Checked:=false;
|
|
reloadstacktrace;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Nonsystemmodulesonly1Click(Sender: TObject);
|
|
begin
|
|
all1.checked:=false;
|
|
Modulesonly1.Checked:=false;
|
|
Nonsystemmodulesonly1.Checked:=true;
|
|
stacktrace2.Checked:=false;
|
|
reloadstacktrace;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.stacktrace2Click(Sender: TObject);
|
|
begin
|
|
all1.checked:=false;
|
|
Modulesonly1.Checked:=false;
|
|
Nonsystemmodulesonly1.Checked:=false;
|
|
stacktrace2.Checked:=true;
|
|
reloadstacktrace;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miReferencedFunctionsClick(Sender: TObject);
|
|
begin
|
|
if (dissectcode=nil) then
|
|
begin
|
|
if MessageDlg(rsNeedToRunDissectCode, mtConfirmation, [mbyes, mbno], 0)=mryes then
|
|
begin
|
|
Dissectcode1Click(sender);
|
|
frmDissectCode.ondone:=odOpenReferedFunctionsList;
|
|
frmDissectCode.btnStart.click;
|
|
end;
|
|
end else
|
|
begin
|
|
if frmReferencedFunctions=nil then
|
|
frmReferencedFunctions:=tfrmReferencedFunctions.Create(self);
|
|
|
|
frmReferencedFunctions.Show;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.Referencedstrings1Click(Sender: TObject);
|
|
begin
|
|
|
|
if (dissectcode=nil) then
|
|
begin
|
|
if MessageDlg(rsNeedToRunDissectCode, mtConfirmation, [mbyes, mbno], 0)=mryes then
|
|
begin
|
|
Dissectcode1Click(sender);
|
|
frmDissectCode.ondone:=odOpenReferedStringList;
|
|
frmDissectCode.btnStart.click;
|
|
end;
|
|
end else
|
|
begin
|
|
if frmReferencedStrings=nil then
|
|
frmReferencedStrings:=tfrmReferencedStrings.Create(self);
|
|
|
|
frmReferencedStrings.Show;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TMemoryBrowser.GetReturnaddress: ptrUint;
|
|
var
|
|
haserror: boolean;
|
|
stack: array [0..1023] of ptrUint;
|
|
x: ptrUint;
|
|
i: integer;
|
|
begin
|
|
|
|
result:=0;
|
|
|
|
//do a stacktrace and find the return address
|
|
|
|
if frmstacktrace=nil then
|
|
frmstacktrace:=tfrmstacktrace.create(self);
|
|
|
|
if frmStacktrace.ListView1.Items.Count>0 then
|
|
begin
|
|
result:=symhandler.getAddressFromName(frmStacktrace.ListView1.Items[0].SubItems[2], false,haserror);
|
|
if haserror then result:=0;
|
|
end;
|
|
|
|
if result=0 then
|
|
begin
|
|
|
|
//go through the stack and find a entry that falls in executable memory
|
|
ReadProcessMemory(processhandle, pointer(contexthandler.StackPointerRegister^.getValue(context)), @stack[0], 4096, x);
|
|
for i:=0 to (x div processhandler.pointersize) do
|
|
begin
|
|
if symhandler.inModule(stack[i]) and isExecutableAddress(stack[i]) then
|
|
begin
|
|
result:=stack[i]; //best guess, it's an address specifier, it falls inside a module, and it's executable
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.miDebugExecuteTillReturnClick(Sender: TObject);
|
|
var x: ptrUint;
|
|
begin
|
|
begin
|
|
x:=getreturnaddress;
|
|
if x>0 then
|
|
begin
|
|
disassemblerview.SelectedAddress:=x;
|
|
miDebugRunTill.Click;
|
|
end else beep; //not possible
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.lvStacktraceDataData(Sender: TObject; Item: TListItem);
|
|
var
|
|
x: dword;
|
|
value: ptrUint;
|
|
a: ptrUint;
|
|
address,bytes,details: string;
|
|
v: TVariableType;
|
|
pref: string;
|
|
|
|
offset: ptrint;
|
|
offsetstring: string;
|
|
|
|
refname: string;
|
|
begin
|
|
|
|
if stacktrace2.checked then
|
|
begin
|
|
|
|
//show frmstacktrace
|
|
if frmStacktrace=nil then
|
|
begin
|
|
frmstacktrace:=TfrmStacktrace.Create(self); //should never happen
|
|
end;
|
|
|
|
if item.Index<frmStacktrace.ListView1.Items.Count then
|
|
begin
|
|
item.data:=frmStacktrace.ListView1.Items[item.index].Data;
|
|
item.Caption:=frmStacktrace.ListView1.Items[item.index].SubItems[2]; //returnaddress
|
|
item.SubItems.Add(frmStacktrace.ListView1.Items[item.index].SubItems[3]); //subitems address
|
|
end;
|
|
end
|
|
else
|
|
if all1.checked then
|
|
begin
|
|
//show for each dword what it is
|
|
|
|
|
|
a:=contexthandler.StackPointerRegister^.getValue(context)+item.Index*processhandler.pointersize;
|
|
|
|
if laststack<>nil then
|
|
begin
|
|
if processhandler.is64bit then
|
|
begin
|
|
pref:='r';
|
|
value:=ptruint(pqword(ptruint(laststack)+item.Index*processhandler.pointersize)^);
|
|
item.SubItems.Add(inttohex(value,16));
|
|
end
|
|
else
|
|
begin
|
|
pref:='e';
|
|
value:=ptruint(pdword(ptruint(laststack)+item.Index*processhandler.pointersize)^);
|
|
item.SubItems.Add(inttohex(value,8));
|
|
end;
|
|
|
|
if miAddESP.checked then
|
|
offsetstring:='('+pref+'sp+'+inttohex(item.Index*processhandler.pointersize,1)+')'
|
|
else
|
|
begin
|
|
|
|
|
|
if miAddRef.checked then
|
|
begin
|
|
offset:=a-StackReference;
|
|
refname:=' ';
|
|
end
|
|
else
|
|
begin
|
|
if processhandler.SystemArchitecture=archX86 then
|
|
begin
|
|
offset:=a-PCONTEXT(context)^.{$ifdef cpu64}rbp{$else}Ebp{$endif};
|
|
refname:=pref+'bp';
|
|
end
|
|
else
|
|
begin
|
|
offset:=a-StackReference;
|
|
refname:=' ';
|
|
end;
|
|
|
|
end;
|
|
|
|
if offset<0 then
|
|
offsetstring:='('+refname+'-'+inttohex(-offset,1)+')'
|
|
else
|
|
offsetstring:='('+refname+'+'+inttohex(offset,1)+')';
|
|
end;
|
|
|
|
|
|
item.Caption:=inttohex(a,8)+offsetstring;
|
|
|
|
|
|
|
|
|
|
|
|
v:=FindTypeOfData(a,pointer(ptruint(laststack)+item.Index*processhandler.pointersize),StacktraceSize-item.Index*processhandler.pointersize);
|
|
if v in [vtbyte..vtQword] then
|
|
begin
|
|
//override into pointersize type
|
|
if processhandler.is64bit then
|
|
v:=vtQword
|
|
else
|
|
v:=vtDword;
|
|
end;
|
|
|
|
item.SubItems.Add(DataToString(pbytearray(ptruint(laststack)+item.Index*processhandler.pointersize),processhandler.pointersize, v));
|
|
end;
|
|
end else
|
|
begin
|
|
//show strace
|
|
|
|
if strace<>nil then
|
|
begin
|
|
if item.index<strace.count then
|
|
begin
|
|
seperatestacktraceline(strace[item.index], address,bytes,details);
|
|
item.Caption:=address;
|
|
item.SubItems.Add(bytes);
|
|
item.SubItems.Add(details);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.lvStacktraceDataDblClick(Sender: TObject);
|
|
var
|
|
hasError: boolean;
|
|
x: ptrUint;
|
|
|
|
column : integer;
|
|
cursorpos: tpoint;
|
|
tvrect: trect;
|
|
i: integer;
|
|
|
|
currentleft: integer;
|
|
s: string;
|
|
ksh: TShiftState;
|
|
|
|
pointed: TListItem;
|
|
mp: tpoint;
|
|
begin
|
|
mp:=mouse.CursorPos;
|
|
mp:=lvStacktraceData.ScreenToControl(mp);
|
|
|
|
pointed:=lvStacktraceData.GetItemAt(mp.x,mp.y);
|
|
|
|
if pointed=nil then
|
|
pointed:=lvStacktraceData.Selected;
|
|
|
|
if pointed=nil then exit;
|
|
|
|
if stacktrace2.checked then
|
|
begin
|
|
//go to the selected address
|
|
|
|
disassemblerview.SelectedAddress:=ptruint(pointed.Data);
|
|
end
|
|
else
|
|
begin
|
|
//depending on what column is selected go to the disassembler/hexview part
|
|
cursorpos:=mp;
|
|
|
|
column:=0;
|
|
|
|
currentleft:=0;
|
|
for i:=0 to lvStacktraceData.Columns.count-1 do
|
|
begin
|
|
if (cursorpos.X>currentleft) and (cursorpos.X<(currentleft+lvStacktraceData.Columns[i].width)) then
|
|
begin
|
|
column:=i;
|
|
break;
|
|
end;
|
|
inc(currentleft, lvStacktraceData.Columns[i].width);
|
|
end;
|
|
|
|
|
|
if column=0 then
|
|
begin
|
|
s:=pointed.Caption;
|
|
i:=pos('(', s);
|
|
if i>0 then
|
|
s:=copy(s,1,i-1);
|
|
|
|
end
|
|
else
|
|
s:=pointed.SubItems[column-1];
|
|
|
|
x:=symhandler.getAddressFromName(s,false,haserror);
|
|
if not haserror then
|
|
begin
|
|
ksh:=GetKeyShiftState;
|
|
if ssShift in ksh then
|
|
begin
|
|
disassemblerview.SelectedAddress:=x
|
|
end
|
|
else
|
|
if ssCtrl in ksh then
|
|
begin
|
|
hexview.AddToBackList(pointer(memoryaddress));
|
|
memoryaddress:=x;
|
|
end
|
|
else
|
|
if isExecutableAddress(x) then
|
|
begin
|
|
disassemblerview.SelectedAddress:=x
|
|
end
|
|
else
|
|
begin
|
|
hexview.AddToBackList(pointer(memoryaddress));
|
|
memoryaddress:=x;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.setHexviewAddress(a: ptrUint);
|
|
begin
|
|
if hexview<>nil then
|
|
hexview.address:=a;
|
|
end;
|
|
|
|
function TMemoryBrowser.getHexviewAddress:ptrUint;
|
|
begin
|
|
if hexview<>nil then
|
|
result:=hexview.address
|
|
else
|
|
result:=0;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.OnMemoryViewerRunning;
|
|
begin
|
|
{Disable debug functions & toolbar}
|
|
//tbDebug.enabled:=false; //disable toolbar
|
|
tbRun.Enabled:=false; //disable toolbar run button
|
|
tbStepInto.Enabled:=false; //disable toolbar step into button
|
|
tbStepOver.Enabled:=false; //disable toolbar step over button
|
|
tbStepOut.Enabled:=false; //disable toolbar step out button
|
|
tbRunTill.Enabled:=false;
|
|
miDebugRun.Enabled:=false;
|
|
miRunUnhandled.Enabled:=false;
|
|
miRunUnhandled.Visible:=false;
|
|
miDebugStep.Enabled:=false;
|
|
miDebugStepOver.Enabled:=false;
|
|
miDebugRunTill.Enabled:=false;
|
|
miDebugSetAddress.enabled:=false;
|
|
stacktrace1.Enabled:=false;
|
|
miDebugExecuteTillReturn.Enabled:=false;
|
|
|
|
ApplySourceCodeDebugUpdate;
|
|
{Other tasks}
|
|
//...
|
|
end;
|
|
|
|
|
|
procedure setControlFontKeepColor(c: TWinControl; f: TFont);
|
|
var
|
|
i: integer;
|
|
oldc: tcolor;
|
|
tc: TControl;
|
|
tw: TWinControl absolute tc;
|
|
begin
|
|
oldc:=c.font.color;
|
|
c.Font.assign(f);
|
|
c.font.color:=oldc;
|
|
|
|
for i:=0 to c.ControlCount-1 do
|
|
begin
|
|
tc:=c.Controls[i];
|
|
if (tc is TWinControl) and (tw.Controlcount>0) then
|
|
setControlFontKeepColor(tw,f);
|
|
|
|
if tc is TControl then
|
|
begin
|
|
oldc:=tc.font.color;
|
|
tc.Font.assign(f);
|
|
tc.font.color:=oldc;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.setRegisterPanelFont(f: TFont);
|
|
begin
|
|
registerpanelfont.Assign(f);
|
|
scrollbox1.ControlCount;
|
|
setControlFontKeepColor(scrollbox1,f);
|
|
end;
|
|
|
|
procedure TMemoryBrowser.showDebugPaneltimertimer(sender: tobject);
|
|
begin
|
|
showdebugpaneltimer.enabled:=false;
|
|
showDebugPanels:=true;
|
|
registerview.ClientWidth:=lblFlags.left+lblFlags.width+16+scrollbox1.VertScrollBar.Size;
|
|
scrollbox1.HorzScrollBar.Visible:=false;
|
|
scrollbox1.Invalidate;
|
|
end;
|
|
|
|
procedure TMemoryBrowser.UpdateDebugContext(threadhandle: THandle; threadid: dword; changeselection: boolean=true; _debuggerthread: TDebuggerThread=nil);
|
|
var temp: string='';
|
|
temp2: string;
|
|
Regstart: string='';
|
|
charcount: integer=8;
|
|
bs: dword;
|
|
x: ptrUint;
|
|
stackaddress: PtrUInt;
|
|
i: integer=0;
|
|
a: ptruint;
|
|
a64: int64;
|
|
d: TDisassembler;
|
|
|
|
params: string;
|
|
accessedreglist: tstringlist=nil;
|
|
|
|
oldcontexthandler: TContextInfo;
|
|
|
|
l: TLabel;
|
|
gprlist, flaglist, speciallist: PContextElementRegisterList;
|
|
|
|
cer: PContextElement_register;
|
|
|
|
iptlog: pointer;
|
|
iptlogsize: integer;
|
|
begin
|
|
if _debuggerthread<>nil then debuggerthread.execlocation:=41301;
|
|
|
|
|
|
|
|
|
|
|
|
oldcontexthandler:=contexthandler;
|
|
contexthandler:=getBestContextHandler;
|
|
|
|
if processhandler.SystemArchitecture=archX86 then
|
|
begin
|
|
a:=contexthandler.InstructionPointerRegister^.getValue(context);
|
|
d:=TDisassembler.create;
|
|
|
|
d.disassemble(a, temp);
|
|
params:=d.LastDisassembleData.parameters;
|
|
accessedreglist:=tstringlist.create;
|
|
accessedreglist.Sorted:=true;
|
|
accessedreglist.Duplicates:=dupIgnore;
|
|
getRegisterListFromParams(params, accessedreglist); //todo: get more data when disassembling
|
|
|
|
d.free;
|
|
d:=nil;
|
|
end;
|
|
|
|
if frmThreadlist<>nil then
|
|
frmThreadlist.FillThreadlist;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41302;
|
|
|
|
|
|
|
|
if contexthandler<>oldcontexthandler then
|
|
begin
|
|
//rebuild the registerlist
|
|
self.BeginFormUpdate;
|
|
try
|
|
while pnlGeneralRegisters.ControlCount>0 do
|
|
pnlGeneralRegisters.Controls[0].Free;
|
|
|
|
while pnlFlags.ControlCount>0 do
|
|
pnlFlags.Controls[0].Free;
|
|
|
|
while pnlExtraRegisters.ControlCount>0 do
|
|
pnlExtraRegisters.Controls[0].Free;
|
|
|
|
gprlist:=contexthandler.getGeneralPurposeRegisters;
|
|
if gprlist<>nil then
|
|
begin
|
|
lblRegisters.visible:=true;
|
|
sRegisters.visible:=true;
|
|
pnlGeneralRegisters.visible:=true;
|
|
|
|
for i:=0 to length(gprlist^)-1 do
|
|
begin
|
|
l:=tlabel.create(self);
|
|
l.Caption:=gprlist^[i].name;
|
|
l.parent:=pnlGeneralRegisters;
|
|
l.Cursor:=crHandPoint;
|
|
l.Tag:=ptruint(@gprlist^[i]);
|
|
l.PopupMenu:=pmRegisters;
|
|
l.onclick:=RegisterLabelDblClick;
|
|
l.OnMouseDown:=RegisterMouseDown;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
lblRegisters.visible:=false;
|
|
sRegisters.visible:=false;
|
|
pnlGeneralRegisters.visible:=false;
|
|
end;
|
|
|
|
flaglist:=contexthandler.getGeneralPurposeFlags;
|
|
if flaglist<>nil then
|
|
begin
|
|
lblFlags.visible:=true;
|
|
sflags.visible:=true;
|
|
pnlFlags.visible:=true;
|
|
|
|
for i:=0 to length(flaglist^)-1 do
|
|
begin
|
|
l:=tlabel.create(self);
|
|
l.Caption:=flaglist^[i].name;
|
|
l.parent:=pnlFlags;
|
|
l.Cursor:=crHandPoint;
|
|
l.Tag:=ptruint(@flaglist^[i]);
|
|
l.PopupMenu:=pmRegisters;
|
|
l.onclick:=RegisterLabelDblClick;
|
|
l.OnMouseDown:=RegisterMouseDown;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
lblFlags.visible:=false;
|
|
sflags.visible:=false;
|
|
pnlFlags.visible:=false;
|
|
end;
|
|
|
|
speciallist:=contexthandler.getSpecializedRegisters;
|
|
if speciallist<>nil then
|
|
begin
|
|
lblSpecial.visible:=true;
|
|
sSpecial.visible:=true;
|
|
pnlExtraRegisters.visible:=true;
|
|
|
|
for i:=0 to length(speciallist^)-1 do
|
|
begin
|
|
l:=tlabel.create(self);
|
|
l.Caption:=flaglist^[i].name;
|
|
l.parent:=pnlExtraRegisters;
|
|
l.Cursor:=crHandPoint;
|
|
l.Tag:=ptruint(@speciallist^[i]);
|
|
l.PopupMenu:=pmRegisters;
|
|
l.onclick:=RegisterLabelDblClick;
|
|
l.OnMouseDown:=RegisterMouseDown;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
lblSpecial.visible:=false;
|
|
sSpecial.visible:=false;
|
|
pnlExtraRegisters.visible:=false;
|
|
end;
|
|
|
|
finally
|
|
EndFormUpdate;
|
|
end;
|
|
|
|
end;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41303;
|
|
|
|
{}
|
|
if (accessedreglist<>nil) then
|
|
begin
|
|
for i:=0 to pnlGeneralRegisters.ControlCount-1 do
|
|
begin
|
|
l:=tlabel(pnlGeneralRegisters.Controls[i]);
|
|
if accessedreglist.IndexOf(PContextElement_register(l.Tag).name)>=0 then l.color:=fAccessedRegisterColor else l.color:=clNone;
|
|
end;
|
|
|
|
end;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41304;
|
|
|
|
//tbDebug.enabled:=true;
|
|
if (tbDebug.visible=false) and (tbDebug.Tag<>-1) then
|
|
ShowDebugToolbar; //show toolbar
|
|
|
|
miDebugRun.Enabled:=true;
|
|
tbRun.Enabled:=true; //enable toolbar run button
|
|
|
|
if debuggerthread=nil then exit;
|
|
|
|
|
|
miRunUnhandled.Enabled:=(debuggerthread.CurrentThread<>nil) and debuggerthread.CurrentThread.isUnhandledException;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41305;
|
|
miRunUnhandled.Visible:=miRunUnhandled.Enabled;
|
|
tbRunUnhandled.enabled:=miRunUnhandled.enabled;
|
|
tbRunUnhandled.visible:=miRunUnhandled.enabled;
|
|
|
|
miDebugStep.Enabled:=true;
|
|
tbStepInto.Enabled:=true; //enable toolbar step into button
|
|
miDebugStepOver.Enabled:=true;
|
|
tbStepOver.Enabled:=true; //enable toolbar step over button
|
|
miDebugRunTill.Enabled:=true;
|
|
tbRunTill.Enabled:=true;
|
|
tbStepOut.Enabled:=true; //enable toolbar step out button
|
|
miDebugSetAddress.enabled:=true;
|
|
stacktrace1.Enabled:=true;
|
|
miDebugExecuteTillReturn.Enabled:=true;
|
|
|
|
|
|
|
|
|
|
if threadid<>0 then
|
|
caption:=Format(rsMemoryViewerCurrentlyDebuggingThread, [inttohex(threadid, 1)]);
|
|
|
|
if (debuggerthread.CurrentThread<>nil) and debuggerthread.CurrentThread.isUnhandledException then
|
|
caption:=caption+' '+format(rsBecauseOfUnhandledExeption, [ExceptionCodeToString(debuggerthread.CurrentThread.lastUnhandledExceptionCode)]);
|
|
|
|
if (frmstacktrace<>nil) then
|
|
begin
|
|
if (threadhandle=0) and (debuggerthread<>nil) and (debuggerthread.CurrentThread<>nil) then
|
|
threadhandle:=debuggerthread.CurrentThread.handle;
|
|
|
|
frmstacktrace.stacktrace(threadhandle, context);
|
|
end;
|
|
|
|
if changeselection then
|
|
begin
|
|
disassemblerview.SelectedAddress:=contexthandler.InstructionPointerRegister^.getValue(context);
|
|
end;
|
|
|
|
{}
|
|
|
|
//apply the values
|
|
if pnlGeneralRegisters.visible then
|
|
begin
|
|
for i:=0 to pnlGeneralRegisters.ControlCount-1 do
|
|
begin
|
|
l:=tlabel(pnlGeneralRegisters.controls[i]);
|
|
cer:=PContextElement_register(l.tag);
|
|
|
|
temp:=padleft(cer^.name, contexthandler.GeneralPurposeRegisterMaxCharCount)+' '+cer^.getFullValueString(context);
|
|
if temp<>l.caption then
|
|
begin
|
|
l.Font.Color:=fChangedRegisterColor;
|
|
l.Caption:=temp;
|
|
end
|
|
else
|
|
l.Font.Color:=clWindowText;
|
|
end;
|
|
end;
|
|
|
|
if pnlFlags.visible then
|
|
begin
|
|
for i:=0 to pnlFlags.ControlCount-1 do
|
|
begin
|
|
l:=tlabel(pnlFlags.controls[i]);
|
|
cer:=PContextElement_register(l.tag);
|
|
temp:=padleft(cer^.name, contexthandler.GeneralPurposeFlagMaxCharCount)+' '+cer^.getFlag(context).ToString;
|
|
if temp<>l.caption then
|
|
begin
|
|
l.Font.Color:=fChangedRegisterColor;
|
|
l.Caption:=temp;
|
|
end
|
|
else
|
|
l.Font.Color:=clWindowText;
|
|
end;
|
|
end;
|
|
|
|
if pnlExtraRegisters.Visible then
|
|
begin
|
|
for i:=0 to pnlExtraRegisters.ControlCount-1 do
|
|
begin
|
|
l:=tlabel(pnlExtraRegisters.controls[i]);
|
|
cer:=PContextElement_register(l.tag);
|
|
temp:=padleft(cer^.name, contexthandler.GeneralPurposeRegisterMaxCharCount)+' '+cer^.getValueString(context);
|
|
if temp<>l.caption then
|
|
begin
|
|
l.Font.Color:=fChangedRegisterColor;
|
|
l.Caption:=temp;
|
|
end
|
|
else
|
|
l.Font.Color:=clWindowText;
|
|
end;
|
|
end;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41308;
|
|
{}
|
|
|
|
sbShowFloats.BringToFront;
|
|
//sbShowFloats.visible:=true;
|
|
|
|
if not registerview.visible then
|
|
begin
|
|
showdebugpaneltimer:=ttimer.Create(self);
|
|
showDebugPaneltimer.interval:=1;
|
|
showDebugPaneltimer.OnTimer:=showDebugPaneltimertimer;
|
|
showDebugPaneltimer.enabled:=true;
|
|
|
|
//tthread.Queue(nil, doshowdebugpanels);
|
|
|
|
|
|
end;
|
|
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41309;
|
|
|
|
if laststack=nil then
|
|
getmem(laststack,stacktraceSize+64);
|
|
|
|
|
|
//get a stackview
|
|
i:=0;
|
|
stackaddress:=contexthandler.StackPointerRegister^.getValue(context);
|
|
while i<stacktracesize do
|
|
begin
|
|
bs:=4096-((stackaddress+i) mod 4096);
|
|
bs:=min(stacktraceSize-i, bs);
|
|
|
|
|
|
readprocessmemory(processhandle, pointer(stackaddress+i), pointer(ptruint(laststack)+i), bs, x);
|
|
|
|
inc(i,bs);
|
|
end;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41310;
|
|
|
|
reloadStacktrace;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41311;
|
|
|
|
if frmFloatingPointPanel<>nil then
|
|
frmFloatingPointPanel.SetContextPointer(context);
|
|
|
|
|
|
if not memorybrowser.Visible then
|
|
memorybrowser.show;
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41312;
|
|
|
|
if (frmWatchlist<>nil) and (frmWatchlist.Visible) then
|
|
frmWatchlist.UpdateContext(context);
|
|
|
|
if accessedreglist<>nil then
|
|
freeandnil(accessedreglist);
|
|
|
|
if _debuggerthread<>nil then _debuggerthread.execlocation:=41313;
|
|
|
|
|
|
{$IFDEF WINDOWS}
|
|
if (debuggerthread<>nil) and debuggerthread.usingIPT and (frmiptlog<>nil) and (frmiptlog.visible) and (debuggerthread.CurrentThread<>nil) then
|
|
begin
|
|
debuggerthread.CurrentThread.getLastIPTLog(iptlog,iptlogsize);
|
|
frmiptlog.loadlog('',iptlog, iptlogsize);
|
|
freemem(iptlog);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
registerview.OnResize(registerview);
|
|
|
|
|
|
ApplyFollowRegister;
|
|
ApplySourceCodeDebugUpdate;
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
MemoryBrowsers:=TList.Create;
|
|
|
|
{$i MemoryBrowserFormUnit.lrs}
|
|
|
|
finalization
|
|
if MemoryBrowsers<>nil then
|
|
FreeAndNil(MemoryBrowsers);
|
|
|
|
|
|
end.
|