To learn how to modify the debugged process, let's take a few functions related to this. 1. Read the specified process memory: ReadProcessMemory defines this function as: Function ReadProcessMemory (HProcess: Thandle; Const LPBaseAddress: Pointer; lpbuffer: Pointer; Nsize: dword; var lpnumberofbytesread: dword): Bool; stdcall; HProcess pointing to the handle of the process of being read, this handle must have Process_vm_read permissions. LPBaseAddress: Pointer to the intermediate site of the reader in the process. LPBuffer : Point points to the pointer to the buffer for saving the read data. Nsize: Specifies the number of bytes to be read from the specified process. LPNumberofBytesRead: Points the actual number of bytes to the read data.
Second, write to the specified process memory: Defining WriteProcessMemory of this function is: function WriteProcessMemory (hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: DWORD): BOOL; stdcall; meaning of the parameters with ReadProcessMemory, which The HProcess handle must have process_vm_write and process_vm_operation permissions for the process. LPBuffer is a pointer to the data to be written to the specified process.
Note that if you want to modify the page access protection properties of the page to read-only, such as code segments, to modify the page access protection to modify it. You can use the VirtualProtectex function, please refer to the following code segment: VirtualProtectex (HPHANDLE , Address, SizeOf (BYTE), PAGE_READWRITE, OldFlg); WriteProcessMemory (hPHandle, Address, @BreakCode, SizeOf (BYTE), Read); VirtualProtectEx (hPhandle, Address, SizeOf (BYTE), OldFlg, OldFlg); // recovery page Protecting property hphldle is the target process handle, address is the base address of the memory to be modified, indicates the length of the area you want to modify. If this length crosses all the pages across the point of one or more page, Access protection properties, Oldflg is used to store the original access protection properties to call WriteProcessMemory to restore page protection properties.
Three obtained context structure specified thread: Define GetThreadContext of this function is: function GetThreadContext (hThread: THandle; var lpContext: TContext): BOOL; stdcall; hThread: To get the handle to the thread context structure, can CREATE_THEAD_DEBUG_EVENT debugging event occurs Save the thread ID and thread handle to get a thread handle when calling getThReadContext. LPCONTEXT: The structure used to save the specified thread up and down file information. In the multi-task operating system like Windows, several programs may be running in the same time. .Windows assigned to each thread a time film, after the end of the intermediate film, Windows will freeze the current thread and switch to the next thread with the highest priority. Windows will save the current process's register of the current process, so When the thread restores the run again, Windows can restore the most recent thread running environment. Save register content is now known as process context. The structure of the upper and lower files depends on the type of CPU. Before calling getthreadContext, set the TCONTEXT CONTEXTFLAGS logo. Specifically to retrieve the register. For example, only the value of the segment register of the CPU can set the contextFlags flag as context_segments. Other possible signs are as follows: Context_control: Control registers containing the CPU, such as today pointer, stack pointer, logo, and function return address . CONTEXT_INTEGER: integer registers used to identify the CPU CONTEXT_FLOATING_POINT:. identifies CPU floating point registers CONTEXT_SEGMENTS:. segment register is used to identify the CPU CONTEXT_DEBUG_REGISTER:. debug register is used to identify the CPU CONTEXT_EXTENDED_REGISTERS:. extension for identifying the CPU register CONTEXT_FULL: equivalent CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS, i.e., a combination of three flags set four specified thread context structure: SetThreadContext this function is defined as: function SetThreadContext (hThread:.. THandle; const lpContext : Tcontext): Bool; stdcall; parameter with getthreadContext. With these two functions can implement a lot of features, such as writing a debug interrupt with WriteProcessMemory in a function entry in the debugged process (INT 3, $ CC), then When running to this debug interrupt, an interrupt is generated, and then get the context of the current thread with GetThReadContext, you can use information on the parameters of the function of the ESP. You can even modify the value of the EIP to make the debugging to jump to any address. Execute or modify the value of the flag register to modify the execution of the process.
After understanding the above functions, we can use it to modify the debugged process. What kind of feature that can be implemented is limited to its own imagination, but it is not very miserable to use the debugprue. Of course, these functions can not only be used to be debugged processes, which apply as other processes (available OpenProcess to get process handles according to process identifiers), such as using them to make your own game modifier, and more.
The following example demonstrates how to get the context of the thread and set the CPU as a single step mode. Note that due to the slower mode slower, it may wait for a long time when running a large debugger. UNIT UNIT1;
Interface
Uses Windows, Messages, Sysutils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Stdctrls;
TYPE TFORM1 = Class (TFORM) Button1: TButton; label1: TLabel; Procedure Button1Click (Sender: Tobject); private {private declarations}}}}
IMPLEMENTATION
{$ R * .dfm}
{Debugging information processing} procedure debugpro; var si: _StartupinfoA; (process startup information} PI: _Process_information; {process information} Flage: DWORD; debugd: debug_event; {debugging event} rc: boolean; codecount: dword; {running number of instructions} ThreadHandle: Thandle; {main thread handle} Context: tContext; begin {establish debugging process} CodeCount: = 0; ConText.ContextFlags: = CONTEXT_CONTROL; flage: = DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS; GetStartupInfo (si); {si initialization structure Otherwise, the process cannot be created norm} if not createprocess (NIL, PCHAR ('C: /Winnt/Notepad.exe C: /Boot.ini'), NIL, NIL, FALSE, FLAGE, NIL, NIL, SI, PI) THEN Begin MessageBox (Application.Handle, 'Establishing the Debug Process Failed', '!!!', MB_OK or Mb_ICONERROR); EXIT; End; While WaitfordeBugevent (Debugd, Infinite) Do Begin {CASE DEBUGD is performed according to the event code} Case Debugd. dwDebugEventCode of EXIT_PROCESS_DEBUG_EVENT: begin MessageBox (Application.Handle, 'debugging process is suspended', '!!!', MB_OK or MB_ICONERROR); Break; end; CREATE_PROCESS_DEBUG_EVENT: begin ThreadHandle: = DebugD.CreateProcessInfo.hThread; MessageBox (Application.Handle, 'was established debugging process', '!!!', MB_OK or MB_ICONERROR); end; EXCEPTION_DEBUG_EVENT: begin if (DebugD.Exception.ExceptionRecord.ExceptionCode <> EXCEPTION_SINGLE_STEP) and (DebugD.Exception.ExceptionRecord. ExceptionCode <> exception_breakpoint) THEN RC: = false {If the debugger has an exception, it handles itself} else begin getthreadContext (threadHandle, Context); {Set the logo register logo to True, so that the CPU will be in Single-step mode} context.eflags: = context.eflags or $ 100; inc (codecount); form1.label1.caption: = INTTOSTR (CODECOUNT); setthreadContext (threadHandle, Context);
Rc: = True; end; end; end; if Rc then ContinueDebugEvent (DebugD.dwProcessId, DebugD.dwThreadId, DBG_CONTINUE) else ContinueDebugEvent (DebugD.dwProcessId, DebugD.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); end; CloseHandle (pi.hProcess); Closehandle (pi.hThread); end; procedure TForm1.Button1Click (Sender: TObject); var ThreadHandle, ThreadID: THandle; begin ThreadHandle: = CreateThread (nil, 0, @DebugPro, nil, 0, ThreadID); end;
End.
Finally attach other debug API. 1. Procedure debugbreak; stdcall; This function generates breakpoint in the current process so that the thread that can be called can signal the debugger. II. Procedure Fatalexit (EXITCODE: Integer); stdcall; Give the execution control to the debugger, the debugger behavior then is then specified as the type of debugger used. III. Function FlushinStructioncache (HProcess: Thandle; Const lpBaseAddress: Pointer; DWSIZE: DWORD): Bool; stdcall; This function is the specified process Refresh the command cache, this function is only valid on the multi-process computer. HProcess: To refresh the process handle of the cache. LPBaseAddress: To refresh the base address pointer of the area, you can be 0 dwsize: To refresh the length of the area Function isdebuggerPresent; Bool; stdcall; This function indicates whether the process runs under the debugger description, which outputs from kernel32.dll. 5. Procedure outputDebugstring (LPOUTPUTSTRING: PCHAR); stdcall; this function is current The application sends a string to the debugger, LPOUTPUTSTRING is the string to be sent. In Delphi, you can universally use View-> Debug Windows-> Event Log Open the Event Log window to view the string sent by the debugger. Six. Procedure setDebugerrorlevel (DWLEVEL: DWORD; STDCALL; This function sets the minimum error level, which will generate debug events in the system in the error level and pass it to the debugger. dWlevel: Specify the minimum error debugger for debug events, if the error is equal or Big than this program, the system generates a debug event. This parameter must be one of the following values. 0: Do not log any error. SLE_ERROR: Only the error level debug event is logged. SLE_MINORERROR: Record only the Minorerror level and ERROR level debug event. SLE_WARNING: Record the debug event of Warning Level, Minorerror and Error Level.