unit Debugger; //just my place to play with all kinds of threading methods //when i find out the best suited method I'll use that.... interface uses Classes,windows,sysutils,cefuncproc,Messages,forms,SyncObjs, dialogs,controls,Graphics,NewKernelHandler,symbolhandler,StrUtils, ComCtrls, assemblerunit, addressparser; const reg0set= $3; //(00000000000000000000000000000011) reg1set= $C; //(00000000000000000000000000001100) reg2set= $30; //(00000000000000000000000000110000) reg3set= $c0; //(00000000000000000000000011000000) debugexact= $300; gd_flag= $2000; //(00000000000000000010000000000000) reg0w= $10000; //(00000000000000010000000000000000) reg0rw= $30000; //(00000000000000110000000000000000) reg0len2=$40000; //(00000000000001000000000000000000) reg0len4=$c0000; //(00000000000011000000000000000000) reg1w= $100000; //(00000000000100000000000000000000) reg1rw= $300000; //(00000000001100000000000000000000) reg1len2=$400000; //(00000000010000000000000000000000) reg1len4=$c00000; //(00000000110000000000000000000000) reg2w= $1000000; //(00000001000000000000000000000000) reg2rw= $3000000; //(00000011000000000000000000000000) reg2len2=$4000000; //(00000100000000000000000000000000) reg2len4=$c000000; //(00001100000000000000000000000000) reg3w= $10000000; //(00010000000000000000000000000000) reg3rw= $30000000; //(00110000000000000000000000000000) reg3len2=$40000000; //(01000000000000000000000000000000) reg3len4=$c0000000; //(11000000000000000000000000000000) reg0len0=0; reg1len0=0; reg2len0=0; reg3len0=0; type TWindowsDebuggerContinueOption = (wdco_run=0, wdco_stepinto, wdco_stepover, wdco_runtill); type TReadonly = record pagebase: dword; pagesize: dword; Address: dword; size: integer; originalprotection: dword; end; type tThreadEntry=record threadHandle: thandle; address: dword; end; type Process=record ProcessID: dword; running: boolean; end; type tbreakpoint = record address:dword; originalbyte: byte; end; type TRegistermodificationBP=record address:dword; //addres to break on change_eax:BOOL; change_ebx:BOOL; change_ecx:BOOL; change_edx:BOOL; change_esi:BOOL; change_edi:BOOL; change_ebp:BOOL; change_esp:BOOL; change_eip:BOOL; change_cf:BOOL; change_pf:BOOL; change_af:BOOL; change_zf:BOOL; change_sf:BOOL; change_of:BOOL; new_eax:dword; new_ebx:dword; new_ecx:dword; new_edx:dword; new_esi:dword; new_edi:dword; new_ebp:dword; new_esp:dword; new_eip:dword; new_cf:BOOL; new_pf:BOOL; new_af:BOOL; new_zf:BOOL; new_sf:BOOL; new_of:BOOL; end; type PRegisterModificationBP=^TRegisterModificationBP; type TNewProcedureData=record processid: dword; processhandle: dword; filehandle: dword; EntryPoint: dword; OriginalEntryByte: byte; DotNet: boolean; FirstBreak: boolean; end; type TDebugger = class(TThread) private originalbyte: byte; filename: String; parameters: string; CreateAProcess: boolean; OpenProcessID: Thandle; AddressFound: Dword; HideDebugger: boolean; HandleBreakpoints: boolean; CanUseDebugRegs: boolean; createdusingprocesswindow:boolean; CurrentProcess: integer; procedure addtochangeslist; procedure ProcessCreated; procedure ResetBreakpoint; procedure SetSingleStepping(Threadid: dword); procedure AddDebugString; function injectcode(AddressOfEntryPoint:dword;processhandle:thandle):dword; function handledebuggerplugins(devent:PDebugEvent):integer; procedure tracersync; function tracer(devent: _Debug_EVENT):boolean; function WaitForDebugEvent(var lpDebugEvent: TDebugEvent; dwMilliseconds: DWORD): BOOL; function continueDebugEvent(dwProcessId, dwThreadId, dwContinueStatus: DWORD): BOOL; public //semaphore: THandle; Processes: array of process; Newprocesses: array of TNewProcedureData; pausedthreadhandle: thandle; running: boolean; continueprocess: boolean; continuehow: TWindowsDebuggerContinueOption; DRRegs: _CONTEXT; FindWriter2: boolean; attaching: boolean; attached: boolean; context: _CONTEXT; debugging: boolean; stepping: boolean; HowToContinue: integer; removed: boolean; readonly: TReadonly; readonlyset: boolean; readonlyremoved: boolean; findreaderset: boolean; findreader: TReadOnly; findreaderremoved:boolean; alsowrites: boolean; breakpointset: boolean; breakpointaddress: dword; lastbreakpoint: dword; temps: string; whattodo: integer; //ignore, continue, showwindow etc.... userisdebugging: boolean; userbreakpoints: array of dword; registermodificationBPs: array of tregistermodificationBP; int3userbreakpoints: array of tbreakpoint; int3CEBreakpoint: TBreakpoint; threadlist: array of array [0..4] of dword; threadinfo: array of dword; testje: string; breakpointlistsection: TCriticalSection; threadentrys: array of tThreadEntry; traceaddress: dword; tracecount: integer; Constructor MyCreate(filenm: String); Constructor MyCreate2(processID: THandle); destructor Destroy; override; procedure Execute; override; procedure Debuginfo; procedure Updateregisters; procedure FoundOne; procedure RemoveBreakpoint; procedure suspendallthreads; procedure resumeallthreads; function isBreakpoint(address:dword): boolean; end; type TDbgUIDebugActiveProcess = function(processhandle:THandle):boolean; stdcall; type TDebugBreakProcess = function(processhandle:THandle):boolean; stdcall; type TDebugActiveProcessStop= function(pid: dword):boolean; stdcall; type TDebugSetProcessKillOnExit=function(KillOnExit: boolean):boolean; stdcall; type TIsDebuggerPresent=function:boolean; stdcall; type TntSuspendProcess=function(ProcessID:Dword):DWORD; stdcall; type TntResumeProcess=function(ProcessID:Dword):DWORD; stdcall; type TProcessBasicInformation = record ExitStatus : Longint; PebBaseAddress : Pointer; AffinityMask : DWORD; BasePriority : Longint; UniqueProcessId : DWORD; InheritedFromUniqueProcessId : DWORD end; TProcessInfoClass=( ProcessBasicInformation,ProcessQuotaLimits,ProcessIoCounters,ProcessVmCounters,ProcessTimes, ProcessBasePriority,ProcessRaisePriority,ProcessDebugPort,ProcessExceptionPort,ProcessAccessToken, ProcessLdtInformation,ProcessLdtSize,ProcessDefaultHardErrorMode,ProcessIoPortHandlers, ProcessPooledUsageAndLimits,ProcessWorkingSetWatch,ProcessUserModeIOPL,ProcessEnableAlignmentFaultFixup, ProcessPriorityClass,ProcessWx86Information,ProcessHandleCount,ProcessAffinityMask,ProcessPriorityBoost, ProcessDeviceMap,ProcessSessionInformation,ProcessForegroundInformation,ProcessWow64Information, MaxProcessInfoClass); type TNtQueryInformationProcess=function( Handle : THandle; infoClass : TProcessInfoClass; processInformation : Pointer; processInformationLength : ULONG; returnLength : PULONG ) : DWORD; stdcall; var DebuggerThread: TDebugger; Semaphore: Thandle; DbgUIDebugActiveProcess:TDbgUIDebugActiveProcess; DebugBreakProcess:TDebugBreakProcess; DebugActiveProcessStop:TDebugActiveProcessStop; DebugSetProcessKillOnExit:TDebugSetProcessKillOnExit; IsDebuggerPresent:TIsDebuggerPresent; ntSuspendProcess: TntSuspendProcess; ntResumeProcess: tntResumeProcess; NtQueryInformationProcess: TNtQueryInformationProcess; IsDebuggerPresentLocation:dword; DbgBreakPointLocation:dword; krn: thandle; ntdlllib: thandle; CRDebugging: TCriticalSection; function startdebuggerifneeded: boolean; overload; function startdebuggerifneeded(ask:boolean): boolean; overload; function breakthread(threadhandle: thandle):boolean; function DebugActiveProcessStopProstitute(x: dword): boolean; function ToggleBreakpoint(address:dword):boolean; implementation uses Mainunit,frmFloatingPointPanelUnit,Memorybrowserformunit,disassembler,frmTracerUnit,foundcodeunit,kerneldebugger,advancedoptionsunit,formChangedAddresses,frmstacktraceunit,frmThreadlistunit,formdebugstringsunit,formsettingsunit,processwindowunit,plugin,frmCreatedProcessListUnit; function ToggleBreakpoint(address:dword):boolean; {$ifndef net} procedure setbreakpoints; var i: integer; begin with debuggerthread do begin //set the debug breakpoint suspend; DRRegs.ContextFlags:=CONTEXT_DEBUG_REGISTERS; DRRegs.Dr7:=reg0set or reg1set or reg2set or reg3set; DRRegs.Dr0:=0; drregs.dr1:=0; drregs.dr2:=0; for i:=0 to length(userbreakpoints)-1 do begin if i=0 then DRRegs.Dr0:=userbreakpoints[0] else if i=1 then DRRegs.Dr1:=userbreakpoints[1] else if i=2 then DRRegs.Dr2:=userbreakpoints[2]; end; for i:=0 to length(threadlist)-1 do begin suspendthread(debuggerthread.threadlist[i][1]); setthreadcontext(debuggerthread.threadlist[i][1],debuggerthread.DRRegs); resumethread(debuggerthread.threadlist[i][1]); end; Resume; end; end; var i,j,k: integer; a,original,written: dword; int3: byte; {$endif} begin {$ifndef net} result:=false; if foundcodedialog<>nil then raise exception.Create('I can''t do that! You are currently using one of the code finder options, please, stop it first'); if kdebugger.isactive then begin { for i:=0 to 3 do begin if debuggerthread2.breakpoints[i]=address then begin outputdebugstring('Going to disable this changereg breakpoint'); if debuggerthread2.breakpointchanges[i].address<>0 then begin StopRegisterChange(i); debuggerthread2.breakpointchanges[i].address:=0; end; debuggerthread2.breakpoints[i]:=0; debuggerthread2.setbreakpoints; memorybrowser.updatebplist; result:=false; for j:=0 to 3 do if debuggerthread2.breakpoints[j]<>0 then begin result:=true; break; end; if not result then freeandnil(debuggerthread2); exit; end; end; } end; if not startdebuggerifneeded then exit; int3:=$cc; //still here so the debugger has been attached to the process or i've fucked up again with debuggerthread do begin try WaitForSingleObject(semaphore,infinite); userisdebugging:=true; if formsettings.rbDebugAsBreakpoint.checked then begin //try to see if it already is in the list for i:=0 to length(userbreakpoints)-1 do if userbreakpoints[i]=address then begin //if it is then remove the breakpoint for j:=i to length(userbreakpoints)-2 do userbreakpoints[j]:=userbreakpoints[j+1]; setlength(userbreakpoints,length(userbreakpoints)-1); //also remove the registermodificationBP for j:=0 to length(debuggerthread.registermodificationBPs)-1 do if registermodificationBPs[j].address=address then begin 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 kdebugger.isactive 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; kdebugger.StopDebugger; 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 or CONTEXT_EXTENDED_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 debuggerthread3<>nil then raise exception.Create('Please stop the kernelmode debugging routines and breakpoints before starting this debugger'); } 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; ProcessHandler.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 debuggerthread3<>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.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; ProcessHandler.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; temp: dword; {$endif} begin {$ifndef net} if frmtracer<>nil then begin temp:=context.eip; s:=disassemble(temp); 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 (cnil then with foundcodedialog do begin address:=addressfound; opcode:=disassemble(address,desc); setlength(coderecords,length(coderecords)+1); coderecords[length(coderecords)-1].address:=addressfound; coderecords[length(coderecords)-1].size:=address-addressfound; coderecords[length(coderecords)-1].opcode:=opcode; coderecords[length(coderecords)-1].description:=desc; coderecords[length(coderecords)-1].eax:=context.Eax; coderecords[length(coderecords)-1].ebx:=context.Ebx; coderecords[length(coderecords)-1].ecx:=context.Ecx; coderecords[length(coderecords)-1].edx:=context.Edx; coderecords[length(coderecords)-1].esi:=context.Esi; coderecords[length(coderecords)-1].edi:=context.Edi; coderecords[length(coderecords)-1].ebp:=context.Ebp; coderecords[length(coderecords)-1].esp:=context.Esp; coderecords[length(coderecords)-1].eip:=context.Eip; coderecords[length(coderecords)-1].context:=context; Foundcodelist.Items.Add(opcode); end; {$else} //send the state information to the client(s) //FoundCode(Address: dword;eax:dword; ebx:dword; ecx:dword; edx:dword;esi:dword;edi:dword;ebp:dword;esp:dword;eip:dword) setlength(coderecords,length(coderecords)+1); coderecords[length(coderecords)-1]:=addressfound; output[0]:=SC_FoundCode; pdword(@output[1])^:=addressfound; pdword(@output[5])^:=context.Eax; pdword(@output[9])^:=context.Ebx; pdword(@output[13])^:=context.Ecx; pdword(@output[17])^:=context.Edx; pdword(@output[21])^:=context.Esi; pdword(@output[25])^:=context.Edi; pdword(@output[29])^:=context.Ebp; pdword(@output[33])^:=context.Esp; pdword(@output[37])^:=context.Eip; threadlist:=form1.idtcpserver1.Threads.LockList; try for i:=0 to threadlist.count-1 do TIdPeerThread(threadlist[i]).Connection.WriteBuffer(output[0],41); finally form1.idtcpserver1.Threads.UnlockList; end; {$endif} end; procedure tdebugger.suspendallthreads; var i: integer; begin for i:=0 to length(threadlist)-1 do suspendthread(threadlist[i,1]); end; procedure tdebugger.resumeallthreads; var i: integer; begin for i:=0 to length(threadlist)-1 do resumethread(threadlist[i,1]); end; function TDebugger.isBreakpoint(address: dword): boolean; var j: integer; begin result:=false; for j:=0 to length(debuggerthread.userbreakpoints)-1 do if address=userbreakpoints[j] then begin result:=true; exit; end; for j:=0 to length(debuggerthread.int3userbreakpoints)-1 do if address=int3userbreakpoints[j].address then begin result:=true; exit; end; end; procedure TDebugger.UpdateRegisters; var temp: string; i: integer; begin {$ifndef netserver} with memorybrowser do begin //enable debug mode run1.Enabled:=true; step1.Enabled:=true; stepover1.Enabled:=true; runtill1.Enabled:=true; stacktrace1.Enabled:=true; Executetillreturn1.Enabled:=true; for i:=0 to length(threadlist)-1 do begin if threadlist[i,1]=pausedthreadhandle then begin caption:='Memory Viewer - Currently debugging thread '+inttohex(threadlist[i,0],8); break; end; end; if frmstacktrace<>nil then begin frmstacktrace.stacktrace(debuggerthread.pausedthreadhandle,debuggerthread.context); end; disassemblerview.SelectedAddress:=context.Eip; temp:='EAX '+IntToHex(context.Eax,8); if temp<>eaxlabel.Caption then begin eaxlabel.Font.Color:=clred; eaxlabel.Caption:=temp; end else eaxlabel.Font.Color:=clWindowText; temp:='EBX '+IntToHex(context.Ebx,8); if temp<>ebxlabel.Caption then begin ebxlabel.Font.Color:=clred; ebxlabel.Caption:=temp; end else ebxlabel.Font.Color:=clWindowText; temp:='ECX '+IntToHex(context.ECx,8); if temp<>eCxlabel.Caption then begin eCXlabel.Font.Color:=clred; eCXlabel.Caption:=temp; end else eCXlabel.Font.Color:=clWindowText; temp:='EDX '+IntToHex(context.EDx,8); if temp<>eDxlabel.Caption then begin eDxlabel.Font.Color:=clred; eDxlabel.Caption:=temp; end else eDxlabel.Font.Color:=clWindowText; temp:='ESI '+IntToHex(context.ESI,8); if temp<>eSIlabel.Caption then begin eSIlabel.Font.Color:=clred; eSIlabel.Caption:=temp; end else eSIlabel.Font.Color:=clWindowText; temp:='EDI '+IntToHex(context.EDI,8); if temp<>eDIlabel.Caption then begin eDIlabel.Font.Color:=clred; eDIlabel.Caption:=temp; end else eDIlabel.Font.Color:=clWindowText; temp:='EBP '+IntToHex(context.EBP,8); if temp<>eBPlabel.Caption then begin eBPlabel.Font.Color:=clred; eBPlabel.Caption:=temp; end else eBPlabel.Font.Color:=clWindowText; temp:='ESP '+IntToHex(context.ESP,8); if temp<>eSPlabel.Caption then begin eSPlabel.Font.Color:=clred; eSPlabel.Caption:=temp; end else eSPlabel.Font.Color:=clWindowText; temp:='EIP '+IntToHex(context.EIP,8); if temp<>eIPlabel.Caption then begin eIPlabel.Font.Color:=clred; eIPlabel.Caption:=temp; end else eIPlabel.Font.Color:=clWindowText; temp:='CS '+IntToHex(context.SEGCS,4); if temp<>CSlabel.Caption then begin CSlabel.Font.Color:=clred; CSlabel.Caption:=temp; end else CSlabel.Font.Color:=clWindowText; temp:='DS '+IntToHex(context.SEGDS,4); if temp<>DSlabel.Caption then begin DSlabel.Font.Color:=clred; DSlabel.Caption:=temp; end else DSLabel.Font.Color:=clWindowText; temp:='SS '+IntToHex(context.SEGSS,4); if temp<>SSlabel.Caption then begin SSlabel.Font.Color:=clred; SSlabel.Caption:=temp; end else SSlabel.Font.Color:=clWindowText; temp:='ES '+IntToHex(context.SEGES,4); if temp<>ESlabel.Caption then begin ESlabel.Font.Color:=clred; ESlabel.Caption:=temp; end else ESlabel.Font.Color:=clWindowText; temp:='FS '+IntToHex(context.SEGFS,4); if temp<>FSlabel.Caption then begin FSlabel.Font.Color:=clred; FSlabel.Caption:=temp; end else FSlabel.Font.Color:=clWindowText; temp:='GS '+IntToHex(context.SEGGS,4); if temp<>GSlabel.Caption then begin GSlabel.Font.Color:=clred; GSlabel.Caption:=temp; end else GSlabel.Font.Color:=clWindowText; temp:='CF '+IntToStr(GetBitOf(context.EFLAgs,0)); if temp<>cflabel.Caption then begin CFlabel.Font.Color:=clred; CFlabel.caption:=temp; end else cflabel.Font.Color:=clWindowText; temp:='PF '+IntToStr(GetBitOf(context.EFlags,2)); if temp<>Pflabel.Caption then begin Pflabel.Font.Color:=clred; Pflabel.caption:=temp; end else Pflabel.Font.Color:=clWindowText; temp:='AF '+IntToStr(GetBitOf(context.EFlags,4)); if temp<>Aflabel.Caption then begin Aflabel.Font.Color:=clred; Aflabel.caption:=temp; end else Aflabel.Font.Color:=clWindowText; temp:='ZF '+IntToStr(GetBitOf(context.EFlags,6)); if temp<>Zflabel.Caption then begin Zflabel.Font.Color:=clred; Zflabel.caption:=temp; end else Zflabel.Font.Color:=clWindowText; temp:='SF '+IntToStr(GetBitOf(context.EFlags,7)); if temp<>Sflabel.Caption then begin Sflabel.Font.Color:=clred; Sflabel.caption:=temp; end else Sflabel.Font.Color:=clWindowText; temp:='DF '+IntToStr(GetBitOf(context.EFlags,10)); if temp<>Dflabel.Caption then begin Dflabel.Font.Color:=clred; Dflabel.caption:=temp; end else Dflabel.Font.Color:=clWindowText; temp:='OF '+IntToStr(GetBitOf(context.EFlags,11)); if temp<>Oflabel.Caption then begin Oflabel.Font.Color:=clred; Oflabel.caption:=temp; end else Oflabel.Font.Color:=clWindowText; lastdebugcontext:=context; { EAXv:=context.Eax; EBXv:=context.Ebx; ECXv:=context.Ecx; EDXv:=context.Edx; ESIv:=context.ESi; EDIv:=context.Edi; EBPv:=context.Ebp; ESPv:=context.Esp; EIPv:=context.Eip; } if frmFloatingpointpanel<>nil then begin frmFloatingpointpanel.SetContextPointer(@context); frmFloatingpointpanel.UpdatedContext; end; disassemblerview.Update; showDebugPanels:=true; reloadStacktrace; end; {$endif} end; procedure TDebugger.SetSingleStepping(Threadid: dword); var i: integer; begin for i:=0 to length(threadlist)-1 do if threadlist[i,0]=ThreadId then begin ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; getthreadcontext(threadlist[i,1],context); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; //CONTEXT_CONTROL; context.EFlags:=context.EFlags or $100; setthreadcontext(threadlist[i,1],context); break; end; end; procedure TDebugger.ResetBreakpoint; var zerobreak: _context; i: integer; int3: byte; original,a,written:dword; begin if canusedebugregs then for i:=0 to length(threadlist)-1 do begin suspendthread(threadlist[i,1]); setthreadcontext(threadlist[i,1],drregs); resumethread(threadlist[i,1]); end else begin int3:=$cc; for i:=0 to length(int3userbreakpoints)-1 do RewriteCode(processhandle,int3userbreakpoints[i].address,@int3,1); if int3CEBreakpoint.address>0 then RewriteCode(processhandle,int3CEBreakpoint.address,@int3,1); end; end; procedure TDebugger.RemoveBreakpoint; var zerobreak: _context; i: integer; original,written,a:dword; begin if canusedebugregs then begin zeromemory(@zerobreak,sizeof(zerobreak)); zerobreak.ContextFlags:=CONTEXT_DEBUG_REGISTERS; zerobreak.Dr7:=reg0set or reg1set or reg2set or reg3set; for i:=0 to length(threadlist)-1 do begin suspendthread(threadlist[i,1]); setthreadcontext(threadlist[i,1],zerobreak); resumethread(threadlist[i,1]); end; end else begin //temporarily disable all breakpoints for i:=0 to length(int3userbreakpoints)-1 do RewriteCode(processhandle,int3userbreakpoints[i].address,@int3userbreakpoints[i].originalbyte,1); if int3CEBreakpoint.address>0 then begin RewriteCode(processhandle,int3CEbreakpoint.address,@int3cebreakpoint.originalbyte,1); int3CEBreakpoint.address:=0; end; end; end; function TDebugger.handledebuggerplugins(devent:PDebugEvent):integer; begin {$ifndef net} //go through the list of debugger plugins result:=pluginhandler.handledebuggerplugins(devent); {$endif} end; //I always knew viruses are usefull function TDebugger.injectcode(AddressOfEntryPoint:dword;processhandle:thandle):dword; {$ifndef net} var LoadLibraryPtr: pointer; GetProcAddressPtr: Pointer; injectedlocation: pointer; h: Thandle; inject: array [0..255] of byte; x:dword; outp:TAssemblerBytes; position,position2: dword; dllLocation: string; startaddresS: dword; IHWCIloc: dword; {$endif} begin {$ifndef net} h:=LoadLibrary('Kernel32.dll'); if h=0 then raise exception.Create('No kernel32.dll loaded'); try GetProcAddressPtr:=GetProcAddress(h,'GetProcAddress'); if getprocaddressptr=nil then raise exception.Create('GetProcAddress not found'); LoadLibraryPtr:=GetProcAddress(h,'LoadLibraryA'); if LoadLibraryptr=nil then raise exception.Create('LoadLibraryA not found'); injectedlocation:=VirtualAllocEx(processhandle,nil,4096,MEM_COMMIT,PAGE_EXECUTE_READWRITE); if injectedlocation=nil then raise exception.Create('Failed to allocate memory'); dlllocation:=extractfilepath(application.exename)+'CEHOOK.DLL'; position:=dword(injectedlocation); position2:=0; copymemory(@inject[0],pchar(dllLocation+#0),length(dllLocation)+1); inc(position,length(dllLocation)+1); inc(position2,length(dlllocation)+1); ihwciloc:=position; copymemory(@inject[position2],pchar('IHWCI'#0),6); inc(position,6); inc(position2,6); startaddress:=position; assemble('PUSHAD',position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); //loadlibrary(cehook); assemble('PUSH '+IntToHex(dword(injectedlocation),8),position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); assemble('CALL '+IntToHex(dword(LoadLibraryPtr),8),position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); //getprocaddress assemble('PUSH '+IntToHex(ihwciloc,8),position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); assemble('PUSH EAX',position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); assemble('CALL '+IntToHex(dword(GetProcAddressPtr),8),position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); assemble('CALL EAX',position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); assemble('POPAD',position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); //jump to original start address assemble('JMP '+IntToHex(AddressOfEntryPoint,8),position,outp); copymemory(@inject[position2],outp,length(outp)); inc(position,length(outp)); inc(position2,length(outp)); //call the routine writeprocessmemory(processhandle,injectedlocation,@inject[0],position2,x); result:=startaddress; //showmessage('Injected code at: '+IntToHex(dword(injectedlocation),8)+' startaddress='+IntToHex(startaddress,8)); finally FreeLibrary(h); end; {$endif} end; function TDebugger.WaitForDebugEvent(var lpDebugEvent: TDebugEvent; dwMilliseconds: DWORD): BOOL; begin if not terminated then result:=newkernelhandler.WaitForDebugEvent(lpDebugEvent, dwMilliseconds) else result:=false; end; function TDebugger.continueDebugEvent(dwProcessId, dwThreadId, dwContinueStatus: DWORD): BOOL; var i: integer; begin if terminated then begin RemoveBreakpoint; ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL; getthreadcontext(pausedthreadhandle,context); context.ContextFlags:=CONTEXT_FULL; //CONTEXT_CONTROL; context.EFlags:=context.EFlags and (not $100); setthreadcontext(pausedthreadhandle,context); result:=newkernelhandler.ContinueDebugEvent(dwProcessID, dwThreadID, dwContinueStatus); for i:=0 to length(processes)-1 do if processes[i].running then DebugActiveProcessStop(processes[i].ProcessID); //this sometimes works end else result:=newkernelhandler.ContinueDebugEvent(dwProcessID, dwThreadID, dwContinueStatus); end; procedure TDebugger.Execute; var startupinfo:_STARTUPINFOA; int3: byte; devent: _Debug_EVENT; processinfo:_Process_information; //make an array of this i,j: integer; original: dword; tobefrozen: integer; //-1 is none notinlist: boolean; tid,thnd: dword; //---- temp: dword; desc,opcode: string; seperator: integer; fb: integer; nb: integer; address: string; offset:dword; errorlog: textfile; times: integer; debugpatch: integer; previousexception: dword; mbi : _MEMORY_BASIC_INFORMATION; hthr: thandle; asciistring: pansichar; unicodestring: pwidechar; bytesread: dword; err:string; found: boolean; a,b,c: dword; ab: byte; SelectorEntry:_LDT_ENTRY; oldcontext: _CONTEXT; exefile: File; dosheader: ^IMAGE_DOS_HEADER; Optionalheader: ^IMAGE_OPTIONAL_HEADER; ExeHeader: array [0..4095] of byte; AddressOfEntryPoint:dword; dotnet: boolean; firstbreak: boolean; creationhandleD: boolean; begin AddressOfEntryPoint:=0; setlength(processes,0); creationhandleD:=false; zeromemory(@drregs,sizeof(drregs)); drregs.ContextFlags:=CONTEXT_DEBUG_REGISTERS; previousexception:=0; times:=0; debugpatch:=0; int3:=$cc; breakpointset:=false; attached:=false; readonlyset:=false; ProcessHandler.ProcessHandle:=0; tobefrozen:=-1; //GetStartUpInfo(STARTUPINFO); FillMemory(@STARTUPINFO,sizeof(STARTUPINFO),0); STARTUPINFO.cb :=sizeof(STARTUPINFO); try if createaprocess then begin //create a process filemode:=0; assignfile(exefile,filename); try reset(exefile,1); except attaching:=false; err:='The file can''t be opened!'; messagebox(0,pchar(err),'Create failure',mb_ok); exit; end; try temp:=0; blockread(exefile,exeheader[0],4096,temp); if temp>0 then begin dosheader:=@exeheader[0]; optionalheader:=pointer(dword(dosheader)+dosheader._lfanew+24); AddressOfEntryPoint:=optionalheader.ImageBase+optionalheader.AddressOfEntryPoint; end; finally closefile(exefile); end; if not Createprocess(nil,pchar(filename+' '+parameters),nil,nil,false,(CREATE_SUSPENDED or DEBUG_PROCESS or NORMAL_PRIORITY_CLASS),nil,nil,Startupinfo,processinfo) then begin attaching:=false; err:='Cheat Engine failed to create the process. (Error='+pchar(IntToStr(GetLastError))+')'; messagebox(0,pchar(err),'Create failure',mb_ok); {$ifndef net} postmessage(mainform.Handle,WM_USER+1,0,0); {$endif} exit; end; readprocessmemory(processinfo.hProcess,pointer(addressofentrypoint),@originalbyte,1,temp); { dotneT:=false; firstbreak:=true; if originalbyte=$ff then begin readprocessmemory(processinfo.hProcess,pointer(addressofentrypoint+1),@ab,1,temp); if ab=$25 then dotnet:=true; end; if not dotnet then writeprocessmemory(processinfo.hProcess,pointeR(AddressOfEntryPoint),@int3,1,temp); } // messagebox(0,pchar(IntToHex(Context.Eax,8)),pchar(IntTOHex(Context.Eax,8)),MB_OK ); resumethread(processinfo.hThread); end else begin // BOOL DebugActiveProcess(DWORD dwProcessId)= { if(DbgUiConnectToDbg()) { HANDLE hProcess = ProcessIdToHandle(dwProcessId); if(hProcess) { DbgUiDebugActiveProcess(hProcess); NtClose(hProcess); } // } // return FALSE; // } //attach to a running process if not DebugActiveProcess(Openprocessid) then begin attaching:=false; {$ifndef net} err:='Cheat Engine failed to attach to the process. (Error='+IntToStr(GetLastError)+')'; messagebox(0,pchar(err),'Attach failure',mb_ok); postmessage(mainform.Handle,WM_USER+1,0,0); //set debuggerthread to nil {$endif} exit; end; end; DebugSetProcessKillOnExit(true); //WHY DOESN'T IT WORK LIKE I WANT TO? running:=true; continuehow:=wdco_run; while not terminated and debugging do begin if WaitForDebugEvent(devent,4000) then //4 seconds wont cause a hog I hope begin {$ifndef net} if handledebuggerplugins(@devent)=1 then continue; {$endif} //working on a debug thing currentprocess:=-1; for i:=0 to length(newprocesses)-1 do begin if newprocesses[i].processid=devent.dwProcessId then begin currentprocess:=i; break; end; end; if length(newprocesses)>0 then ProcessHandler.ProcessHandle:=newprocesses[length(newprocesses)-1].processhandle; case devent.dwDebugEventCode of EXCEPTION_DEBUG_EVENT: begin if newprocesses[currentprocess].firstbreak then begin if newprocesses[currentprocess].dotnet then begin //jump near (I assume the next byte is a $25 if readprocessmemory(newprocesses[currentprocess].processhandle,pointer(addressofentrypoint+2),@a,4,temp) then begin readprocessmemory(newprocesses[currentprocess].processhandle,pointer(a),@b,4,temp); newprocesses[currentprocess].EntryPoint:=b; readprocessmemory(newprocesses[currentprocess].processhandle,pointer(b),@newprocesses[currentprocess].OriginalEntryByte,1,temp); writeprocessmemory(newprocesses[currentprocess].processhandle,pointeR(b),@int3,1,temp); end; end; if hidedebugger then RemoveDebuggerDetection(newprocesses[currentprocess].processhandle); newprocesses[currentprocess].firstbreak:=false; end; // if devent.Excdeeption.dwFirstChance=0 then MessageBox(0,'seconde time','second time',MB_OK); //this is called after the threadlist has been initialised for i:=0 to length(threadlist)-1 do if threadlist[i,0]=devent.dwThreadId then begin ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; getthreadcontext(threadlist[i,1],context); pausedthreadhandle:=threadlist[i,1]; break; end; if createaprocess and (context.eip=newprocesses[currentprocess].EntryPoint+1) then begin creationHandled:=true; writeprocessmemory(newprocesses[currentprocess].processhandle,pointeR(newprocesses[currentprocess].EntryPoint),@newprocesses[currentprocess].OriginalEntryByte ,1,temp); context.ContextFlags:=context_full; outputdebugstring('Injecting dll'); context.Eip:=injectcode(newprocesses[currentprocess].EntryPoint,newprocesses[currentprocess].processhandle)+1; SetThreadcontext(pausedthreadhandle,context); if createdusingprocesswindow and (currentprocess=0) then begin //set a breakpoint at the AddressOfEntryPoint if not attached then begin attached:=true; attaching:=false; synchronize(ProcessCreated); end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end; end; if attached and {hidedebugger and} (not userisdebugging) then if readprocessmemory(newprocesses[currentprocess].processhandle,pointeR(context.eip-1),@ab,1,a) then begin if ab=int3 then begin if (not createaprocess) or (creationHandled) then begin if (context.Eip-1)<>DbgBreakPointLocation then begin if handlebreakpoints then debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE) else debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); outputdebugstring('err1'); continue; end; end; end; end; if not attached then begin attached:=true; attaching:=false; synchronize(ProcessCreated); end; i:=0; //find out what exception it is if devent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_BREAKPOINT then begin if userisdebugging then begin //check if this is a exception breakpoint that was made by cheat engine addressfound:=dword(devent.Exception.ExceptionRecord.ExceptionAddress); found:=(int3CEBreakpoint.address=addressfound); crdebugging.enter; try for i:=0 to length(int3userbreakpoints)-1 do if (int3userbreakpoints[i].address=addressfound) then found:=true; finally crdebugging.Leave; end; if found or createdusingprocesswindow then begin //we have a confirmation.... //set the byte back if not createdusingprocesswindow then removebreakpoint; createdusingprocesswindow:=false; if int3CEBreakpoint.address=addressfound then begin int3CEBreakpoint.address:=0; int3CEBreakpoint.originalbyte:=0; end; //set eip back dec(context.Eip); notinlist:=true; crdebugging.enter; try for i:=0 to length(registermodificationBPs)-1 do begin if registermodificationBPs[i].address=context.eip then begin notinlist:=false; //modify the context of this thread according to the data in registermodificationBPs[i] if registermodificationBPs[i].change_eax then context.Eax:=registermodificationBPs[i].new_eax; if registermodificationBPs[i].change_ebx then context.Ebx:=registermodificationBPs[i].new_ebx; if registermodificationBPs[i].change_ecx then context.Ecx:=registermodificationBPs[i].new_ecx; if registermodificationBPs[i].change_edx then context.Edx:=registermodificationBPs[i].new_edx; if registermodificationBPs[i].change_esi then context.Esi:=registermodificationBPs[i].new_esi; if registermodificationBPs[i].change_edi then context.Edi:=registermodificationBPs[i].new_edi; if registermodificationBPs[i].change_ebp then context.Ebp:=registermodificationBPs[i].new_ebp; if registermodificationBPs[i].change_esp then context.Esp:=registermodificationBPs[i].new_esp; if registermodificationBPs[i].change_eip then context.Eip:=registermodificationBPs[i].new_eip; if registermodificationBPs[i].change_cf then if registermodificationBPs[i].new_cf then context.EFlags:=context.EFlags or $1 //enable the bit else context.EFlags:=context.EFlags and (not $1); if registermodificationBPs[i].change_pf then if registermodificationBPs[i].new_pf then context.EFlags:=context.EFlags or $4 //enable the bit else context.EFlags:=context.EFlags and (not $4); if registermodificationBPs[i].change_af then if registermodificationBPs[i].new_af then context.EFlags:=context.EFlags or $10 //enable the bit else context.EFlags:=context.EFlags and (not $10); if registermodificationBPs[i].change_zf then if registermodificationBPs[i].new_zf then context.EFlags:=context.EFlags or $40 //enable the bit else context.EFlags:=context.EFlags and (not $40); if registermodificationBPs[i].change_sf then if registermodificationBPs[i].new_sf then context.EFlags:=context.EFlags or $80 //enable the bit else context.EFlags:=context.EFlags and (not $80); if registermodificationBPs[i].change_of then if registermodificationBPs[i].new_of then context.EFlags:=context.EFlags or $800 //enable the bit else context.EFlags:=context.EFlags and (not $800); context.ContextFlags:=CONTEXT_FULL; setthreadcontext(pausedthreadhandle,context); SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); j:=devent.dwThreadId; if not WaitForDebugEvent(devent,10000) then application.MessageBox('userbreakpoint bug','Cheat Engine Debugger',0); while j<>devent.dwthreadid do begin debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if not WaitForDebugEvent(devent,10000) then application.MessageBox('userbreakpoint bug','Cheat Engine Debugger',0); end; resetbreakpoint; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); break; end; end; //registermodificiation loop finally crdebugging.Leave; end; if (traceaddress<>0) and (self.traceaddress=dword(devent.Exception.ExceptionRecord.ExceptionAddress)) then //do tracecount steps begin context.ContextFlags:=CONTEXT_FULL; setthreadcontext(pausedthreadhandle,context); if tracecount>0 then begin debugging:=tracer(devent); tracecount:=0; end else debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); resetbreakpoint; continue; end; if not notinlist then continue; //exit, we've done what was needed context.ContextFlags:=CONTEXT_FULL; setthreadcontext(pausedthreadhandle,context); continueprocess:=false; continuehow:=wdco_run; suspendallthreads; synchronize(updateregisters); running:=false; while not continueprocess do sleep(10); WaitForSingleObject(semaphore,infinite); running:=true; //meaning, keep your fucking hands of the registers resumeallthreads; //make a step SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); j:=devent.dwThreadId; WaitForDebugEvent(devent,10000); while j<>devent.dwthreadid do begin debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); WaitForDebugEvent(devent,10000); end; //set the breakpoint back if needed resetbreakpoint; releasesemaphore(semaphore,1,nil); if continuehow=wdco_stepinto then //it was a step, so begin continueprocess:=false; continuehow:=wdco_run; suspendallthreads; for j:=0 to length(threadlist)-1 do if threadlist[j,0]=devent.dwThreadId then begin ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; getthreadcontext(threadlist[j,1],context); pausedthreadhandle:=threadlist[j,1]; break; end; synchronize(updateregisters); running:=true; //meaning, keep your fucking hands of the registers while not continueprocess do sleep(10); running:=true; //meaning, keep your fucking hands of the registers resumeallthreads; //make a step if continuehow=wdco_stepinto then SetSingleStepping(devent.dwThreadId); end; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); Outputdebugstring(pchar('Breakpoint:'+IntToHex(dword(devent.Exception.ExceptionRecord.ExceptionAddress),8))); continue; end; //check if it is because the single stepping mode is enabled if devent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_SINGLE_STEP then begin //it is in single step mode //--added if (traceaddress<>0) and (dword(devent.Exception.ExceptionRecord.ExceptionAddress)=traceaddress) then begin RemoveBreakpoint; if tracecount>0 then debugging:=tracer(devent) else debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); tracecount:=0; ResetBreakpoint; continue; end; if findwriter2 then begin addressfound:=dword(devent.Exception.ExceptionRecord.ExceptionAddress); offset:=addressfound; opcode:=disassemble(offset,desc); if pos('REP',opcode)>0 then begin if context.Ecx=0 then addressfound:=previousopcode(addressfound); end else addressfound:=previousopcode(addressfound); //check if the address is in the list notinlist:=true; try {$ifndef net} for i:=0 to length(foundcodedialog.coderecords)-1 do if foundcodedialog.coderecords[i].address=addressfound then //if it is in the list then set notinlist to false and go out of the loop begin notinlist:=false; break; end; {$else} //check if it is in the list for i:=0 to length(coderecords)-1 do if coderecords[i]=addressfound then begin notinlist:=false; break; end; {$endif} except //list got shortened or invalid end; if notinlist then synchronize(foundone); //add this memory address to the foundcode window. end; if findreaderset then begin WaitForSingleObject(semaphore,infinite); if findreaderset then VirtualProtectEx(processhandle,pointer(findreader.Address),findreader.size,PAGE_NOACCESS,original); releasesemaphore(semaphore,1,nil); end; if breakpointset then begin if breakpointaddress=dword(devent.Exception.ExceptionRecord.ExceptionAddress) then begin //find out what the address points to offset:=breakpointaddress; opcode:=disassemble(offset,desc); fb:=pos('[',opcode); if fb>0 then begin nb:=pos(']',opcode); if nb>fb then //just a simple check to verify the opcode is ok begin temps:=copy(opcode,fb+1,nb-fb-1); //lastbreakpoint:=address; synchronize(addtochangeslist); //and add that address to a list removebreakpoint; SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,10000)=false then application.MessageBox('error2-3','error2-3',0); while devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP do begin if devent.dwDebugEventCode=EXCEPTION_DEBUG_EVENT then begin //I hate it when this happens debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); outputdebugstring('err2'); break; end; end; if breakpointset then resetbreakpoint; end; end; end; end; if userisdebugging then begin //got a breakpoint //set the breakpoint if not canusedebugregs then removebreakpoint; if (canusedebugregs) and (drregs.dr3=context.Eip) then begin drregs.Dr3:=0; resetbreakpoint; end; //check if it is a regmodification bp crdebugging.Enter; try notinlist:=true; for i:=0 to length(registermodificationBPs)-1 do begin if registermodificationBPs[i].address=context.eip then begin notinlist:=false; //modify the context of this thread according to the data in registermodificationBPs[i] if registermodificationBPs[i].change_eax then context.Eax:=registermodificationBPs[i].new_eax; if registermodificationBPs[i].change_ebx then context.Ebx:=registermodificationBPs[i].new_ebx; if registermodificationBPs[i].change_ecx then context.Ecx:=registermodificationBPs[i].new_ecx; if registermodificationBPs[i].change_edx then context.Edx:=registermodificationBPs[i].new_edx; if registermodificationBPs[i].change_esi then context.Esi:=registermodificationBPs[i].new_esi; if registermodificationBPs[i].change_edi then context.Edi:=registermodificationBPs[i].new_edi; if registermodificationBPs[i].change_ebp then context.Ebp:=registermodificationBPs[i].new_ebp; if registermodificationBPs[i].change_esp then context.Esp:=registermodificationBPs[i].new_esp; if registermodificationBPs[i].change_eip then context.Eip:=registermodificationBPs[i].new_eip; if registermodificationBPs[i].change_cf then if registermodificationBPs[i].new_cf then context.EFlags:=context.EFlags or $1 //enable the bit else context.EFlags:=context.EFlags and (not $1); if registermodificationBPs[i].change_pf then if registermodificationBPs[i].new_pf then context.EFlags:=context.EFlags or $4 //enable the bit else context.EFlags:=context.EFlags and (not $4); if registermodificationBPs[i].change_af then if registermodificationBPs[i].new_af then context.EFlags:=context.EFlags or $10 //enable the bit else context.EFlags:=context.EFlags and (not $10); if registermodificationBPs[i].change_zf then if registermodificationBPs[i].new_zf then context.EFlags:=context.EFlags or $40 //enable the bit else context.EFlags:=context.EFlags and (not $40); if registermodificationBPs[i].change_sf then if registermodificationBPs[i].new_sf then context.EFlags:=context.EFlags or $80 //enable the bit else context.EFlags:=context.EFlags and (not $80); if registermodificationBPs[i].change_of then if registermodificationBPs[i].new_of then context.EFlags:=context.EFlags or $800 //enable the bit else context.EFlags:=context.EFlags and (not $800); context.ContextFlags:=CONTEXT_FULL; setthreadcontext(pausedthreadhandle,context); removebreakpoint; SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); j:=devent.dwThreadId; if not WaitForDebugEvent(devent,10000) then application.MessageBox('userbreakpoint bug','Cheat Engine Debugger',0); while j<>devent.dwthreadid do begin debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if not WaitForDebugEvent(devent,10000) then application.MessageBox('userbreakpoint bug','Cheat Engine Debugger',0); end; resetbreakpoint; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); break; end; end; finally crdebugging.Leave; end; if not notinlist then continue; //----------------------------------- continueprocess:=false; continuehow:=wdco_run; suspendallthreads; synchronize(updateregisters); running:=false; while not continueprocess do sleep(10); running:=true; //meaning, keep your fucking hands of the registers resumeallthreads; removebreakpoint; SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); i:=devent.dwThreadId; if not WaitForDebugEvent(devent,10000) then application.MessageBox('userbreakpoint bug','Cheat Engine Debugger',0); while i<>devent.dwthreadid do begin debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if not WaitForDebugEvent(devent,10000) then application.MessageBox('userbreakpoint bug','Cheat Engine Debugger',0); end; resetbreakpoint; //get new context info for i:=0 to length(threadlist)-1 do if threadlist[i,0]=devent.dwThreadId then begin ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; getthreadcontext(threadlist[i,1],context); pausedthreadhandle:=threadlist[i,1]; break; end; if ((canusedebugregs) and (drregs.Dr3=context.Eip)) or (continuehow=wdco_stepinto) then begin if (canusedebugregs) and (drregs.dr3=context.Eip) then begin drregs.Dr3:=0; resetbreakpoint; end; suspendallthreads; synchronize(updateregisters); continueprocess:=false; continuehow:=wdco_run; running:=false; while not continueprocess do; running:=true; resumeallthreads; if continuehow=wdco_stepinto then SetSingleStepping(devent.dwThreadId); end; end; if not canusedebugregs then resetbreakpoint; //it's a single step exception (most likely made by me, so I'd better fix it) debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end; //if it was a access violation, and it was a WRITE access violation then if readonlyset and (devent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_ACCESS_VIOLATION) and (devent.Exception.ExceptionRecord.ExceptionInformation[0]=1) then begin //now check if this address is in our locked array? if (devent.Exception.ExceptionRecord.ExceptionInformation[1]>=readonly.pagebase) and (devent.Exception.ExceptionRecord.ExceptionInformation[1]<=readonly.pagebase+readonly.pagesize) then begin //the address that created an exception is in a page I locked //check if the exception is at the same spot as the entry in the read-only list if (devent.Exception.ExceptionRecord.ExceptionInformation[1]>=readonly.Address-readonly.size+1) and (devent.Exception.ExceptionRecord.ExceptionInformation[1]<=readonly.Address+readonly.size-1) then begin //it is!!! addressfound:=dword(devent.Exception.ExceptionRecord.ExceptionAddress); //check if the address is in the list notinlist:=true; //go through the list try {$ifndef net} for i:=0 to length(foundcodedialog.coderecords)-1 do if foundcodedialog.coderecords[i].address=addressfound then //if it is in the list then set notinlist to false and go out of the loop begin notinlist:=false; break; end; {$else} //check if it is in the list for i:=0 to length(coderecords)-1 do if coderecords[i]=addressfound then begin notinlist:=false; break; end; {$endif} except end; if notinlist then synchronize(foundone); //add this memory address to the foundcode window. end; //set the protection back to the original, in single stepping mode VirtualProtectEx(processhandle,pointer(readonly.Address),readonly.size,readonly.originalprotection,original); //set the process to single stepping //find the threadhandle SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,30000) then while debugging and readonlyset and (devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP) do begin inc(debugpatch); //This SHOULD never come up... if devent.dwDebugEventCode=EXCEPTION_DEBUG_EVENT then //in case of a thread that does something begin for i:=0 to length(threadlist)-1 do if threadlist[i,0]=devent.dwThreadId then begin hthr:=threadlist[i,1]; ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; getthreadcontext(hthr,context); context.ContextFlags:=CONTEXT_FULL; //CONTEXT_CONTROL; context.EFlags:=context.EFlags or $100; setthreadcontext(hthr,context); break; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); outputdebugstring('err3'); break; end; for i:=0 to length(threadlist)-1 do if threadlist[i,0]=devent.dwThreadId then begin hthr:=threadlist[i,1]; ZeroMemory(@context,sizeof(context)); context.ContextFlags:=CONTEXT_FULL or CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS; getthreadcontext(hthr,context); context.ContextFlags:=CONTEXT_FULL; //CONTEXT_CONTROL; context.EFlags:=context.EFlags or $100; setthreadcontext(hthr,context); break; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,30000)=false then application.MessageBox('Write Exception Error. (2)','Debugger error',0) end; {while} //set the protection back to read-only if the readonly flag is still needed WaitForSingleObject(semaphore,infinite); if readonlyset then VirtualProtectEx(processhandle,pointer(readonly.Address),readonly.size,PAGE_EXECUTE_READ,original); releasesemaphore(semaphore,1,nil); if devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP then continue; //debugloghelp inc(times); previousexception:=devent.Exception.ExceptionRecord.ExceptionInformation[1]; end; //release the semaphore so other threads that want to use the rea-only list can access this //the access violation was created by me, so handle it myself, and not the app debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end; {access violation} //read access violations if findreaderset then begin if (devent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_ACCESS_VIOLATION) and ((devent.Exception.ExceptionRecord.ExceptionInformation[0]=0) or (alsowrites)) //0=read then //0=read begin //check if the exception is at the same spot as the entry in the read-only list if ((devent.Exception.ExceptionRecord.ExceptionInformation[1]>=findreader.Address) and (devent.Exception.ExceptionRecord.ExceptionInformation[1]findreader.Address-findreader.size)) then begin //it is!!! addressfound:=dword(devent.Exception.ExceptionRecord.ExceptionAddress); //check if the address is in the list notinlist:=true; //go through the list try {$ifndef net} for i:=0 to length(foundcodedialog.coderecords)-1 do if foundcodedialog.coderecords[i].address=addressfound then //if it is in the list then set notinlist to false and go out of the loop begin notinlist:=false; break; end; {$else} //check if it is in the list for i:=0 to length(coderecords)-1 do if coderecords[i]=addressfound then begin notinlist:=false; break; end; {$endif} except end; if notinlist then synchronize(foundone); //add this memory address to the foundcode window. end; //set the protection back to the original, in single stepping mode VirtualProtectEx(processhandle,pointer(findreader.Address),findreader.size,findreader.originalprotection,original); //set the process to single stepping SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,10000)=false then application.MessageBox('error1-3','error1-3',0); while devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP do begin if devent.dwDebugEventCode=EXCEPTION_DEBUG_EVENT then begin //I hate it when this happens debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); outputdebugstring('err4'); break; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,30000)=false then application.MessageBox('error2','error2',0) end; //set the protection back to read-only if the readonly flag is still needed WaitForSingleObject(semaphore,infinite); if findreaderset then VirtualProtectEx(processhandle,pointer(findreader.Address),findreader.size,original,original); releasesemaphore(semaphore,1,nil); if devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP then continue; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end; {read access violation} //check if it was a write access violation if (devent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_ACCESS_VIOLATION) and (devent.Exception.ExceptionRecord.ExceptionInformation[0]=1) then //1=write begin VirtualProtectEx(processhandle,pointer(findreader.Address),findreader.size,findreader.originalprotection,original); //set the process to single stepping SetSingleStepping(devent.dwThreadId); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,10000)=false then application.MessageBox('error1-1','error1-1',0); while devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP do begin if devent.dwDebugEventCode=EXCEPTION_DEBUG_EVENT then begin debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); outputdebugstring('err5'); continue; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); if WaitForDebugEvent(devent,30000)=false then application.MessageBox('error2','error2',0) end; //set the protection back to no access if the readonly flag is still needed WaitForSingleObject(semaphore,infinite); if findreaderset then VirtualProtectEx(processhandle,pointer(findreader.Address),findreader.size,original,original); releasesemaphore(semaphore,1,nil); if devent.Exception.ExceptionRecord.ExceptionCode<>EXCEPTION_SINGLE_STEP then continue; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end {if findreaderset} else begin if (devent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_ACCESS_VIOLATION) then begin if findreader.Address<>0 then begin //check if the exception is at the same spot as the entry in the read-only list if ((devent.Exception.ExceptionRecord.ExceptionInformation[1]>=(findreader.Address div $1000) * $1000) and (devent.Exception.ExceptionRecord.ExceptionInformation[1]<((findreader.Address+$1000 div $1000) * $1000)+findreader.size)) then begin //perhaps a leftover or not, lets handle it anyhow VirtualProtectEx(processhandle,pointer(findreader.Address),findreader.size,findreader.originalprotection,original); debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); continue; end; end; end; end; //not captured if findreaderremoved or readonlyremoved then begin findreaderremoved:=false; readonlyremoved:=false; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); end else begin debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); outputdebugstring(pchar('err6:'+IntToStr(currentprocess)+ '/'+IntToStr(length(newprocesses)-1)+ ' eip='+IntToHex(context.eip,8)+' esi='+IntToHex(context.esi,8)+' edi='+IntToHex(context.edi,8) )); end; continue; end; CREATE_THREAD_DEBUG_EVENT: begin //seems this is a way of unhooking the debugger ProcessHandler.ProcessHandle:=newprocesses[currentprocess].processhandle; setlength(threadlist,length(threadlist)+1); threadlist[length(threadlist)-1,0]:=devent.dwThreadId; threadlist[length(threadlist)-1,1]:=devent.CreateThread.hThread; threadlist[length(threadlist)-1,2]:=dword(devent.CreateThread.lpStartAddress); threadlist[length(threadlist)-1,3]:=dword(devent.CreateThread.lpThreadLocalBase); if canusedebugregs and (findwriter2 or breakpointset or userisdebugging) then //set the debug registers here too setthreadcontext(devent.CreateThread.hThread,drregs); {$ifndef net} if frmthreadlist<>nil then synchronize(frmthreadlist.fillthreadlist); {$endif} //let the application/OS handle this debug event debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); end; EXIT_THREAD_DEBUG_EVENT: begin //search the threadid in the threadid list tid:=devent.dwThreadId; for i:=0 to length(threadlist)-1 do if threadlist[i,0]=tid then begin for j:=i to length(threadlist)-2 do threadlist[j]:=threadlist[j+1]; setlength(threadlist,length(threadlist)-1); break; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); end; CREATE_PROCESS_DEBUG_EVENT: begin currentprocess:=length(newprocesses); setlength(newprocesses,length(newprocesses)+1); newprocesses[currentprocess].processid:=devent.dwProcessId; newprocesses[currentprocess].processhandle:=devent.CreateProcessInfo.hProcess; newprocesses[currentprocess].filehandle:=devent.CreateProcessInfo.hFile; newprocesses[currentprocess].EntryPoint:=dword(devent.CreateProcessInfo.lpStartAddress); newprocesses[currentprocess].FirstBreak:=true; if attached then synchronize(ProcessCreated); readprocessmemory(newprocesses[currentprocess].processhandle,pointer(newprocesses[currentprocess].EntryPoint),@newprocesses[currentprocess].OriginalEntryByte,1,temp); newprocesses[currentprocess].dotnet:=false; if newprocesses[currentprocess].OriginalEntryByte=$ff then begin readprocessmemory(newprocesses[currentprocess].processhandle,pointer(newprocesses[currentprocess].EntryPoint),@ab,1,temp); if ab=$25 then newprocesses[currentprocess].dotnet:=true; end; if not newprocesses[currentprocess].dotnet then if not writeprocessmemory(newprocesses[currentprocess].processhandle,pointeR(newprocesses[currentprocess].EntryPoint),@int3,1,temp) then outputdebugstring('failed to set break'); setlength(threadlist,length(threadlist)+1); threadlist[length(threadlist)-1,0]:=devent.dwThreadId; threadlist[length(threadlist)-1,1]:=devent.CreateProcessInfo.hThread; setlength(Processes,length(processes)+1); processes[length(processes)-1].ProcessID:=devent.dwProcessId; processes[length(processes)-1].running:=true; if processhandle=0 then begin ProcessHandler.ProcessHandle:=devent.CreateProcessInfo.hProcess; ProcessHandler.processid:=devent.dwProcessId; processinfo.hProcess:=processhandle; processinfo.hThread:=devent.CreateProcessInfo.hThread; if devent.CreateProcessInfo.hProcess<>processhandle then BEEP; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE); {$ifndef net} memorybrowser.thhandle:=devent.CreateProcessInfo.hThread; {$endif} symhandler.reinitialize; end; EXIT_PROCESS_DEBUG_EVENT: begin //a process stopped //find the process in the process list for i:=0 to length(processes)-1 do begin if devent.dwProcessId=Processes[i].ProcessID then begin processes[i].running:=false; break; end; end; for i:=0 to length(newprocesses)-1 do if devent.dwProcessId=newprocesses[i].processid then begin for j:=i to length(newprocesses)-2 do newprocesses[i]:=newprocesses[i+1]; break; end; debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); //check if there are processes left debugging:=false; for i:=0 to length(processes)-1 do if processes[i].running then debugging:=true; end; OUTPUT_DEBUG_STRING_EVENT: begin if devent.DebugString.fUnicode=0 then begin //8 bit ascii try getmem(asciistring,devent.DebugString.nDebugStringLength+1); try ReadProcessMemory(newprocesses[currentprocess].processhandle,devent.DebugString.lpDebugStringData,asciistring,devent.DebugString.nDebugStringLength,bytesread); asciistring[devent.DebugString.nDebugStringLength]:=#0; temps:=asciistring; finally freemem(asciistring); end; except ; end; end else begin //16 bit unicode try getmem(unicodestring,devent.DebugString.nDebugStringLength+1); try ReadProcessMemory(newprocesses[currentprocess].processhandle,devent.DebugString.lpDebugStringData,unicodestring,devent.DebugString.nDebugStringLength,bytesread); unicodestring[devent.DebugString.nDebugStringLength div 2]:=#0; temps:=unicodestring; finally freemem(unicodestring); end; except end; end; synchronize(AddDebugString); if hidedebugger then //double bevcause of the way it is implementedin the os debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED) else debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_CONTINUE) end; else debugging:=ContinueDebugEvent(devent.dwProcessId,devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); end; end; end; except messagebox(0,'Debugger crash','CE Debugger',mb_ok); end; // application.MessageBox(pchar('devent.dwDebugEventCode='+inttohex(devent.dwDebugEventCode,8)),'error'); setlength(userbreakpoints,0); setlength(int3userbreakpoints,0); for i:=0 to length(processes)-1 do if processes[i].running then DebugActiveProcessStop(processes[i].ProcessID); //this sometimes works attached:=false; setlength(threadlist,0); {$ifndef net} postmessage(mainform.Handle,WM_USER+1,0,0); {$endif} end; initialization CRDebugging:=TCriticalSection.Create; krn := LoadLibrary('Kernel32.dll'); if krn <> 0 then begin @DebugBreakProcess := GetProcAddress(krn, 'DebugBreakProcess'); @DebugSetProcessKillOnExit :=GetProcAddress(krn,'DebugSetProcessKillOnExit'); @DebugActiveProcessStop :=GetProcAddress(krn,'DebugActiveProcessStop'); @IsDebuggerPresent:=GetProcAddress(krn,'IsDebuggerPresent'); IsDebuggerPresentLocation:=DworD(GetProcAddress(krn,'IsDebuggerPresent')); if @DebugBreakProcess=nil then @DebugBreakProcess:=@DebugBreakProstitute; if @DebugSetProcessKillOnExit=nil then @DebugSetProcessKillOnExit:=@DebugSetProcessKillOnExitProtitute; if @DebugActiveProcessStop=nil then @DebugActiveProcessStop:=@DebugActiveProcessStopProstitute; end; ntdlllib:=LoadLibrary('ntdll.dll'); if ntdlllib<>0 then begin DbgUIDebugActiveProcess:=getprocaddress(ntdlllib,'DbgUiDebugActiveProcess'); DbgBreakPointLocation:=dword(getprocaddress(ntdlllib,'DbgBreakPoint')); NtQueryInformationProcess:=nil; NtQueryInformationProcess:=GetProcAddress(ntdlllib,'NtQueryInformationProcess'); ntsuspendprocess:=nil; ntsuspendprocess:=GetProcAddress(ntdlllib,'NtSuspendProcess'); ntresumeprocess:=GetProcAddress(ntdlllib,'NtResumeProcess'); freelibrary(ntdlllib); end; finalization if CRDebugging<>nil then CRDebugging.Free; end.