Uninformed: Informative Information for the Uninformed

Vol 9» 2008.Jan

Interception of SetThreadContext

As previously described, the Lockdown modules attempt to disable the use of the processor's complement of debug registers in order to make it difficult to utilize so-called hardware breakpoints during the process of reverse engineering or analyzing a Lockdown module. This scheme is, at present, relatively easily compromised, however.

There are several possible attacks that could be used:

  1. Hook the SetThreadContext API and block attempts to disable debug registers (programmatic).
  2. Patch the import address table entry for SetThreadContext in the Lockdown module to point to a custom routine that does nothing (programmatic).
  3. Patch the Lockdown module instruction code to not call SetThreadContext in the first place (programmatic). However, this is approach is considered to be generally untenable, due to the memory checksum protection scheme.
  4. Set a conditional breakpoint on `kernel32!SetThreadContext' that re-applies the hardware breakpoint" state after the call, or simply alters execution flow to immediately return (debugger).

Depending on whether the attacker wants to make programmatic alterations to the behavior of the Lockdown module via hardware breakpoints, or simply wishes to observe the behavior of the module in the debugger unperturbed, there are several options available.

The suggested counters include techniques such as the following:

  1. Verify that the debug registers were really cleared. However, this could simply be patched out as well. More subtle would be to include the value of several debug registers in the checksum calculations, but this would also be fairly obvious to attackers due to the fact that debug registers cannot be directly accessed from user mode and require a call to Get/SetThreadContext, or the underlying NtGet/SetContextThread system calls.
  2. Include additional calls to disable debug register usage in different locations within the Lockdown module. To be most effective, these would need to be inlined and use different means to set the debug register state. For example, one location could use a direct import, another could use a GetProcAddress dynamic import, a third could manually walk the EAT of kernel32 to find the address of SetThreadContext, and a fourth could make a call to NtSetContextThread in ntdll, and a fifth could disassemble the opcodes comprising NtSetContextThread, determine the system call ordinal, and make the system call directly (e.g. via `int 2e'). The goal here is to add additional work and eliminate "single points of failure" from the perspective of an attacker seeking to disable the anti-debugging feature. Note that the direct system call approach will require additional work in order to function under Wow64 (e.g. x64 computers running native Windows x64).
  3. Verify that all IAT entries corresponding to kernel32 actually point to the same module in-memory. This is risky, though, as in some cases (such as when the Microsoft application compatibility layer module is in use), these APIs may be legitimately detoured.