Use WinDbg to debug Windows Kernel Process Analysis (2)

Source: Internet
Author: User
Tags ssdt

Use WinDbg to debug Windows Kernel Process Analysis (2)

The previous article introduced the basic environment settings and some basic debugging skills for windbg to debug the kernel. This article introduces some advanced debugging skills for windbg.

0 × 01 use breakpoint to track data

Breakpoint is usually used to pause the Execution Code we are interested in. For example, when a function is called, we can also use the WinDbg breakpoint command string to track some information. Here, we will focus on tracking interesting information about specific user mode processes, that is, an example of writing specific data NOTEPAD. EXE to a disk. Before starting, we need to open a notepad instance in our virtual machine. Now we can create a breakpoint to intercept the data written to notepad by the file system and display the data to be written to the disk.

The first step is to find some information about the notepad.exe process to ensure that we only break down in this process, rather than every process. The information we need to find is a pointer to the EPROCESS structure. The EPROCESS structure is used to represent the main kernel data structure of a process. You can see the information that contains the "DT _ EPROCESS" (dump type in the EPROCESS structure. To find the EPROCESS structure of a given process, we can call it! Process extension command. This extension command prints information about the active processes in the target system. We filter the notepad process and display only the minimum information:

 

The EPROCESS pointer is blue to highlight the "PROCESS" field. We will use this value next.

We need to set the NtWriteFile breakpoint in the kernel. This is a system call. This function is called when all user modes are written to the disk. By setting a breakpoint here, we can see all the processes in which the system writes data to the disk. This is annoying, so we will use the above EPROCESS value and require the NtWriteFile function to be interrupted from the context of the selected process. You can run the following command:

 

 

 bp /p fffffa800295d060 nt!NtWriteFile "da poi(@rsp+30); g"

 

This is only set in our process (use our EPROCESS value through/P) NT! NtWriteFile (NT is the name of the kernel module) breakpoint. When a breakpoint hits, the quoted command runs. Here, each command is separated by a semicolon. The notepad command is used to display data, and then "g" is used to restart the Virtual Machine for execution. However, why is the result of "da poi (* @ rsp + 30)" written buffer data?

To understand this part, we need to look at the NtWriteFile function prototype:

 

 

NTSTATUS NtWriteFile(

  _In_     HANDLE           FileHandle,

  _In_opt_ HANDLE           Event,

  _In_opt_ PIO_APC_ROUTINE  ApcRoutine,

  _In_opt_ PVOID            ApcContext,

  _Out_    PIO_STATUS_BLOCK IoStatusBlock,

  _In_     PVOID            Buffer,

  _In_     ULONG            Length,

  _In_opt_ PLARGE_INTEGER   ByteOffset,

  _In_opt_ PULONG           Key

);

 

From here

In the prototype of this function, we are interested in the Buffer parameter. The data in these buffers is finally written to the disk through function calls. In Microsoft's 64-bit call conventions, the first four parameters are passed by registers (RCX, RDX, R8, and R9), and the remaining parameters are passed through stacks. Although the first four parameters pass the call convention in the register, it is required to allocate Space on the stack (this is called Home Space ). Since Buffer is 6th parameters, after the Home Space and fifth parameters. This means that, after the stack is interrupted, the stack is like this:

 

The da poi (@ rsp + 30) command is used to retrieve the value in the register RSP, add 30 h to point to 6th parameters, and then use POI () to reference this value (POI () returns a pointer size value, similar to * in C ). Finally, we pass this address into da (ASCII ). We can monitor the buffer data because we know that notepad stores plain text instead of binary files. Run this breakpoint and save some text in Notepad. The WinDbg output is as follows:

 

Using this technology, you can track interesting information through the kernel.

0 × 02 more advanced command usage

Through debugging to manipulate some data, more meaningful results are often obtained. A good example shows that some of the technologies are system service description tables (SSDT ). This SSDT forms a system call table generated by all system calls. The SSDT exported by the kernel is a structure with the following format symbol KeServiceDescriptorTable:

 

 

typedef struct _KSERVICE_DESCRIPTOR_TABLE {

    PULONG ServiceTableBase;         // Pointer to function/offset table (the table itself is exported as KiServiceTable)

    PULONG ServiceCounterTableBase; 

    ULONG  NumberOfServices;         // The number of entries in ServiceTableBase

    PUCHAR ParamTableBase; 

} KSERVICE_DESCRIPTOR_TABLE,*PKSERVICE_DESCRIPTOR_TABLE;

 

In Windows, ServiceTableBase is a pointer to a function pointer array. In 64-Bit mode, ServiceTableBase points to the 32-Bit Array offset value, all of which are relative to the location of the KiServiceTable table in the memory, this makes it impossible for visualization to use commonly used memory display commands (such as dds. Instead, we will have to use more advanced WinDbgs commands to iterate over the list and manipulate the data to a more appropriate form.

Let's take a look at how the offset is in the memory. We can use the dd (DWORD display) command to list the array offset values. Use the/c 1 option to instruct the debugger to display a DWORD per line:

 

 

kd> dd /c 1 KiServiceTable

fffff800`02692300  040d9a00

fffff800`02692304  02f55c00

fffff800`02692308  fff6ea00

fffff800`0269230c  02e87805

fffff800`02692310  031a4a06

fffff800`02692314  03116a05

...

 

 

These values are at least four digits after being shifted to the left and encoded with other data. In order to form the Absolute Memory Address for each value we need, we need to shift 4 to the right and add the KiServiceTable address. We want to do this at each entry point of the table and output the symbols associated with the absolute address. To achieve this, we can use the. foreach command to iterate and use the. printf display symbol. The following is a command implementation that will explain and explain each part:

 

.foreach /ps 1 /pS 1 ( offset {dd /c 1 nt!KiServiceTable L poi(nt!KeServiceDescriptorTable+10)}){ .printf "%y\n", ( offset >>> 4) + nt!KiServiceTable }

 

. Foreach -- this step specifies each token (in our example, we use the dd command to provide the token ). These parameters/PS 1 and/PS 1 allow foreach to skip one token per second. This is because the dd command output <address> <value> is only interested in the current value. These options skip the token address each time.

Offset -- declare a variable named offset, which saves the token of the current foreach iteration (current offset value)

Dd -- run the dd command to display the DWORD offset list, which will be iterated by. foreach. /C 1 ensure that only one DWORD is output in each line. Nt! KiServiceTable is the address we will display (this is an offset array )." L poi (nt! KeServiceDescriptorTable + 10) "describes the number of values to be displayed. In this case, we retrieve 16 bytes (10 H) and POI () starting from the KeServiceDescriptorTable pointing to the NumberOfServices struct, and then indirectly reference the value stored in the actual address, for example, the valid entry value in the table.

. Printf -- printf command for us to execute formatted printing. Here we use the formatted string % y to print the symbol to the given memory address. When we pass a parameter "(offset >>> 4) +! NT KiServiceTable ", which is the address to which the current offset value is shifted four places to the right and added to KiServiceTable. We use> operator instead of> operator to maintain the symbol bit, because some values represent negative offsets.

If the flag is set correctly, the output result of the preceding command is as follows:

 

 

kd> .foreach /ps 1 /pS 1 ( offset {dd /c 1 nt!KiServiceTable L poi(nt!KeServiceDescriptorTable+10)}){ .printf "%y\n", ( offset >>> 4) + nt!KiServiceTable }

nt!NtMapUserPhysicalPagesScatter (fffff800`02a9fca0)

nt!NtWaitForSingleObject (fffff800`029878c0)

nt!NtCallbackReturn (fffff800`026891a0)

nt!NtReadFile (fffff800`0297aa80)

nt!NtDeviceIoControlFile (fffff800`029ac7a0)

nt!NtWriteFile (fffff800`029a39a0)

 

The result should show a list of SSDT functions that can be called by the main kernel systems of user-mode code.

0 × 03 Summary

I hope you can start to use the debugger and explore the operating system with confidence. By combining this series of articles, you can start to sort out the internal working principles of Windows, which can be used to help identify problems and vulnerabilities, as well as list some security-related technologies and commands. It is important to work with this knowledge and the debugger to understand how to build Windows and the API layer for user mode and kernel mode interaction.

Related Article

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.