[Win32] Implementation of a debugger (iv) read registers and memory

Source: Internet
Author: User

[Win32] Implementation of a debugger (iv) read registers and memory

Zplutor
Source: http://www.cnblogs.com/zplutor/
This article copyright belongs to the author and the blog Garden altogether, welcome reprint. However, without the author's consent, this statement must be retained, and in the article page obvious location to the original link, otherwise reserves the right to pursue legal responsibility.

In the previous articles, the debugger I implemented could only passively receive debug events and output information about those events. Now, I'm going to modify it to receive commands and perform various operations on the debugged process according to the command. Start with the most basic operations first.

Gets the value of the Register

Each thread has a context that contains most of the information about the thread, such as the address of the line stacks, the address of the instruction that the thread is currently executing, and so on. The context is saved in the register, and the context switch occurs when the system is scheduling the thread, essentially saving the context of one thread into memory and then loading the context of another thread into the register.

Getting the context of a thread requires the use of the GetThreadContext function, which declares the following:

1 BOOL WINAPI GetThreadContext (
2 HANDLE Hthread,
3 Lpcontext Lpcontext
4);

The first parameter is the handle to the thread, and the second argument is a pointer to the context structure. Note that you need to set the Contextflags field of the context structure before calling the function, indicating which part of the register you want to get the value of. The values for this field are as follows:

Context_control

Gets the values of EBP,EIP,CS,eflags,ESP , and SS registers.

Context_integer

Gets the values of EAX,EBX,ECX,EDX,ESI , and EDI registers.

Context_segments

Gets the values of the DS,ES,FS , and GS registers.

Context_floating_point

Gets the value of the floating-point register.

Context_debug_registers

Gets the value of DR0,DR1,DR2,DR3,DR6, andDR7 registers.

Context_full

equals Context_control | Context_integer | Context_segments

Once the GetThreadContext function is called, the corresponding fields of the context structure are assigned, and the values of each register can be output at this point.

For other registers, it is possible to output its value directly, but the output of the EFlags register is cumbersome because each of its bits represents a different meaning and we need to lose these meanings. In general, we only need to know the following flags:

Sign

-bit

Meaning

Cf

0

Carry flag. When an overflow occurs for an unsigned number, the flag is 1, otherwise 0.

Pf

2

Parity flag. The minimum byte of the result of the operation contains an even number of 1 , the flag is 1, otherwise 0.

Af

4

Auxiliary carry flag. When the third bit of the lowest byte of the result of the operation is rounded to the high, the flag is 1, otherwise 0.

Zf

6

0 Mark. When the result of the operation is not 0 , the flag is 1, otherwise 0.

SF

7

Symbol flags. When the result of the operation is not negative, the flag is 1, otherwise 0.

Df

10

Direction flag. When the flag is 1 , the string instruction decrements the ESI and EDIafter each operation, incrementing by 0 .

Of

11

Overflow flag. When an overflow occurs for a signed number, the flag is 1, otherwise 0.

Use the bitwise AND operation to know whether a flag is 1. For example, to check if the of is 1:

1 if (context. EFlags & 0x400)! = 0) {
2
3 std::wcout << TEXT ("of");
4
5}

Hexadecimal number 0x400 only the 11th digit is 1, and the remaining bits are 0. Other signs are judged in the same way.

Read Memory contents

I am very impressed with the D command of the 16-bit debugger debug windows comes with, which can display the contents of the process memory in 16-and ASCII-encoded, for viewing data in a segment. Now I'm going to add a similar feature to the debugger.

The memory of the read process uses the ReadProcessMemory function, which is declared as follows:

1 BOOL WINAPI ReadProcessMemory (
2 HANDLE hprocess,//process handle
3 lpcvoid lpbaseaddress,//address to read
4 LPVOID lpbuffer,//A buffer pointer, save read to the content
5 size_t nSize,//number of bytes to read
6 size_t* lpnumberofbytesread//A variable pointer to save the actual number of bytes read to
7);

To successfully read the memory of the process, two conditions are required: one is that the hprocess handle has Process_vm_read permissions, and the memory range specified by lpbaseaddress and nsize must be in the user-mode address space and allocated.

For the debugger, the first condition is easy to satisfy, because the debugger has full permissions on the debugged process and can do anything about it.

The second condition means that we cannot read the memory of the process's arbitrary address, but there is a limit. Windows divides the virtual address space of the process into four partitions, as shown in the following table: (from Windows core Programming (5th edition))

Partition

Address range

Null pointer assignment partition

0x00000000~0x0000ffff

User-mode Partitioning

0x00010000~0x7ffeffff

64KB Forbidden Partition

0x7fff0000~0x7fffffff

Kernel-mode Partitioning

0x80000000~0xffffffff

Null pointer assignment Partitioning is primarily intended to help programmers detect access to null pointers, and any read or write operation on this partition throws an exception. 64KB Forbidden Partition as its name suggests, it is forbidden to access, reserved by Windows. Kernel-mode partitioning is used by the kernel portion of Windows, and processes running in the user state cannot access the zone. The process can access only the memory of the user-mode partition, and access to other partitions throws a Access_violation exception.

In addition, not any part of the user-mode partition can be accessed. We know that in 32-bit protected mode, the 4GB address space of the process is virtual and does not exist in physical memory. If you want to use a certain portion of the address space, you must first submit a request to the operating system to have the operating system allocate physical memory for that part of the address space. Only the allocated address space is accessible, and attempting to access an unallocated address space still throws a Access_violation exception.

Is the case where the readprocessmemory call succeeds, the gray part is the allocated part of the user mode address space, and the dashed part is the range specified by lpbaseaddress and nsize:

ReadProcessMemory succeeds only if the length of the dashed portion is less than or equal to the length of the gray part.

The following images are the case where the readprocessmemory call failed:

This begs the question: how do you deal with readprocessmemory failures? Everyone's ideas may be different, and here's how I handle it: for bytes that cause ReadProcessMemory to fail, with "??" To express. As shown in the following:

D 3FFFFFD0 indicates that memory starting from address 0x3fffffd0 is displayed. Because the address space before 0x40000000 is unassigned, the previous 48 bytes show "??".

Note that this is handled in bytes, which means that a readprocessmemory is called once for each byte. If you want to display 128 bytes, you call ReadProcessMemory128 times. You would have thought it would be inefficient to do this, but with actual usage, the display speed is acceptable, with almost no difference in the way that a readprocessmemory is called to read all the memory.

You can refer to the sample code for a specific procedure. If you have a better idea, you might want to share it.

As for the character on the right, I decoded the bytes using only the ASCII character set, not the ANSI character set. The reason is that Chinese characters use two bytes, if the first byte of a Chinese character is at the end of a line, and the second byte is in the head of the next line, how can this be handled? I couldn't think of a good solution, so I had to give up the ANSI character set.

The ASCII characters between 0x00~0x1f and 0x81~0xff cannot be displayed, I have "." respectively. And the "?" To replace.

Sample code

The structure of this minidebugger has been greatly improved, mainly in order to support the interaction with users and to add later functions. Note that the debugger only supports single-threaded programs, and if you use it to debug a multithreaded program, it can cause both to be stuck in a blocking state. Of course, it is not difficult to change to support multithreading, you can try to do so. Comments are made in the code and are not discussed here. The following are the currently supported commands:

s path

Start the debugging process and start debugging. If there are spaces in the path, enclose the path in double quotation marks. For example: S C:\windows\notepad.exe.

T

Ends the debugging process and stops debugging.

g [C]

continues to be executed by the debug process. If no parameter c is taken, the exception is not handled, and the parameter C indicates that the exception has been handled.

R

Displays the value of the register of the process being debugged.

d [Address] [length]

Displays the memory of the process being debugged. If the length parameter is omitted, 128 bytes are displayed, and if two parameters are omitted, the 128 bytes at the EIP address are displayed.

Q

End Debugging and exit the debugger.

If you want to let the debugging process run to a stop to test the various commands, you can add __asm int 3 to the code, or throw an exception to let the debugger catch the exception.

Http://files.cnblogs.com/zplutor/MiniDebugger4.rar

[Win32] Implementation of a debugger (iv) read registers and memory

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.