DynamoRIO / DynamoRIO/dynamorio

[APP CRASH] Memory corruption when delivering CONTEXT of non-suspended thread with NtGetContextThread on WoW64

Open
#4,591 2 comments 0 reactions 0 assignees View on GitHub
help wanted OpSys-Windows
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.