Subverting the windows kernel pdf




















Share This Paper. Background Citations. Methods Citations. Citation Type. Has PDF. Publication Type. More Filters. Rootkit detection from outside the Matrix.

Journal in Computer Virology. View 1 excerpt, cites background. SMM rootkits: a new breed of OS independent malware.

SMM rootkit: a new breed of OS independent malware. An undergraduate rootkit research project: How available? If a program launched under a guest account duplicates the token of the System process running at highest privileges , and assigns it to itself, then this program now has full privileges too. It can also impersonate the token and use it for privileged APIs or access to secure objects.

Usually interrupts jump to a specific location kernel-mode, but they can be created with a pointer inside a user-mode program. However, callgates and interrupts can only be created from kernel-mode, because theyre located in Ring 0 memory.

Backdoor exists in Windows NT, similar to Linux. Mapping usually done by CPU using a table. Doing it manually requires reading the table, but the table is in kernel mode memory too! So how can we do the mapping? One way would be a brute force scanning approach with a known value at a known virtual address. However, the mapping relation can change even between pages bytes. Code now runs in Ring 0. Use it to edit kernel structures, such as the process list to hide processes.

Use it to edit the code inside Kernel APIs that return files or processes in order to hide certain ones. Some IDS software blocked access to the object through hooking. Valid reason for ignoring the issue: object only accessible as an administrator. If a malicious user is already an administrator, then he can already load a driver, format the disk, etc. The API allows direct access to kernel memory through the virtual address no need for mapping and using physical memory. The user-mode debugger needed the API for most of its commands.

Within a few months, was discovered and came into use by malware and low-level software. Again, this needs administrator access.

The only extra requirement was a special privilege recall the security intro , which can be acquired with a single call. Was not considered a threat by Microsoft, and its usage is relatively low in the wild.

Windows shipped with these features intact. Microsoft removed both threats in Service Pack 1. Was not a silent removal. Revealed an interesting change in mentality: due to the prevalence of rootkits and most Windows users running in the administrators context, the administrator can do anything concept became any Windows application can do anything.

Is this the end of user-mode rootkits with Ring 0 access? This memory is physical, and needs to be mapped. Kernel needs to know which addresses should I map? Very simple pair of Base and Size data. Designers had some idea of the risks: addresses below 0xC are skipped.

Remember, this is physical memory. We need to depend on the mask shown earlier, but its not reliable on anything else then the base kernel pages. It fails! It can only be called by a process with the Subsystem Privilege recall Tokens. But Recall that tokens can be duplicated for impersonation!

System process token was not created with this access level for the Administrator account recall ACLs. Open the system process token for ACL edit access finally, something that doesnt fail. Re-open the token with duplicate access and call NtDuplicateToken to duplicate it as an impersonation token.

Impersonate the current thread as a Local System Thread. Acquire Set Primary Token Privilege, required to set a new process token. Duplicate the token again, as a primary token. Call NtSetInformationProcess to set the token as primary. Function probes parameters, so that kernelmode doesnt crash while attempting to read them, but we were sending NULL data.

Called NtVdmControl with this new structure it fails! VDM wants the memory at 0x0 to be already allocated so that it can copy some data inside. How to allocate memory at 0x0? Easy solution: use 0x1. Once allocated, NtVdmControl might still fail: the memory it tries to map might not be free.

Therefore, we need to make sure its free, and release it beforehand. Could be a problem if memory allocated is critical. Better solution: dont use any other DLLs then ntdll, and calculate the address you need beforehand, and immediately allocate it. When calling NtVdmControl, free it right before.

Now that this works, actual flaw can be exploited. Allocate 0xx and allocate the pointer youll need. Free the pointer youll need and call NtVdmControl. Write your patch it fails! Actually, it doesnt, but the changes dont show up. How do we solve this latest problem? Writes seem lost because the memory was allocated by the kernel, in kernel mode, with kernel flags. Therefore, user mode has no access to it, from the CPUs perspective, so they are silently ignored.

Yet another ace in the hole: NtWriteVirtualMemory. Slightly more annoying then being able to do direct memory writes overhead of an API , but thankfully, it works! Now that we can patch kernel code, what can we do? Best solution: restore lost functionality in SP1. Even better, restore ZwSystemDebugControl.

Microsoft states that even administrators cant open the object anymore, and that the protection is specifically for user-mode access, in general. Therefore, either a special flag is on the object makes sense , or a string compare is done in the kernel ugly and problematic: could potentially use a symbolic link to bypass.

Creates the memory section with ObCreateObject, just like any other object. However, a strange flag is used on ObjectAttributes. Attributes: 0x Attributes are defined in ntdef. Highest one has always been 0x, so this flag definitely stands out. Wrote a test driver that created a new object, using this flag: object became protected as well.

This demonstrated a new kernel check for this flag, or something similar and generic. Objects have meta-structures which are internally used by the Object Manager to handle them for example, the reference count.

In fact, what you do with this technique is largely up to your imagination. Now that you understand the basic theory of API hooking and what you can accomplish using it, we will detail implementing an API hook in a user process in the following three sections. The first section outlines how an IAT hook works, and the second section describes what an inline function hook is and how it works.

The third section covers injecting a DLL into a userland process. The simpler of the two userland hooking processes is called Import Address Table hooking. When an application uses a function in another binary, the application must import the address of the function. Once your rootkit's hook function is in the application's address space, your rootkit can parse the PE format of the target application in memory and replace the target function's address in the IAT with the address of the hook function.

Then, when the function is called, your hook will be executed instead of the original function. Figure illustrates the control flow once the IAT is hooked. Figure Normal execution path vs. We will discuss how to get your rootkit into the address space of the target application later in the chapter. For code to hook the IAT of a given binary, see the section titled Hybrid Hooking Approach near the end of this chapter.

You can see from Figure that this is a very powerful yet rather simple technique. It does have its drawbacks, though, in that it is relatively easy to discover these types of hooks. On the other hand, hooks like these are used frequently, even by the operating system itself in a process called DLL forwarding. Even if someone is trying to detect a rootkit hook, determining what is a benign hook as opposed to a malicious hook is difficult. Another problem with this technique has to do with the binding time.

Some applications do late-demand binding. With late-demand binding, function addresses are not resolved until the function is called. This reduces the amount of memory the application will use.

These functions may not have addresses in the IAT when your rootkit attempts to hook them. The second userland hooking process we will discuss is called inline function hooking. Inline function hooks are much more powerful than IAT hooks. They do not suffer from the problems associated with the binding time of the DLL. When implementing an inline function hook, your rootkit will actually overwrite the code bytes of the target function so that no matter how or when the application resolves the function address, it will still be hooked.

This technique can be used in the kernel or in a userland process, but it is more common in userland. Typically, an inline function hook is implemented by saving the first several bytes of the target function that the hook will overwrite. After the original bytes are saved, an immediate jump is usually placed in the first five bytes of the target function.

The jump leads to the rootkit hook. The hook can then call the original function using the saved bytes of the target function that were overwritten. Using this method, the original function will return execution control to the rootkit hook.

Now, the hook can alter the data returned by the original function. The easiest location to use for placement of an inline hook is within the first five bytes of the function.

There are two reasons for this. The first concerns the structure of most functions in memory. Most of the functions in the Win32 API begin the same way. This structure is called the preamble. The following block of code is the Assembly language for typical function preambles.

It is important to determine which version of the function preamble your rootkit is to overwrite. An unconditional jump to your rootkit hook on the x86 architecture will usually require five bytes. The first byte is for the jmp opcode, and the remaining four bytes are the address of your hook. An illustration of this is provided in Chapter 5.

In the pre-XP SP2 case, you will overwrite the three bytes of the preamble and two bytes of some other instruction. To account for this, your patching function must be able to disassemble the beginning of the function and determine instruction lengths in order to preserve the original function's opcodes. The preamble is exactly five bytes, so you have exactly enough room. Microsoft actually did this to allow for hot patching insertion of new code without rebooting the machine.



0コメント

  • 1000 / 1000