Win32 API debugging experience (3)

Source: Internet
Author: User

To learn how to modify the debugged process, let's take a look at several related functions.
1. Read the specified process memory: readprocessmemory
This function is defined as: function readprocessmemory (hprocess: thandle; const lpbaseaddress: pointer; lpbuffer: pointer; nsize: DWORD; var lpnumberofbytesread: DWORD): bool; stdcall;
Hprocess points to the handle of the read-in-memory process, which must have the process_vm_read permission.
Lpbaseaddress: pointer to the base address in the read process.
Lpbuffer: pointer to the buffer used to save read data.
Nsize: specifies the number of bytes to be read from a specified process.
Lpnumberofbytesread: refers to the actual number of bytes of data read.

2. Write the specified process memory: writeprocessmemory
This function is defined as: function writeprocessmemory (hprocess: thandle; const lpbaseaddress: pointer; lpbuffer: pointer; nsize: DWORD; var lpnumberofbyteswritten: DWORD): bool; stdcall;
The parameter description is the same as readprocessmemory. The hprocess handle must have the process_vm_write and process_vm_operation permissions on the process. lpbuffer is the pointer to data written to the specified process.

Note: If the access protection attribute of the page in which the memory to be modified is read-only, such as a code segment, You need to modify the access protection of the page before modification. you can use the virtualprotectex function. See the following code snippet:
Virtualprotectex (hphandle, address, sizeof (byte), page_readwrite, oldflg );
Writeprocessmemory (hphandle, address, @ breakcode, sizeof (byte), read );
Virtualprotectex (hphandle, address, sizeof (byte), oldflg, oldflg); // restore the page number protection attribute
Hphandle is the target Process Handle, address is the base address of the memory to be modified, and sizeof (byte) indicates the length of the region to be modified. If the length spans one or more page boundaries, modify the access protection attributes of all pages that have been crossed. oldflg is used to store the original access protection attributes so that the page protection attributes can be restored after writeprocessmemory is called.

3. Get the Context Structure of the specified Thread: getthreadcontext
This function is defined as: function getthreadcontext (hthread: thandle; var lpcontext: tcontext): bool; stdcall;
Hthread: to obtain the thread handle of the context structure, you can save the association between the thread ID and the thread handle when the create_thead_debug_event debugging event occurs so that the thread handle can be obtained when getthreadcontext is called.
Lpcontext: used to save the structure of the file information of the specified thread.
In a multitasking operating system like Windows, several programs may run at the same time. windows assigns a time slice to each thread. When the time slice ends, Windows freezes the current thread and switches to the next thread with the highest priority. before switching, Windows will save the content of the register of the current process, so that when the thread resumes running again, Windows can restore the environment where the last thread was running. the stored register content is generally called the process context. the structure of the upstream and downstream files depends on the CPU type.
Before calling getthreadcontext, you must set the contextflags flag of tcontext to specify the register to be retrieved. for example, if you only want to get the value of the segment register of the CPU, you can set the contextflags flag to context_segments. other possible indicators are as follows:
Context_control: contains the control registers of the CPU, such as the current pointer, stack pointer, flag, and function return address.
Context_integer: the integer register used to identify the CPU.
Context_floating_point: the floating-point register used to identify the CPU.
Context_segments: the segment register used to identify the CPU.
Context_debug_register: the debugging register used to identify the CPU.
Context_extended_registers: the extended register used to identify the CPU.
Context_full: equivalent to context_control or context_integer or context_segments, that is, the combination of the three flags.

4. Set the Context Structure of the specified Thread: setthreadcontext
This function is defined as: function setthreadcontext (hthread: thandle; const lpcontext: tcontext): bool; stdcall;
The parameter is the same as getthreadcontext.
With these two functions, You can implement many functions. For example, you can use writeprocessmemory to write a debugging interrupt (INT 3, $ CC) at the entrance of a function in the debugging process ), then, when the debugging is interrupted, an interruption occurs. Then, getthreadcontext is used to get the context of the current thread. Then, the ESP parameter and other information can be obtained based on the value of the function. you can even modify the value of the EIP to allow the debugged program to jump to any address for execution, or modify the value of the Flag register to modify the execution method of the process.

After learning about the above functions, we can modify the debugging process. The specific functions are limited to our imagination, however, applications cannot be used as debugging programs. Of course, these functions can be used not only for debugging processes, but also for other processes (OpenProcess can get process handles Based on Process identifiers), such as using them to make your own game modifiers.

The following example demonstrates how to obtain the thread context and set the CPU to the single-step mode to run the program. Note that the single-step mode is slow, it may take a long time to run a large program to be debugged.
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}
Public
{Public declarations}
End;

VaR
Form1: tform1;

Implementation

{$ R *. DFM}

{Debugging information processing process}
Procedure debugpro;
VaR
Si: _ startupinfoa; (process startup information}
Pi: _ process_information; {process information}
Flage: DWORD;
Debugd: debug_event; {debugging event}
RC: Boolean;
Codecount: DWORD; {Number of running commands}
Threadhandle: thandle; {main thread handle}
Context: tcontext;
Begin
{Establish a debugging process}
Codecount: = 0;
Context. contextflags: = context_control;
Flage: = debug_process or debug_only_this_process;
Getstartupinfo (SI); {initialize the Si structure, or the process cannot be established normally}
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, 'failed to establish the debugged process ','!!! ', Mb_ OK or mb_iconerror );
Exit;
End;
While waitfordebugevent (debugd, infinite) Do
Begin {Processing Based on Event code}
Case debugd. dwdebugeventcode
Exit_process_debug_event:
Begin
MessageBox (application. Handle, 'stopped by the debugging process ','!!! ', Mb_ OK or mb_iconerror );
Break;
End;
Create_process_debug_event:
Begin
Threadhandle: = debugd. createprocessinfo. hthread;
MessageBox (application. Handle, 'created by the debugging process ','!!! ', Mb_ OK or mb_iconerror );
End;
Prediction_debug_event:
Begin
If (debugd. Exception. exceptionrecord. exceptioncode <> exception_single_step) and
(Debugd. Exception. exceptionrecord. exceptioncode <> exception_breakpoint) then
RC: = false {if an exception occurs in the debugged program, let it handle it by itself}
Else
Begin
Getthreadcontext (threadhandle, context );
{Set the trap flag of the Flag register to true so that the CPU is 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.

Other debugging APIs are attached.
1. Procedure debugbreak; stdcall;
This function generates breakpoints in the current process so that the called thread can send signals to the debugger.
2. Procedure fatalexit (exitcode: integer); stdcall;
This function gives execution control to the debugger. The behavior of the debugger is subsequently specified as the type of the debugger used.
3. Function flushinstructioncache (hprocess: thandle; const lpbaseaddress: pointer; dwsize: DWORD): bool; stdcall;
This function is the cache for the specified process refresh command. This function is only valid on multi-process computers.
Hprocess: Process Handle of the cache to be refreshed.
Lpbaseaddress: The base address pointer of the region to be refreshed. It can be 0.
Dwsize: the length of the area to be refreshed.
4. Function isdebuggerpresent; bool; stdcall;
This function indicates whether the called process runs in the description table of the debugger. This function is output from kernel32.dll.
5. Procedure outputdebugstring (lpoutputstring: pchar); stdcall;
This function sends a string to the debugger for the current application, and lpoutputstring is the string to be sent.
In Delphi, you can choose View> debug Windows> Event Log to open the event log window to view the string sent by the debug program.
6. Procedure setdebugerrorlevel (dwlevel: DWORD); stdcall;
This function sets the minimum error level. In this error level, the system will generate a debugging event and pass it to the debugger.
Dwlevel: specifies the minimum error debugging program for debugging events. If an error is equal to or greater than this program, the system generates a debugging event. This parameter must be one of the following values.
0: no errors. sle_error: Only debugging events at the error level are recorded.
Sle_minorerror: Only debug events at the minorerror and error levels are recorded.
Sle_warning: records debugging events at the warning level, minorerror level, and error level.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.