From d5fe49d0072005705781bb90d090d50654bf8c0e Mon Sep 17 00:00:00 2001 From: cheat-engine Date: Sat, 13 Mar 2021 18:19:20 -0800 Subject: [PATCH] add a cr3 switcher for individual memoryview windows --- Cheat Engine/LuaHandler.pas | 2 +- Cheat Engine/MainUnit2.pas | 1 + Cheat Engine/MemoryBrowserFormUnit.lfm | 9 +- Cheat Engine/MemoryBrowserFormUnit.pas | 108 +++++++++++++- Cheat Engine/NewKernelHandler.pas | 2 +- Cheat Engine/cheatengine.lpi | 12 +- Cheat Engine/cheatengine.lpr | 3 +- Cheat Engine/dbk32/DBK32functions.pas | 11 +- Cheat Engine/dbvmdebuggerinterface.pas | 6 +- Cheat Engine/debugeventhandler.pas | 22 ++- Cheat Engine/debughelper.pas | 17 ++- Cheat Engine/disassemblerviewlinesunit.pas | 34 +++-- Cheat Engine/disassemblerviewunit.pas | 35 ++++- Cheat Engine/frmcr3switcherunit.lfm | 91 ++++++++++++ Cheat Engine/frmcr3switcherunit.pas | 163 +++++++++++++++++++++ Cheat Engine/hexviewunit.pas | 47 +++++- 16 files changed, 521 insertions(+), 42 deletions(-) create mode 100644 Cheat Engine/frmcr3switcherunit.lfm create mode 100644 Cheat Engine/frmcr3switcherunit.pas diff --git a/Cheat Engine/LuaHandler.pas b/Cheat Engine/LuaHandler.pas index 8a27e493bb..2d0b83ee7d 100755 --- a/Cheat Engine/LuaHandler.pas +++ b/Cheat Engine/LuaHandler.pas @@ -7311,7 +7311,7 @@ function lua_dbvm_bp_setBrokenThreadEventFull(L: PLua_state): integer; cdecl; if not lua_isnil(L,-1) then state.basic.R9:=lua_tointeger(L,-1); lua_pop(L,1); - lua_pushstring(L,'R0'); + lua_pushstring(L,'R10'); lua_gettable(L,2); if not lua_isnil(L,-1) then state.basic.R10:=lua_tointeger(L,-1); lua_pop(L,1); diff --git a/Cheat Engine/MainUnit2.pas b/Cheat Engine/MainUnit2.pas index e56e7dcdb9..6a0d5236b8 100755 --- a/Cheat Engine/MainUnit2.pas +++ b/Cheat Engine/MainUnit2.pas @@ -1086,6 +1086,7 @@ procedure LoadSettingsFromRegistry(skipPlugins: boolean=false); MemoryBrowser.Kerneltools1.visible:=false; {$else} MemoryBrowser.Kerneltools1.Enabled:={$ifdef windows}DBKLoaded or isRunningDBVM{$else}false{$endif}; + MemoryBrowser.miCR3Switcher.visible:=MemoryBrowser.Kerneltools1.Enabled; {$endif} diff --git a/Cheat Engine/MemoryBrowserFormUnit.lfm b/Cheat Engine/MemoryBrowserFormUnit.lfm index c14c98d39b..338a2aaa54 100755 --- a/Cheat Engine/MemoryBrowserFormUnit.lfm +++ b/Cheat Engine/MemoryBrowserFormUnit.lfm @@ -1,7 +1,7 @@ object MemoryBrowser: TMemoryBrowser - Left = 403 + Left = 627 Height = 536 - Top = 95 + Top = 107 Width = 643 HelpContext = 12 Caption = 'Memory Viewer' @@ -1679,6 +1679,11 @@ object MemoryBrowser: TMemoryBrowser OnClick = miBinutilsSelectClick end end + object miCR3Switcher: TMenuItem + Caption = 'CR3 Switcher' + Visible = False + OnClick = miCR3SwitcherClick + end object miTextPreferences: TMenuItem Caption = 'Preferences' ImageIndex = 40 diff --git a/Cheat Engine/MemoryBrowserFormUnit.pas b/Cheat Engine/MemoryBrowserFormUnit.pas index 065b997e07..f871dcb63a 100755 --- a/Cheat Engine/MemoryBrowserFormUnit.pas +++ b/Cheat Engine/MemoryBrowserFormUnit.pas @@ -20,7 +20,8 @@ interface debughelper, debuggertypedefinitions,frmMemviewPreferencesUnit, registry, disassemblerComments, multilineinputqueryunit, frmMemoryViewExUnit, LastDisassembleData, ProcessHandlerUnit, commonTypeDefs, binutils, - fontSaveLoadRegistry, LazFileUtils, ceregistry, betterControls,ScrollBoxEx; + fontSaveLoadRegistry, LazFileUtils, ceregistry, frmCR3SwitcherUnit, + betterControls, ScrollBoxEx; type @@ -48,6 +49,7 @@ TMemoryBrowser = class(TForm) GSlabel: TLabel; MenuItem4: TMenuItem; copyBytesAndOpcodesAndComments: TMenuItem; + miCR3Switcher: TMenuItem; miShowSectionAddresses: TMenuItem; miOpenInDissectData: TMenuItem; miCopyOpcodesOnly: TMenuItem; @@ -342,6 +344,7 @@ TMemoryBrowser = class(TForm) procedure MenuItem11Click(Sender: TObject); procedure MenuItem12Click(Sender: TObject); procedure MenuItem14Click(Sender: TObject); + procedure miCR3SwitcherClick(Sender: TObject); procedure miDBVMFindoutwhataddressesthisinstructionaccessesClick(Sender: TObject); procedure MenuItem4Click(Sender: TObject); procedure miOpenInDissectDataClick(Sender: TObject); @@ -610,6 +613,10 @@ TMemoryBrowser = class(TForm) preferedF5BreakpointMethod: TBreakpointMethod; followRegister: integer; + + fcr3: qword; + fcr3switcher: TfrmCR3Switcher; + procedure cr3switcherCR3Change(sender: TObject); procedure SetStacktraceSize(size: integer); procedure setShowDebugPanels(state: boolean); function getShowValues: boolean; @@ -623,6 +630,12 @@ TMemoryBrowser = class(TForm) procedure setContextValueByTag(value: ptruint; tag: integer); function getContextValueByTag(tag: integer): ptruint; 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; @@ -675,6 +688,9 @@ TMemoryBrowser = class(TForm) procedure miStopDifferenceClick(Sender: TObject); procedure Scrollboxscroll(sender: TObject); procedure AddToDisassemblerBackList(address: pointer); + + procedure createcr3switcher; + property cr3switcher: TfrmCR3Switcher read fcr3switcher; published //support for old scripts that reference these property Run1: TMenuItem read miDebugRun; @@ -690,6 +706,8 @@ TMemoryBrowser = class(TForm) 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 @@ -859,9 +877,41 @@ procedure TMemoryBrowser.SetStacktraceSize(size: integer); 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:=newkernelhandler.ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead) + else + result:=ReadProcessMemoryCR3(fcr3,lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead); +end; + + procedure TMemoryBrowser.Splitter1Moved(Sender: TObject); begin @@ -1183,6 +1233,45 @@ procedure TMemoryBrowser.MenuItem14Click(Sender: TObject); EnableWindowsSymbols(true); end; +procedure TMemorybrowser.setCR3(newcr3: qword); +begin + fcr3:=newcr3; + disassemblerview.cr3:=fcr3; + hexview.cr3:=fcr3; + + if newcr3<>0 then + begin + createcr3switcher; + fcr3switcher.addCR3ToList(newcr3); + + fcr3switcher.Show; + 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); @@ -3361,10 +3450,17 @@ procedure TMemoryBrowser.AssemblePopup(x:string); bytelength:=length(bytes); - vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(Address),bytelength,PAGE_EXECUTE_READWRITE,p); - WriteProcessMemoryWithCloakSupport(processhandle,pointer(Address),@bytes[0],bytelength,a); - if vpe then - VirtualProtectEx(processhandle,pointer(Address),bytelength,p,p); + if fcr3=0 then + begin + vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(Address),bytelength,PAGE_EXECUTE_READWRITE,p); + WriteProcessMemoryWithCloakSupport(processhandle,pointer(Address),@bytes[0],bytelength,a); + if vpe then + VirtualProtectEx(processhandle,pointer(Address),bytelength,p,p); + end + else + begin + WriteProcessMemoryCR3(fcr3, pointer(address),@bytes[0], bytelength,a); + end; hexview.update; disassemblerview.Update; @@ -4527,7 +4623,7 @@ procedure TMemoryBrowser.Newwindow1Click(Sender: TObject); caption:=caption+'* ('+ns+')'; Kerneltools1.enabled:=memorybrowser.Kerneltools1.enabled; - + miCR3Switcher.visible:=Kerneltools1.Enabled; ischild:=true; show; end; diff --git a/Cheat Engine/NewKernelHandler.pas b/Cheat Engine/NewKernelHandler.pas index 90e0e93d0b..fce18d441f 100755 --- a/Cheat Engine/NewKernelHandler.pas +++ b/Cheat Engine/NewKernelHandler.pas @@ -1618,7 +1618,7 @@ procedure LoadDBK32; stdcall; {$endif} MemoryBrowser.Kerneltools1.Enabled:=DBKLoaded or isRunningDBVM; - + MemoryBrowser.miCR3Switcher.visible:=MemoryBrowser.Kerneltools1.Enabled; end; {$endif} end; diff --git a/Cheat Engine/cheatengine.lpi b/Cheat Engine/cheatengine.lpi index 96f4f7ff9f..d34d1a24c4 100755 --- a/Cheat Engine/cheatengine.lpi +++ b/Cheat Engine/cheatengine.lpi @@ -26,7 +26,7 @@ - + @@ -639,7 +639,7 @@ - + @@ -2778,6 +2778,14 @@ + + + + + + + + diff --git a/Cheat Engine/cheatengine.lpr b/Cheat Engine/cheatengine.lpr index 7541a50e90..cd3b6c7234 100755 --- a/Cheat Engine/cheatengine.lpr +++ b/Cheat Engine/cheatengine.lpr @@ -116,7 +116,8 @@ frmMicrotransactionsUnit, frmSyntaxHighlighterEditor, LuaCustomImageList, dotnethost, rttihelper, cefreetype, LuaDotNetPipe, LuaRemoteExecutor, newRadioButton, newCheckbox, newbutton, autoassemblercode, CSharpCompiler, - newhintwindow, memrecDataStructures, LuaCECustomButton, DBVMDebuggerInterface; + newhintwindow, memrecDataStructures, LuaCECustomButton, DBVMDebuggerInterface, + frmCR3SwitcherUnit; {$R cheatengine.res} {$IFDEF windows} diff --git a/Cheat Engine/dbk32/DBK32functions.pas b/Cheat Engine/dbk32/DBK32functions.pas index 9338dc10d0..4d0548a43f 100755 --- a/Cheat Engine/dbk32/DBK32functions.pas +++ b/Cheat Engine/dbk32/DBK32functions.pas @@ -909,7 +909,7 @@ function GetCR3(hProcess:THANDLE;var CR3:system.QWORD):BOOL; stdcall; x:=l.processid; result:=deviceiocontrol(hdevice,cc,@x,4,@_cr3,8,y,nil); - outputdebugstring(pchar('GetCR3: return '+inttohex(_cr3,16))); + // outputdebugstring(pchar('GetCR3: return '+inttohex(_cr3,16))); if result then CR3:=_cr3 else cr3:=$11223344; end; @@ -949,7 +949,7 @@ function GetCR3FromPID(pid: system.QWORD;var CR3:system.QWORD):BOOL; stdcall; x:=pid; result:=deviceiocontrol(hdevice,cc,@x,4,@_cr3,8,y,nil); - outputdebugstring(pchar('GetCR3: return '+inttohex(_cr3,16))); + //outputdebugstring(pchar('GetCR3: return '+inttohex(_cr3,16))); if (_cr3 and $fff)>0 then begin @@ -1339,6 +1339,13 @@ type TInputstruct=record bufpointer2: pointer; towrite: dword; begin + if vmx_loaded and (dbvm_version>=$ce00000a) then + begin + NumberOfBytesWritten:=dbvm_write_physical_memory(qword(lpBaseAddress), lpBuffer, nSize); + exit(NumberOfBytesWritten=nSize); + end; + + result:=false; NumberOfByteswritten:=0; //find the hprocess in the handlelist, if it isn't use the normal method (I could of course use NtQueryProcessInformation but it's undocumented and I'm too lazy to dig it up diff --git a/Cheat Engine/dbvmdebuggerinterface.pas b/Cheat Engine/dbvmdebuggerinterface.pas index ff2e13e945..5a9073de20 100644 --- a/Cheat Engine/dbvmdebuggerinterface.pas +++ b/Cheat Engine/dbvmdebuggerinterface.pas @@ -132,12 +132,13 @@ function TDBVMDebugInterface.setBreakEvent(var lpDebugEvent: TDebugEvent; frozen lpDebugEvent.Exception.ExceptionRecord.ExceptionAddress:=pointer(currentFrozenState.basic.RIP); lpDebugEvent.Exception.ExceptionRecord.ExceptionCode:=EXCEPTION_DBVM_BREAKPOINT; lpDebugEvent.Exception.ExceptionRecord.ExceptionFlags:=watchid; //-1 when stepping - lpDebugEvent.Exception.ExceptionRecord.NumberParameters:=5; + lpDebugEvent.Exception.ExceptionRecord.NumberParameters:=6; lpDebugEvent.Exception.ExceptionRecord.ExceptionInformation[0]:=frozenThreadID; lpDebugEvent.Exception.ExceptionRecord.ExceptionInformation[1]:=currentFrozenState.basic.CR3; lpDebugEvent.Exception.ExceptionRecord.ExceptionInformation[2]:=currentFrozenState.basic.FSBASE; lpDebugEvent.Exception.ExceptionRecord.ExceptionInformation[3]:=currentFrozenState.basic.GSBASE; lpDebugEvent.Exception.ExceptionRecord.ExceptionInformation[4]:=currentFrozenState.basic.GSBASE_KERNEL; + lpDebugEvent.Exception.ExceptionRecord.ExceptionInformation[5]:=ifthen(processCR3<>currentFrozenState.basic.CR3,1,0); if getClientIDFromDBVMBPState(currentFrozenState, clientID) then begin @@ -159,6 +160,8 @@ function TDBVMDebugInterface.setBreakEvent(var lpDebugEvent: TDebugEvent; frozen lpDebugEvent.dwThreadId:=lpDebugEvent.dwThreadId and (1 shl 31); end; + + end; end; @@ -404,6 +407,7 @@ function TDBVMDebugInterface.GetThreadContext(hThread: THandle; var lpContext: T lpContext.Rip:=currentFrozenState.basic.Rip; lpContext.P1Home:=currentFrozenState.basic.Count; + lpContext.P2Home:=currentFrozenState.basic.CR3; CopyMemory(@lpContext.FltSave, @currentFrozenState.fpudata,512); result:=true; diff --git a/Cheat Engine/debugeventhandler.pas b/Cheat Engine/debugeventhandler.pas index 1971369353..4ac16e95d7 100755 --- a/Cheat Engine/debugeventhandler.pas +++ b/Cheat Engine/debugeventhandler.pas @@ -71,6 +71,7 @@ TDebugThreadHandler = class currentBP: PBreakpoint; + dbvm_currentCR3: qword; function CheckIfConditionIsMet(bp: PBreakpoint; script: string=''): boolean; @@ -264,9 +265,12 @@ procedure TDebugThreadHandler.VisualizeBreak; TDebuggerthread(debuggerthread).execlocation:=412; - if WaitingToContinue and (TDebuggerthread(debuggerthread).CurrentThread<>nil) then //no lua script or it returned 0, or it DID continue and returned 0... begin + if currentdebuggerinterface is TDBVMDebugInterface then + memorybrowser.cr3:=dbvm_currentCR3; + + TDebuggerthread(debuggerthread).execlocation:=413; MemoryBrowser.UpdateDebugContext(self.Handle, self.ThreadId, true, TDebuggerthread(debuggerthread)); end; @@ -1493,6 +1497,7 @@ function TDebugThreadHandler.HandleAccessViolationDebugEvent(debugEvent: TDEBUGE end; + function TDebugThreadHandler.HandleExceptionDebugEvent(debugEvent: TDEBUGEVENT; var dwContinueStatus: dword): boolean; var exceptionAddress: ptrUint; @@ -1513,6 +1518,14 @@ function TDebugThreadHandler.HandleExceptionDebugEvent(debugEvent: TDEBUGEVENT; EXCEPTION_DBVM_BREAKPOINT: begin outputdebugstring('EXCEPTION_DBVM_BREAKPOINT'); + + + if (debugevent.Exception.ExceptionRecord.NumberParameters>=6) and (debugevent.Exception.ExceptionRecord.ExceptionInformation[5]=1) then + dbvm_currentCR3:=debugevent.Exception.ExceptionRecord.ExceptionInformation[1] and MAXPHYADDRMASKPB + else + dbvm_currentCR3:=0; + + //dwContinueStatus supports DBG_CONTINUE_SINGLESTEP if debugEvent.Exception.ExceptionRecord.ExceptionFlags=dword(-1) then result:= singleStep(dwContinueStatus) @@ -2097,18 +2110,13 @@ function TDebugEventHandler.HandleDebugEvent(debugEvent: TDEBUGEVENT; var dwCont debuggercs.leave; //The most important data has been gathered (DR6 of the thread). it's safe from this point to occasionally release the lock + currentdebugEvent:=debugEvent; if newthread and (frmthreadlist<>nil) then - begin - currentdebugEvent:=debugEvent; TDebuggerthread(debuggerthread).Synchronize(TDebuggerthread(debuggerthread), updatethreadlist); - end; if frmDebugEvents<>nil then - begin - currentdebugEvent:=debugEvent; TDebuggerthread(debuggerthread).Synchronize(TDebuggerthread(debuggerthread), UpdateDebugEventWindow); - end; TDebuggerthread(debuggerthread).execlocation:=11; diff --git a/Cheat Engine/debughelper.pas b/Cheat Engine/debughelper.pas index a600a3f57b..9bbafd19bc 100755 --- a/Cheat Engine/debughelper.pas +++ b/Cheat Engine/debughelper.pas @@ -724,6 +724,7 @@ function TDebuggerThread.SetBreakpoint(breakpoint: PBreakpoint; UpdateForOneThre PA: qword; newdr7: qword; + old: byte; procedure displayDebugInfo(reason: string); var debuginfo:tstringlist; @@ -1034,12 +1035,24 @@ procedure displayDebugInfo(reason: string); {$ifdef windows} loaddbvmifneeded; + if dbvmbp_options.TriggerCOW and (breakpoint^.breakpointTrigger=bptExecute) then + begin + //trigger COW before placing the bp + if ReadProcessMemory(processhandle, pointer(breakpoint^.address), @old,1,bw) then + begin + vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(breakpoint.address), 1, PAGE_EXECUTE_READWRITE, oldprotect); + WriteProcessMemoryActual(processhandle, pointer(breakpoint.address), @old, 1, bw); //skip the DBVM version and use the native kernelmode/winapi one + if vpe then + VirtualProtectEx(processhandle, pointer(breakpoint.address), 1, oldprotect, oldprotect); + end; + end; + if GetPhysicalAddress(processhandle,pointer(breakpoint^.address),pa) then begin DBVMWatchBPActive:=true; case breakpoint^.breakpointTrigger of - bptExecute: breakpoint^.dbvmwatchid:=dbvm_watch_executes(PA,1,EPTO_DBVMBP,0, TDBVMDebugInterface(currentdebuggerinterface).usermodeloopint3, TDBVMDebugInterface(currentdebuggerinterface).kernelmodeloopint3); + bptExecute:breakpoint^.dbvmwatchid:=dbvm_watch_executes(PA,1,EPTO_DBVMBP,0, TDBVMDebugInterface(currentdebuggerinterface).usermodeloopint3, TDBVMDebugInterface(currentdebuggerinterface).kernelmodeloopint3); bptAccess: breakpoint^.dbvmwatchid:=dbvm_watch_reads(PA,1,EPTO_DBVMBP,0, TDBVMDebugInterface(currentdebuggerinterface).usermodeloopint3, TDBVMDebugInterface(currentdebuggerinterface).kernelmodeloopint3); bptWrite: breakpoint^.dbvmwatchid:=dbvm_watch_writes(PA,1,EPTO_DBVMBP,0, TDBVMDebugInterface(currentdebuggerinterface).usermodeloopint3, TDBVMDebugInterface(currentdebuggerinterface).kernelmodeloopint3); end; @@ -1340,7 +1353,7 @@ procedure TDebuggerThread.RemoveBreakpoint(breakpoint: PBreakpoint); end; end; - if state then DBVMWatchBPActive:=state; + DBVMWatchBPActive:=state; diff --git a/Cheat Engine/disassemblerviewlinesunit.pas b/Cheat Engine/disassemblerviewlinesunit.pas index 9a22dade4e..052431d360 100755 --- a/Cheat Engine/disassemblerviewlinesunit.pas +++ b/Cheat Engine/disassemblerviewlinesunit.pas @@ -342,7 +342,10 @@ procedure TDisassemblerLine.renderLine(var address: ptrUint; linestart: integer; w,h: single; {$endif} + d: TDisassembler; + begin + d:=TDisassemblerview(owner).currentDisassembler; fcanvas.font.style:=[]; @@ -388,16 +391,19 @@ procedure TDisassemblerLine.renderLine(var address: ptrUint; linestart: integer; + + + if iscurrentinstruction then - visibleDisassembler.context:=@MemoryBrowser.lastdebugcontext + d.context:=@MemoryBrowser.lastdebugcontext else - visibleDisassembler.context:=nil; + d.context:=nil; - fdisassembled:=visibleDisassembler.disassemble(address,fdescription); + fdisassembled:=d.disassemble(address,fdescription); - addressstring:=inttohex(visibleDisassembler.LastDisassembleData.address,8); - bytestring:=visibleDisassembler.getLastBytestring; - opcodestring:=visibleDisassembler.LastDisassembleData.prefix+visibleDisassembler.LastDisassembleData.opcode; + addressstring:=inttohex(d.LastDisassembleData.address,8); + bytestring:=d.getLastBytestring; + opcodestring:=d.LastDisassembleData.prefix+d.LastDisassembleData.opcode; //Correction for rendering bug. if (processhandler.isNetwork=true) and (processhandler.SystemArchitecture=archarm) then @@ -406,17 +412,17 @@ procedure TDisassemblerLine.renderLine(var address: ptrUint; linestart: integer; opcodestring+=' '; end; - parameterstring:=visibleDisassembler.LastDisassembleData.parameters+' '; - specialstring:=visibleDisassembler.DecodeLastParametersToString; + parameterstring:=d.LastDisassembleData.parameters+' '; + specialstring:=d.DecodeLastParametersToString; - if iscurrentinstruction and visibleDisassembler.LastDisassembleData.isconditionaljump and visibleDisassembler.LastDisassembleData.willJumpAccordingToContext then + if iscurrentinstruction and d.LastDisassembleData.isconditionaljump and d.LastDisassembleData.willJumpAccordingToContext then parameterstring:=parameterstring+' ---> '; //userdefined comments if dassemblercomments<>nil then - comment:=dassemblercomments.comments[visibleDisassembler.LastDisassembleData.address] + comment:=dassemblercomments.comments[d.LastDisassembleData.address] else comment:=''; @@ -438,7 +444,7 @@ procedure TDisassemblerLine.renderLine(var address: ptrUint; linestart: integer; //split up into lines specialstrings.text:=specialstring; - customheaderstrings.text:=dassemblercomments.commentHeader[visibleDisassembler.LastDisassembleData.address]; + customheaderstrings.text:=dassemblercomments.commentHeader[d.LastDisassembleData.address]; @@ -576,18 +582,18 @@ procedure TDisassemblerLine.renderLine(var address: ptrUint; linestart: integer; - fisJump:=visibleDisassembler.LastDisassembleData.isjump; + fisJump:=d.LastDisassembleData.isjump; if fisJump then begin fisjump:=cefuncproc.isjumporcall(faddress, fJumpsTo); - if visibleDisassembler.LastDisassembleData.iscall then + if d.LastDisassembleData.iscall then fjumpcolor:= TDisassemblerview(owner).jlCallColor else begin - if visibleDisassembler.LastDisassembleData.isconditionaljump then + if d.LastDisassembleData.isconditionaljump then fjumpcolor:=TDisassemblerview(owner).jlConditionalJumpColor else fjumpcolor:=TDisassemblerview(owner).jlUnConditionalJumpColor ; diff --git a/Cheat Engine/disassemblerviewunit.pas b/Cheat Engine/disassemblerviewunit.pas index 824974b1e5..3b65bef838 100755 --- a/Cheat Engine/disassemblerviewunit.pas +++ b/Cheat Engine/disassemblerviewunit.pas @@ -92,6 +92,7 @@ type TDisassemblerview=class(TPanel) fOnDisassemblerViewOverride: TDisassemblerViewOverrideCallback; + fCR3: qword; procedure updateScrollbox; procedure scrollboxResize(Sender: TObject); @@ -126,7 +127,7 @@ type TDisassemblerview=class(TPanel) procedure synchronizeDisassembler; procedure StatusInfoLabelCopy(sender: TObject); - + procedure setCR3(pa: QWORD); protected procedure HandleSpecialKey(key: word); procedure WndProc(var msg: TMessage); override; @@ -154,6 +155,8 @@ type TDisassemblerview=class(TPanel) drawer: TIntfFreeTypeDrawer; {$endif} + currentDisassembler: TDisassembler; + procedure DoDisassemblerViewLineOverride(address: ptruint; var addressstring: string; var bytestring: string; var opcodestring: string; var parameterstring: string; var specialstring: string); procedure reinitialize; //deletes the assemblerlines @@ -192,6 +195,7 @@ type TDisassemblerview=class(TPanel) property Osb: TBitmap read offscreenbitmap; property OnExtraLineRender: TDisassemblerExtraLineRender read fOnExtraLineRender write fOnExtraLineRender; property OnDisassemblerViewOverride: TDisassemblerViewOverrideCallback read fOnDisassemblerViewOverride write fOnDisassemblerViewOverride; + property CR3: qword read fCR3 write setCR3; end; @@ -1135,6 +1139,28 @@ procedure TDisassemblerView.OnLostFocus(sender: TObject); end; +procedure TDisassemblerview.setCR3(pa: QWORD); +begin + if pa=fcr3 then exit; + + freeAndNil(currentDisassembler); + if pa<>0 then + begin + currentDisassembler:=TCR3Disassembler.Create; + TCR3Disassembler(currentDisassembler).CR3:=pa; + currentDisassembler.syntaxhighlighting:=true; + end + else + begin + currentDisassembler:=TDisassembler.Create; + currentDisassembler.syntaxhighlighting:=true; + end; + + fCR3:=pa; + + update; +end; + destructor TDisassemblerview.destroy; begin destroyed:=true; @@ -1165,6 +1191,9 @@ destructor TDisassemblerview.destroy; if statusinfo<>nil then freeandnil(statusinfo); + if currentDisassembler<>nil then + freeandnil(currentDisassembler); + inherited destroy; end; @@ -1176,6 +1205,10 @@ constructor TDisassemblerview.create(AOwner: TComponent); begin inherited create(AOwner); + currentDisassembler:=TDisassembler.Create; + currentDisassembler.syntaxhighlighting:=true; + + {$ifdef USELAZFREETYPE} if loadCEFreeTypeFonts then begin diff --git a/Cheat Engine/frmcr3switcherunit.lfm b/Cheat Engine/frmcr3switcherunit.lfm new file mode 100644 index 0000000000..26045429a7 --- /dev/null +++ b/Cheat Engine/frmcr3switcherunit.lfm @@ -0,0 +1,91 @@ +object frmCR3Switcher: TfrmCR3Switcher + Left = 351 + Height = 240 + Top = 145 + Width = 320 + AutoSize = True + Caption = 'Pagebase Switcher (CR3)' + ClientHeight = 240 + ClientWidth = 320 + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + Position = poScreenCenter + LCLVersion = '2.0.10.0' + object edtNewCR3: TEdit + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Label1 + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Hint = 'Set to 0 or empty and click set to go back to normal windows or DBK memory API' + Top = 37 + Width = 204 + BorderSpacing.Left = 4 + BorderSpacing.Top = 4 + ParentShowHint = False + ShowHint = True + TabOrder = 0 + end + object lbCR3List: TListBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = edtNewCR3 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 3 + Height = 174 + Top = 63 + Width = 314 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Left = 3 + BorderSpacing.Top = 3 + BorderSpacing.Right = 3 + BorderSpacing.Bottom = 3 + ItemHeight = 0 + OnDblClick = lbCR3ListDblClick + OnSelectionChange = lbCR3ListSelectionChange + PopupMenu = pmCR3List + TabOrder = 1 + end + object btnSetCR3: TButton + AnchorSideLeft.Control = edtNewCR3 + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edtNewCR3 + AnchorSideTop.Side = asrCenter + Left = 212 + Height = 25 + Top = 36 + Width = 75 + BorderSpacing.Left = 4 + Caption = 'Set' + OnClick = btnSetCR3Click + TabOrder = 2 + end + object Label1: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 3 + Height = 30 + Top = 3 + Width = 317 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 3 + BorderSpacing.Top = 3 + Caption = 'Select or type the new page base address (CR3) for this memory view window' + ParentColor = False + WordWrap = True + end + object pmCR3List: TPopupMenu + Left = 136 + Top = 112 + object MenuItem1: TMenuItem + Caption = 'Record CR3 list' + OnClick = MenuItem1Click + end + end +end diff --git a/Cheat Engine/frmcr3switcherunit.pas b/Cheat Engine/frmcr3switcherunit.pas new file mode 100644 index 0000000000..02d6d5efea --- /dev/null +++ b/Cheat Engine/frmcr3switcherunit.pas @@ -0,0 +1,163 @@ +unit frmCR3SwitcherUnit; + +//for runtime switching between CR3 targets + +{$mode delphi} + +interface + +uses + Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, + Menus, maps; + +type + + { TfrmCR3Switcher } + + TfrmCR3Switcher = class(TForm) + btnSetCR3: TButton; + edtNewCR3: TEdit; + Label1: TLabel; + lbCR3List: TListBox; + MenuItem1: TMenuItem; + pmCR3List: TPopupMenu; + procedure btnSetCR3Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure lbCR3ListDblClick(Sender: TObject); + procedure lbCR3ListSelectionChange(Sender: TObject; User: boolean); + procedure MenuItem1Click(Sender: TObject); + private + fOnCR3Change: TNotifyEvent; + fCR3: qword; + public + procedure addCR3ToList(v: qword); + property CR3: qword read fCR3 write fCR3; + property OnCR3Change: TNotifyEvent read fOnCR3Change write fOnCR3Change; + end; + +implementation + +{ TfrmCR3Switcher } + +uses CEFuncProc, vmxfunctions; + +resourcestring + rsDBVMCR3Log = 'DBVM CR3 Log'; + rsDescribeDBVMRoutine = 'DBVM will record all CR3 values it encounters up to 512 unique ones). How long should it wait? (In seconds)'; + rsLongwaitWarning = 'Are you sure you wish to wait %d seconds?'; + +procedure TfrmCR3Switcher.FormCreate(Sender: TObject); +begin + loadformposition(self); +end; + +procedure TfrmCR3Switcher.addCR3ToList(v: qword); +var i: integer; +begin + i:=lbCR3List.Items.IndexOf(inttohex(v,8)); + if i<>-1 then + lbCR3List.Items.Move(i,0) + else + lbCR3List.Items.Insert(0,inttohex(v,8)); +end; + +procedure TfrmCR3Switcher.btnSetCR3Click(Sender: TObject); +var + newcr3: qword; +begin + newcr3:=0; + if edtNewCR3.text<>'' then + begin + try + newcr3:=StrToInt64('$'+edtNewCR3.text); + except + showmessage('invalid value'); + exit; + end; + end; + + fcr3:=newcr3; + fOnCR3Change(self); + + //add to the list if not there already, and if it is, bring to the top + addCR3ToList(newcr3); +end; + +procedure TfrmCR3Switcher.FormDestroy(Sender: TObject); +begin + SaveFormPosition(self); +end; + +procedure TfrmCR3Switcher.FormShow(Sender: TObject); +begin + edtNewCR3.ClientWidth:=canvas.TextWidth(' DDDDDDDDDDDDDDDD '); + + if autosize then + begin + autosize:=false; + + clientheight:=edtNewCR3.Height*12; + + end; +end; + +procedure TfrmCR3Switcher.lbCR3ListDblClick(Sender: TObject); +begin + if lbCR3List.ItemIndex<>-1 then + begin + edtNewCR3.Text:=lbCR3List.Items[lbCR3List.ItemIndex]; + btnSetCR3.Click; + end; +end; + +procedure TfrmCR3Switcher.lbCR3ListSelectionChange(Sender: TObject; + User: boolean); +begin + if lbCR3List.ItemIndex<>-1 then + edtNewCR3.Text:=lbCR3List.Items[lbCR3List.ItemIndex]; +end; + +procedure TfrmCR3Switcher.MenuItem1Click(Sender: TObject); +var + v: string; + t: integer; + cr3log: array [0..511] of qword; + i: integer; +begin + v:='5'; + if InputQuery(rsDBVMCR3Log, rsDescribeDBVMRoutine, v) then + begin + t:=strtoint(v); + if (t<60) or (MessageDlg(Format(rsLongwaitWarning, [t]), mtConfirmation, [mbyes, mbno], 0)=mryes) then + begin + if dbvm_log_cr3values_start then + begin + sleep(t*1000); + if dbvm_log_cr3values_stop(@cr3log[0]) then + begin + lbCR3List.Items.BeginUpdate; + try + lbCR3List.Clear; + + for i:=0 to 511 do + begin + if cr3log[i]=0 then break; + + lbCR3List.Items.Add(inttohex(cr3log[i],8)); + end; + finally + lbCR3List.Items.EndUpdate; + end; + end; + end; + end; + end; +end; + +initialization + {$I frmCR3SwitcherUnit.lrs} + +end. + diff --git a/Cheat Engine/hexviewunit.pas b/Cheat Engine/hexviewunit.pas index 1a47ec1d9f..cf49a3c5fb 100755 --- a/Cheat Engine/hexviewunit.pas +++ b/Cheat Engine/hexviewunit.pas @@ -143,6 +143,8 @@ THexView=class(TCustomPanel) drawer: TIntfFreeTypeDrawer; {$endif} + fcr3: qword; + procedure setHexFont(f: TFont); procedure LoadMemoryRegion; @@ -199,6 +201,11 @@ THexView=class(TCustomPanel) procedure lineDown(sender: TObject); function DisplayTypeByteSize(dt: TDisplayType): integer; inline; + procedure setCR3(pa: QWORD); + + function ReadProcessMemory(hProcess: THandle; lpBaseAddress, lpBuffer: Pointer; nSize: size_t; var lpNumberOfBytesRead: PTRUINT): BOOL; + function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: PTRUINT): BOOL; + function VirtualQueryEx(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD): DWORD; protected procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure UTF8KeyPress(var UTF8Key: TUTF8Char); override; @@ -290,6 +297,7 @@ THexView=class(TCustomPanel) property breakpointBackgroundColor: TColor read colors[hcsbreakpoint].backgroundcolor write colors[hcsbreakpoint].backgroundcolor; property differentFontColor: TColor read colors[hcsdifferent].fontcolor write colors[hcsdifferent].fontcolor; property differentBackgroundColor: TColor read colors[hcsdifferent].backgroundcolor write colors[hcsdifferent].backgroundcolor; + property CR3: QWORD read fCR3 write setCR3; end; implementation @@ -1694,7 +1702,8 @@ procedure THexView.UpdateMemoryInfo; {$endif} - if symhandler.getmodulebyaddress(fAddress,mi) then + + if (fcr3=0) and symhandler.getmodulebyaddress(fAddress,mi) then memoryInfo:=memoryInfo+' '+rsModule+'='+mi.modulename; except @@ -1725,7 +1734,7 @@ function THexView.GetPageInfo(a: ptruint): PPageInfo; {$IFDEF STANDALONEHV} p.inModule:=(a and (1 shl 12))>0 {$else} - p.inModule:=symhandler.inModule(a) + p.inModule:=((fcr3=0) and symhandler.inModule(a)) {$ENDIF} else p.inModule:=false; @@ -2895,6 +2904,40 @@ procedure THexview.setHexFont(f: TFont); update; end; +procedure THexview.setCR3(pa: QWORD); +begin + fcr3:=pa; +end; + +function THexview.ReadProcessMemory(hProcess: THandle; lpBaseAddress, lpBuffer: Pointer; nSize: size_t; var lpNumberOfBytesRead: PTRUINT): BOOL; +begin + if fcr3=0 then + result:=newkernelhandler.ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead) + else + result:=ReadProcessMemoryCR3(fcr3,lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead); +end; + +function THexview.WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: PTRUINT): BOOL; +begin + if fcr3=0 then + result:=newkernelhandler.WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten) + else + result:=WriteProcessMemoryCR3(fcr3, lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesWritten); +end; + +function THexview.VirtualQueryEx(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD): DWORD; +begin + if fcr3=0 then + result:=newkernelhandler.VirtualQueryEx(hProcess, lpAddress, lpBuffer, dwLength) + else + begin + if GetPageInfoCR3(fcr3,ptruint(lpAddress), lpBuffer) then + result:=dwlength + else + result:=0; + end; +end; + destructor THexview.destroy; begin unlock; //always destroy links