News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

NtDll errors: How does the kernel know the difference between read and write?

Started by jj2007, May 28, 2012, 07:41:52 AM

Previous topic - Next topic

jj2007

Exception C0000005 uses this string:
The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s"

Any idea how NtDll knows whether it was read or write? The exception code is the same...

qWord

AFAIK this information is supplied by the processor through the error code of the corresponding (exception-) interrupt (GP,PF,...)
MREAL macros - when you need floating point arithmetic while assembling!

zooba

According to Intel's System Programming Guide there is an extra error code included with the exception, but this is zero for most (possibly all; I didn't check) simple memory accesses and does not specify whether it was a read or a write. In effect, there is no way to tell directly from the exception whether it was a read or a write that caused it. Indirectly, you could look at the instruction that caused it (the value of the IP is included with the exception) to see whether it was reading or writing (or some other operation which may also cause a GP fault).

I haven't looked into the Windows code, but I do know that the divide error exception (which could be a divide by zero or an overflow) is determined by decoding the instruction and checking register values to find the original value of the denominator. I assume that a similar process is used for a GP fault; looking up whether the instruction would have been reading or writing (or possibly another cause - the guide lists 31 possible causes, some of which are "everything listed in chapter/section #").

Cheers,
Zooba  :t

Edit to clarify my first paragraph, which was really poorly worded.

dedndave

maybe it looks at the instruction that generated the exception ?

MichaelW

Well Microsoft, here's another nice mess you've gotten us into.

zooba

Quote from: MichaelW on May 28, 2012, 09:45:17 AM
Perhaps the exception handler is calling IsBad****Ptr.

Oh god I hope not... the IsBad***Ptr functions set up an exception handler and return TRUE if it is triggered, but I'm not sure if that works within another handler or even from kernel mode.

Those functions are not recommended for use, since the result is unreliable and the side effects potentially significant, so I'd be very surprised if they were being used here.

Tedd

Page-fault exceptions (CPU generated) provide an 'error code' that contains flags, including one to indicate whether the exception was caused by a read or write.
The OS exception handler can use this to react accordingly.
In this case, NTDLL pushes the appropriate string and creates its own 'exception' code.
Potato2

MichaelW

Quote from: zooba on May 28, 2012, 09:58:39 AM
Quote from: MichaelW on May 28, 2012, 09:45:17 AM
Perhaps the exception handler is calling IsBad****Ptr.

Oh god I hope not... the IsBad***Ptr functions set up an exception handler and return TRUE if it is triggered, but I'm not sure if that works within another handler or even from kernel mode.

Those functions are not recommended for use, since the result is unreliable and the side effects potentially significant, so I'd be very surprised if they were being used here.

Well, considering that Microsoft created those functions I have doubts that they would shy away from using them as part of a "postmortem" investigation.


Well Microsoft, here's another nice mess you've gotten us into.

zooba

Quote from: MichaelW on May 28, 2012, 10:32:34 AM
Well, considering that Microsoft created those functions I have doubts that they would shy away from using them as part of a "postmortem" investigation.

There are plenty of reasons why handling a GP fault isn't "postmortem" - guard pages are a prime example - and the Intel manual specifically states that this interrupt is continuable.

And I'm sure whoever created those functions (I'd guess it was a single developer, surprising as that may seem) would be embarrassed by them now, but unfortunately they shipped and it's near impossible to remove APIs later. They are quite clearly marked as deprecated, though, and have been for a number of years.

MichaelW

Quote from: zooba on May 28, 2012, 02:16:26 PM
Quote from: MichaelW on May 28, 2012, 10:32:34 AM
Well, considering that Microsoft created those functions I have doubts that they would shy away from using them as part of a "postmortem" investigation.

There are plenty of reasons why handling a GP fault isn't "postmortem" - guard pages are a prime example - and the Intel manual specifically states that this interrupt is continuable.

I was assuming that in this case it was postmortem, but in any case wouldn't the "system" know whether or not it was?
Well Microsoft, here's another nice mess you've gotten us into.

zooba

Quote from: MichaelW on May 28, 2012, 03:38:48 PM
I was assuming that in this case it was postmortem, but in any case wouldn't the "system" know whether or not it was?

I guess by the time it gets to formatting the error string it may be able to assume that there will be no recovery - calling FormatMessage directly would require you to provide the value for %s.

My earlier example of division by zero/underflow is not quite the same here, since that determines different status codes while access violations only have the one code. Still, responding to an access violation by trying to cause it again sounds like a bad enough approach that any dev would run away from it.  :biggrin:

Actually, the easier way to prove that they're decompiling the faulting instruction rather than using IsBad***Ptr is that those functions weren't added until XP, and we had access violations well before then  :bgrin:

Cheers,
Zooba  :t

jj2007

Quote from: Tedd on May 28, 2012, 10:01:34 AM
Page-fault exceptions (CPU generated) provide an 'error code' that contains flags, including one to indicate whether the exception was caused by a read or write.
The OS exception handler can use this to react accordingly.
In this case, NTDLL pushes the appropriate string and creates its own 'exception' code.

Tedd, any idea where this is documented, or how to read these flags? The flags and reg values provided by Olly are identical for read or write :(

By the way, invoke IsBadReadPtr, 111h, 222h uses SEH to check if the address is readable. So Michael's suspicion might be right...

MichaelW

Well Microsoft, here's another nice mess you've gotten us into.

qWord

GetExceptionInformation() returns this information through the member EXCEPTION_RECORD.ExceptionInformation, when called from an exception handler.

EDIT: It is a macro, which calls a function named _exception_info (maybe CRT)
MREAL macros - when you need floating point arithmetic while assembling!

Tedd

Quote from: jj2007 on May 28, 2012, 05:47:49 PM
Tedd, any idea where this is documented, or how to read these flags? The flags and reg values provided by Olly are identical for read or write :(

Intel System Programming Guide: Paging: Page-Fault Exceptions (section 4.7 in the current release.)

You won't be able to access the error code directly unless you're the kernel page-fault handler; so unless the handler copies that information to you in some form, I'm not sure you can.


As for IsBad***Ptr, this still wouldn't indicate whether the faulting instruction was a read or write, just whether the memory it tried to access was readable or writable, and in many cases it's neither (missing page, no access.)
Potato2