📄 debugger.pas.svn-base
字号:
for k:=i to length(debuggerthread.registermodificationBPs)-2 do
registermodificationBPs[k]:=registermodificationBPs[k+1];
setlength(registermodificationBPs,length(registermodificationBPs)-1);
break;
end;
setbreakpoints;
releasesemaphore(semaphore,1,nil);
result:=false;
exit;
end;
if length(userbreakpoints)=3 then
raise exception.Create('The current implementation doesn''t support more than 3 breakpoints. (4 debug registers, but 1 is needed for stepping-over code)');
setlength(userbreakpoints,length(userbreakpoints)+1);
userbreakpoints[length(userbreakpoints)-1]:=address;
setbreakpoints;
result:=true;
end
else
begin
//int3 breakpoints
//find it in the breakpointlist
for i:=0 to length(int3userbreakpoints)-1 do
begin
if int3userbreakpoints[i].address=address then
begin
//remove it
RewriteCode(processhandle,address,@int3userbreakpoints[i].originalbyte,1);
for j:=i to length(int3userbreakpoints)-2 do
begin
int3userbreakpoints[j].address:=int3userbreakpoints[j+1].address;
int3userbreakpoints[j].originalbyte:=int3userbreakpoints[j+1].originalbyte;
end;
setlength(int3userbreakpoints,length(int3userbreakpoints)-1);
result:=false;
exit;
end;
end;
//no, it's not in the list, so ADD:
setlength(int3userbreakpoints,length(int3userbreakpoints)+1);
int3userbreakpoints[length(int3userbreakpoints)-1].address:=address;
readprocessmemory(processhandle,pointer(address),@int3userbreakpoints[length(int3userbreakpoints)-1].originalbyte,1,a);
if a=1 then
RewriteCode(processhandle,address,@int3,1)
else
setlength(int3userbreakpoints,length(int3userbreakpoints)-1);
result:=true;
end;
finally
memorybrowser.updatebplist;
releasesemaphore(semaphore,1,nil);
end;
end;
{$endif}
end;
procedure RemoveDebuggerDetection(processhandle: thandle);
var Newfunction: array [0..2] of byte;
original,written: dword;
begin
if IsDebuggerPresentLocation=0 then exit;
{
xor eax,eax
ret
}
Newfunction[0]:=$31;
NewFunction[1]:=$c0;
NewFunction[2]:=$c3;
RewriteCode(processhandle,IsDebuggerPresentLocation,@newfunction[0],3);
end;
function DebugBreakProstitute(x: Thandle):boolean;
begin
result:=false;
end;
function DebugSetProcessKillOnExitProtitute(x: boolean):boolean;
begin
result:=false;
end;
function DebugActiveProcessStopProstitute(x: dword): boolean;
begin
result:=false;
end;
function startdebuggerifneeded(ask:boolean): boolean; overload;
var mes: string;
reS:boolean;
i: integer;
begin
result:=false;
if processhandle=0 then raise exception.create('You must first open a process');
{$ifndef netserver}
if debuggerthread2<>nil then
begin
if messagedlg('The kerneldebugger is currently active. Enabling the default windows debugger will cause the kernel debugger to terminate itself. Continue?',mtwarning,[mbyes,mbno],0)=mrno then exit;
freeandnil(debuggerthread2);
end;
{$endif}
if (debuggerthread=nil) or (not debuggerthread.attached) then
begin
if @DebugActiveProcessStop=@DebugActiveProcessStopProstitute then
mes:='This will attach the debugger of Cheat Engine to the current process. If you close Cheat Engine while the game is running, the game will close too. Are you sure you want to do this?'
else
mes:='This will attach the debugger of Cheat Engine to the current process. Continue?';
{$ifndef net}
if ask then
res:=Messagedlg(mes,mtConfirmation,[mbYes, mbNo],0)=mrYes
else
res:=true;
if res then
{$endif}
begin
{$ifndef net}
if not advancedoptions.Pausebutton.Down then
@ntsuspendprocess:=nil; //lets use the debugger for this
{$endif}
//start the debugger on the current process
//check for a debugger
Debuggerthread:=TDebugger.MyCreate2(processid);
while (debuggerthread<>nil) and DebuggerThread.attaching do sleep(10); //give him some time
if not debuggerthread.attached then
begin
debuggerthread.Free;
debuggerthread:=nil;
raise exception.Create('I couldn''t attach the debugger to this process! You could try to open the process using the processpicker and try that! If that also doesn''t work check if you have debugging rights.');
end;
{$ifndef netserver}
//Enable the debugger screen for the memorybrowser
memorybrowser.splitter1.Visible:=true;
memorybrowser.panel1.Visible:=true;
memorybrowser.view1.Visible:=true;
memorybrowser.Debug1.Visible:=true;
memorybrowser.Splitter2.Visible:=true;
memorybrowser.RegisterView.Visible:=true;
Memorybrowser.UpdateRegisterview;
{$endif}
result:=true;
exit;
end
{$ifndef net}
else
begin
result:=false;
exit;
end;
{$endif}
end;
result:=true;
end;
function startdebuggerifneeded: boolean; overload;
begin
result:=startdebuggerifneeded(true);
end;
function Breakthread(threadhandle:thandle):boolean;
var c: _context;
begin
if GetSystemType<3 then raise exception.Create('You can''t break on this OS. Windows ME or later is required. (You CAN set breakpoints at key locations)');
zeromemory(@c,sizeof(c));
c.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_DEBUG_REGISTERS;
debuggerthread.suspend;
suspendthread(threadhandle);
if not getthreadcontext(threadhandle,c) then exit;
debuggerthread.userisdebugging:=true;
with debuggerthread do
begin
DRRegs.ContextFlags:=CONTEXT_DEBUG_REGISTERS;
DRRegs.Dr7:=reg0set or reg1set or reg2set or reg3set;
DRRegs.Dr0:=0;
drregs.dr1:=0;
drregs.dr2:=0;
DRRegs.Dr3:=c.Eip;
if setthreadcontext(threadhandle,drregs) then result:=true;
end;
resumethread(threadhandle);
debuggerthread.Resume;
end;
Constructor TDebugger.MyCreate(filenm: String);
begin
{$ifndef netserver}
if debuggerthread2<>nil then raise exception.Create('Please stop the kernelmode debugging routines and breakpoints before starting this debugger');
if formsettings.cbUndoMemoryChanges.checked then CheckForChanges; //place this line at important places
if formsettings.cbBreakOnAttach.checked and (ProcessWindow<>nil) then //created using the process list
createdusingprocesswindow:=true;
{$endif}
userisdebugging:=false;
{$ifndef netserver}
handlebreakpoints:=formsettings.CheckBox1.Checked;
hidedebugger:=formsettings.checkbox1.checked;
canusedebugregs:=formsettings.rbDebugAsBreakpoint.checked;
formdebugstrings.listbox1.clear;
{$endif}
attaching:=true;
filename:=filenm;
Inputquery(filename,'Parameters:',parameters);
debugging:=true;
processhandle:=2;
howtocontinue:=0;
createAprocess:=true;
inherited Create(false); //I know, I know, these initalizes could also be done in the execute part.
end;
Constructor TDebugger.MyCreate2(processID: THandle);
var
debugportoffset:dword;
debugport:dword;
ar:dword;
peprocess: dword;
begin
{$ifndef netserver}
if debuggerthread2<>nil then
begin
if messagedlg('The kerneldebugger is currently active. Enabling the default windows debugger will cause the kernel debugger to terminate itself. Continue?',mtwarning,[mbyes,mbno],0)=mrno then exit;
freeandnil(debuggerthread2);
end;
if formsettings.cbUndoMemoryChanges.checked then CheckForChanges; //place this line at important places
if formsettings.cbBreakOnAttach.checked and (ProcessWindow<>nil) then //created using the process list
createdusingprocesswindow:=true;
{$endif}
userisdebugging:=false;
{$ifndef netserver}
handlebreakpoints:=formsettings.cbHandleBreakpoints.checked;
hidedebugger:=formsettings.checkbox1.checked;
canusedebugregs:=formsettings.rbDebugAsBreakpoint.checked;
formdebugstrings.listbox1.clear;
{$endif}
attaching:=true;
debugging:=true;
howtocontinue:=0;
createAprocess:=false;
OpenprocessID:=processid;
processhandle:=OpenProcess(process_all_access,false,processid);
{$ifndef net}
//check for a debugger
if (getsystemtype>5) and (formsettings.cbKernelOpenProcess.Checked) then
begin
debugportoffset:=GetDebugportOffset;
if debugportoffset<>0 then
begin
peprocess:=getpeprocess(processid);
if peprocess<>0 then
begin
debugport:=0;
if KernelReadProcessMemory(processhandle,pointer(peprocess+debugportoffset),@debugport,4,ar) then
begin
//readable
if (debugport<>0) and
(messagedlg('There is already a debugger attached to this process. Do you want to override it ? (Only works in winxp+)',mtconfirmation,[mbyes,mbno],0)=mryes) then
begin
debugport:=0;
KernelWriteProcessMemory(processhandle,pointer(peprocess+debugportoffset),@debugport,4,ar);
//debugger gone
end;
end;
end;
end; //else no way to check or fix it
end;
{$endif}
inherited Create(false); //I know, I know, these initalizes could also be done in the execute part.
end;
destructor TDebugger.Destroy;
begin
//clear all breakpoints
RemoveBreakpoint;
inherited Destroy;
end;
procedure TDebugger.tracersync;
{$ifndef net}
var s: string;
i: integer;
d: TTraceDebugInfo;
{$endif}
begin
{$ifndef net}
if frmtracer<>nil then
begin
s:=disassemble(context.eip);
i:=posex('-',s);
i:=posex('-',s,i+1);
s:=copy(s,i+2,length(s));
s:=inttohex(context.eip,8)+' - '+s;
d:=TTraceDebugInfo.Create;
d.c:=context;
frmtracer.ListBox1.Items.AddObject(s,d);
end;
{$endif}
end;
function TDebugger.tracer(devent: _Debug_EVENT):boolean;
var i,c: integer;
b: boolean;
h: thandle;
hid: dword;
begin
c:=0;
b:=true;
result:=false;
hid:=devent.dwThreadId;
for i:=0 to length(threadlist)-1 do
begin
if threadlist[i,0]=devent.dwThreadId then
begin
h:=threadlist[i,1];
break;
end;
end;
while b and (c<tracecount) do
begin
for i:=0 to length(threadlist)-1 do
begin
if threadlist[i,0]=devent.dwThreadId then
begin
context.ContextFlags:=CONTEXT_FULL;
getthreadcontext(threadlist[i,1],context);
break;
end;
end;
if devent.dwThreadId=hid then
synchronize(tracersync);
inc(c);
if c<tracecount then
begin
if devent.dwThreadId=hid then
SetSingleStepping(hid);
b:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE);
if b then b:=waitfordebugevent(devent,4000);
end;
end;
if b then
result:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE);
end;
procedure TDebugger.RestoreNTOpenProcess;
var NTOpenProcessPos: dword;
MyNTOpenProcessPos: dword;
x: dword;
y: array [0..4] of byte;
mykernel: thandle;
begin
NTOpenProcessPos:=dword(getprocaddress(ntdlllib,'NtOpenProcess'));
LoadDbk32;
if GetLoadedState then
begin
MyNTOpenProcessPos:=dword(getprocaddress(DarkByteKernel,'NOP'));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -