DynamoRIO / DynamoRIO/dynamorio
[APP CRASH] Memory corruption when delivering CONTEXT of non-suspended thread with NtGetContextThread on WoW64
- Dominant language
- C
- Stars
- 3.2k
- Forks
- 629
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 31
Description
**Describe the bug**
DynamoRIO introduces a memory corruption when delivering the output of `NtGetContextThread` over a thread currently not suspended (i.e. the calling thread or another thread concurrently running). It writes extra `0xa0` bytes past the CONTEXT structure, causing a memory corruption that may or may not go silent depending on the surroundings of the holding buffer.
**To Reproduce**
I have attached three instances of a sanitizer program that allocates a page and fills it with a magic byte, places a CONTEXT object with a displacement of 256 bytes in it, and checks if the 256 bytes before and after the CONTEXT get touched by an invocation of `NtGetContextThread` over:
- the caller thread (bug) `sanitizer-self.exe`
- some suspended thread (no bug) `sanitizer-suspThread.exe`
- some other running thread (bug) `sanitizer-runningThread.exe`
I have attached C source and executables for the three variants. To run them just use `drrun.exe` and check that the sanitizer emits `X` in the output for locations corresponding to polluted bytes.
[NtGetContextThread-sanitizer.zip](https://github.com/DynamoRIO/dynamorio/files/5649473/NtGetContextThread-sanitizer.zip)
**Expected behavior**
Only the bytes belonging to CONTEXT shall be touched, so the sanitizer should print no `X` but only `-` when validating every byte surrounding the object. In the version `sanitizer-self.exe` we can see that fields in the CONTEXT object seem to be valid, as it displays the correct EBP value under both native (reads EBP with inline assembly) and context information.
**Pasted Text**
Execution examples:
```
C:\disk\path>..\..\DynamoRIO-Windows-8.0.18585\bin32\drrun.exe -- sanitizer-runningThread.exe
Size of CONTEXT struct: 2cc
Polluted bytes before CONTEXT marked with X (last is closest):
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------
Thread terminated
Polluted bytes after CONTEXT marked with X (first is closest):
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
--------------------------------------------------------------------------------
----------------
Polluted bytes (total): 0xa0
C:\disk\path>..\..\DynamoRIO-Windows-8.0.18585\bin32\drrun.exe -- sanitizer-suspThread.exe
Size of CONTEXT struct: 2cc
Polluted bytes before CONTEXT marked with X (last is closest):
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------
Polluted bytes after CONTEXT marked with X (first is closest):
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------
C:\disk\path>..\..\DynamoRIO-Windows-8.0.18585\bin32\drrun.exe -- sanitizer-self.exe
Size of CONTEXT struct: 2cc
Native EBP: 2686680
Context EBP: 2686680
Polluted bytes before CONTEXT marked with X (last is closest):
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------
Polluted bytes after CONTEXT marked with X (first is closest):
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
--------------------------------------------------------------------------------
----------------
Polluted bytes (total): 0xa0
```
**Versions**
I have used the latest build 18585. This is a 32-bit application executed on Windows 7 SP1 x64.
**Additional context**
I suspect there is a bug in the output rewriting for `NtGetContextThread` for WoW64 e.g. #1141 `core/win32/os.c` and `core/win32/syscall.c`.
MSDN says that you cannot get a valid context for a running thread, but things in practice are different. The `sanitizer-self.exe` shows that EBP is retrieved correctly. Malware does such context extraction all the time (e.g. to inspect debug registers), and the test suite of DynamoRIO does `GetThreadContext` on `GetCurrentThread()` in a few spots (e.g. `suite/tests/security-win32/except-execution.c`, and `suite/tests/win32/getthreadcontext.c` which also states _"technically you're not supposed to do this, msdn says result is undefined, but we should handle it reasonably"_). I built other examples that triggered corruption for stack (hitting canaries) or data-allocated CONTEXT. I think the corruption is silent in the DynamoRIO tests above as there is plenty of stack-allocated variables between CONTEXT and the start of the stack frame.
Contributor guide
Assessment
This issue has not been assessed yet.