Log in

View Full Version : Modifying NTDLL ?


Nido
May 20th, 2009, 14:04
Is it possible to modify NTDLL and reboot ?

Can anyone suggest any pointers or resources to making modifications to NTDLL ?

I'm not after other peoples snippets of the change they made to fulfill some requirement, but a broader overview of the concerns with simply making a modifications to NTDLL. Things to be aware of, things to check for, etc...

Things I can contribute:
* Have a way to recover the system (bootable ISO / USBdisk with something like BartPE is one easy way)
* Don't use your own workstation have a 2nd PC.
* Ensure you always fixup the PE header checksum.

As you can see my knowledge soons runs out. The purpose of my interest is to have more control over anti-debugging measures without using ring-0.


One other question concerning NTDLL there are exported functions NtXXXX and ZwXXXX the NtXXXX series I understand are called from the user-mode context where the state of the machine is exactly the same as a the application.

I'd like to understand more about the ZwXXXX series of functions and the transitions between the two machine states. For example is the "FS" segment register which is used by user-mode to point to the Thread Local Storage (TIB/TEB), is it loaded with the same value for all contexts that ZwXXXX calls are made ?

Some of the anti-debugging area of interest have aliased implementations ("aliased" meaning 2 or more Export Address Table entries pointing to the same implementation of a function, since it is shared by the NtXXXX and the ZwXXXX series).

disavowed
May 20th, 2009, 15:40
NtXXXX should be called from user-mode context. ZwXXXX should be called from kernel-mode context. For many functions they do the same thing, but for some, ZwXXXX makes certain assumptions.

What kind of anti-debugging measures are you looking to have more control over that you expect modifying NTDLL.DLL will help with?

GamingMasteR
May 20th, 2009, 16:04
In user-mode :
ZwXxx == NtXxx
FS points to TEB (Thread Environment Block)

In kernel-mode :
ZwXxx != NtXxx
ZwXxx should be used always .
Most of NtXxx could be called when PreviousMode == KernelMode and passed buffers exist in kernel space .
FS points to KPCR (Current Processor Control Region)

Nido
May 20th, 2009, 20:16
Quote:
[Originally Posted by disavowed;80695]What kind of anti-debugging measures are you looking to have more control over that you expect modifying NTDLL.DLL will help with?


For starters:

NtQueryInformationProcess(..., ProcessDebugPort, ..., ..., ...)
NtSetInformationThread(..., ThreadHideFromDebugger, ..., ...)

Both of these method (and their ZwXXXX aliases) in the platform I am working on (WinXP SP2) directly invoke a system call entry. I have written a tiny interceptor

The implementation for these functions also have around 6 "NOP" instructions padding the call, the entrypoint of the function is not even aligned to any nice boundary. If there a reason for the padding ?

In order to fit my small intercept in I had to relocate the previous function to bunch them up to gain the 3 lots of 6xNOP instructions. I fixed up EAT and only one of the 4 affected methods is being called internally from part code in .text so those 32DISP were also fixed up to the new address. The added code in the .text us simply using up the 0x00 padding currently in the file already and extending the section size in the section header a little (I have not needed to extend the file length and move up all the segments). But I still have not gotten it to successfully bootup.

I am making use of FS segment register for TEB and then PEB access, knowing these same methods are also ZwXXXXX implementations. The use of it is basically an interception switch (I wanted to use $0x7ffe0e08 but that page is readonly) so I opted for PEB but now I shall opt for extending the .data section using a location there. (since the FS segment is different for some contents in which ZwXXXXX is being called).

Is there any glaring problem with what I am trying to achieve ? Should it be possible to make these kinds of modifications (at the moment it auto-reboots during startup, but I've not attempted many tries yet still much to learn).

Does anyone know if any other part of the OS or core DLL/SYS makes assumptions (esp with regards to NOP padding and expected load address for the moved functions) ? or anything I have overlooked that also needs some kind of fixup ?

Thanks for your replies all.

evaluator
May 21st, 2009, 05:56
proper way is driver-hook. because you need to control, when hide - when not.

Nido
May 21st, 2009, 07:14
Quote:
[Originally Posted by evaluator;80706]proper way is driver-hook. because you need to control, when hide - when not.


Thanks for the reply, but proper way in what sense ? Yes I understand a ring0 approach would be the next step but it mitigates a few points:

1) It deprives me of the learning curve associated with this approach.
2) My intercept inside NTDLL already has code/logic in it to enable/disable under my control.
3) I have the ability to run Win32 code under a form of emulation outside of a Win32 system, this allows me to perform intercepts and overwrites of data/code that are just not possible to do inside a Win32 environment (since the program would crash or just not behave correctly).
4) I have been able to verify/debug my modifications to NTDLL under this emulation in the context of the target application being run, so this presumes I can get the machine to boot (which means all other users of NTDLL needs to be happy with my modifications too, I hope to spend some more time on it later today and report back my woes, I bet it's due to my use of FS segment register access when called from ZwXXXX context).

PS. I forgot to add, the emulation doesn't emulate ring0 stuff hence why a user-space solution is being pursued because my main reversing technique is not actually done under / inside a Win32 system at all.

evaluator
May 21st, 2009, 07:45
then, are under you control NTDLL-file-content check!?

& in generic, modifying system file is incorrect approach ~:~

Nido
May 21st, 2009, 07:52
Quote:
[Originally Posted by evaluator;80708]then, are under you control NTDLL-file-content check!?

& in generic, modifying system file is incorrect approach ~:~


I do not understand your cryptic response. Maybe english is not your 1st language. Please have another go.

Kayaker
May 21st, 2009, 09:43
Have you disabled or otherwise modified Windows File Protection (WFP) so the changed ntdll isn't detected?

This may be what evaluator was alluding to. His responses are almost always purposely cryptic, but almost always useful as well. Consider them reversing challenges obfuscating some nugget of information.

BanMe
May 21st, 2009, 11:05
WFP may not need to be bypassed to implement such a solution.. a dll proxy and Peb hooking could do the job at runtime instead of directly modifying the file and having to bypass WFP

PEB Hooking article on phrack

Dll Proxy generator can be found on CodeProject

Regards BanMe

Nido
May 22nd, 2009, 07:38
Thanks for the pointer on WFP, I wasn't aware the mechanism existed, I am 100% happy to disable it since the host machine's only purpose is to assist inspection of the target (It can be reinstalled in 15mins should it be really screwed up). Would I be correct in presuming that with WFP alarms go off I get some form of Microsoft message on screen about it ? "NTDLL.DLL failed WFP validation" or some such, rather than a spontaneous reboot.

I'm not so sure on the Dll Proxy idea, I am after all modifications to be built into the DLL itself, my understanding of generating a proxy means that some VERY obvious "JMP 32DISP" instructions will end up in the address space but not be in the on-disk image. This is not good.

I found the phrack article at http://www.phrack.com/issues.html?issue=65&id=10#article again I'd like to point out I know the protection mechanism inspects the LoaderData and LDR_MODULE structures and loads the DLLs off disk manually so again the modifications described I believe would be detectable by the protection. But the article is a good read to fill in some blanks I had before.

The NTDLL.DLL modifications discussed in this thread are really to free up the debugger use on the target application under WIN32, since I have analyzed the target outside of WIN32 I already know where I can place hardware breakpoints and other such at certain points in time, I already know what the execution path is (i.e. what the target executable is expected it to do next) but I have no way of knowing at this time if that information is executing a decoy. There are a couple of areas where I'd like to compare the real WIN32 environment with debugger against the emulation environment so I can fix the emulation and prove the execution path on both WIN32 and emulator is the same. In order to do that my user-space debugger needs to work.

From a modification point of view my criteria list of what I am looking to achieve is:
* No direct EAT hooking to a new location (that is different from the on-disk default indirection jump location)
* No modification of methods within the first few instructions of the normal function (I do not need to intercept everything only a handful of functions, this means in some cases I have to analyze and write custom interception jump code that understands how to undo any modifications to the stack/registers)
* No CALLs or JMPs to any code outside of the image address space (certainly not into address space of injected DLLs and such).
* 100% Working relocation table (relocations positioned over the top of overwritten code need to be quieted).

I know that the target executable loads DLL image(s) from disk into address space, fixes them up and performs some execution of them, so for all intents and purpose my modifications need to be "real".

deroko
May 22nd, 2009, 09:55
Here we go ok PEB hooking is ok, if you check this code here for kernel32.dll you will get the idea : http://accessroot.com/arteam/site/download.php?view.267

What I do here is to hook kernel32 and advapi32 via PEB and also in fake_k32 hook CreateFileA so when target asks for real kernel32.dll I give it PEB hooked dll from disk, you may do the same here. You don't really need to hook ntdll.dll in whole system, that's not required at all in your scenario. All you have to hook is NtCreateFile and NtOpenFile (or Zw as it's the same in ntdll.dll), and whenever target asks for real ntdll you give it faked version from disk. It's simple as that.

Nido
May 22nd, 2009, 11:44
Quote:
[Originally Posted by deroko;80722]
You don't really need to hook ntdll.dll in whole system, that's not required at all in your scenario.


Thanks for the example I shall inspect in more detail.

With regards to "You don't really need to hook ntdll.dll in whole system" yes I do. The protection mechanism opens the NTDLL.DLL file, seeks to the implementation of ZwQueryInfomationProcess() copies 32 bytes directly from the file onto the stack and then executes it.

So please understand I do need to modify that NTDLL.DLL so those 32bytes now include my intercept code. I've also made the presumption that this code also needs to contain no relocations as I would guess no fixup is done.

Please remember ring0 is not possible. Once you factor all of these things in the easiest solution is just to patch NTDLL.DLL with a few bytes here and there.

deroko
May 22nd, 2009, 11:55
That's why you hook NtCreateFile and NtOpenFile so when it asks for ntdll.dll on disk you simply redirect to your patched dll.

BanMe
May 22nd, 2009, 12:26
to do what deroko rightly suggests from user mode with a dll substitute(proxy is bad word) and PEB hooking..

hook when process loads(The Ldr routines are good) ..
Hook LdrpCheckForLoadedDll(or something like that)as well to filter direct handles ntdll and replace them with handles to our image...I think in this fashion we could use the Handle count for the real ntdll, to have exclusive access to it. by checking its reference count...

Open fake ntdll
CreateMapView
MapViewOfFile

replace TEB.PEB.LDR_DATA.LDR_MODULE_ENTRY for ntdll with your own imagebase and replace all other pointing links(InLoadOrderModuleList,InMemoryOrderModuleList,ect..) to the old ntdll with links to our replacement that can act as a parameter logger or a trampoline of some sort...

hope this makes sense..

regards BanMe

Nido
May 22nd, 2009, 12:51
Quote:
[Originally Posted by deroko;80724]That's why you hook NtCreateFile and NtOpenFile so when it asks for ntdll.dll on disk you simply redirect to your patched dll.


I still do not understand your claim that hooking 2 additional things is easier in some way than altering a few bytes in NTDLL to allow interception of a function which I must hook anyway ? My modifications amount to approx 60 bytes of new asm, 2x32 bytes of replaced asm, 8 reloc fixups and EAT RVA and section header fixups. All mods are contained to NTDLL the execution/debugging of the asm changes can be completed inside the emulator.

But you are claiming that it easier to leave NTDLL untouched, then dynamically patch the address space when the target is being loaded/run and then to intercept an additional 2 calls (that haven't been necessary to intercept so far) to point to another file. This file then needs to have the contents of what is in memory but reconstructed as an EXE.


I am after the runtime address space to be as original as possible to an unpatched system. This is because I am trying to verify a live system against an emulated system, I am not primarily trying to reverse engineer on the Win32 system. That is just slow and a waste of time compared to the reveng speed-up gained by using an emulator as the primary reveng method.

Nido
May 22nd, 2009, 13:01
Thanks for the clarification of the explanation BanMe.

There are other anti-debugging techniques in use by the target:
* VirtualQuery (yeah yeah we can intercept that too)
* Using SEH to then deliberately test that pages are not there. Walking the address space and doing a memory access to a page. Hmm... it is now a bit harder to hide the real DLL now isn't it ?

I'm sure I could go on with the anti-debugging / anti-reversing counter measures the target has implemented. This is why the emulation has been such a good way to see what is going on in such a short space of time.

The advise is great and all; I can understand that it makes sense to you to employ these solutions. But the challenge/goals/specification I keep posing has the same basic goal, all modifications must be in-board of the affected DLLs and look as real as they can be (because there is a lot of other factors I am aware of).

disavowed
May 22nd, 2009, 14:40
does the protection you're looking at also check the digital signature on ntdll.dll? if you patch the file, the signature won't be valid anymore.

Nido
May 22nd, 2009, 15:12
Quote:
[Originally Posted by disavowed;80730]does the protection you're looking at also check the digital signature on ntdll.dll? if you patch the file, the signature won't be valid anymore.


Is the digital signature part of the WPF system ? I have seen the symbol:

ADVAPI32.DLL!CryptVerifySignatureA

located via GetProcAddress() but it has not been used yet (I guess because I am still looking at decoy execution paths).

deroko
May 22nd, 2009, 20:19
Quote:
[Originally Posted by Nido;80727]I still do not understand your claim that hooking 2 additional things is easier in some way than altering a few bytes in NTDLL to allow interception of a function which I must hook anyway ? My modifications amount to approx 60 bytes of new asm, 2x32 bytes of replaced asm, 8 reloc fixups and EAT RVA and section header fixups. All mods are contained to NTDLL the execution/debugging of the asm changes can be completed inside the emulator.


Do themida or winlic, go trough that code which I wrote, and eventually you will see what I'm doing and why.

if your approach works, that's good, do it like that... if my approach seems complicated, simply don't use it, I know that it's not complicated, as I'm using it daily.