3

I find myself playing in strange territory lately, venturing far outside my comfort zone to test some theories. At present I want to return True every time a specific program calls IsDebuggerPresent, without actually debugging the program.

Since I'm not a software developer, I'd really rather avoid writing code to do API hooking. My next thought was to use a modified kernel32.dll in the same directory as the program, counting on "DLL Load Order Hijacking". So... I modified a copy of the dll, essentially replacing the export for IsDebuggerPresent with mov eax, 1

If I open the DLL in IDA and examine the export, it shows exactly the code I patched in, but if I run the executable, when it makes the call to IsDebuggerPresent the same address I modified instead shows a JMP to the proper IsDebuggerPresent instructions.

Is what I'm trying to do even feasible, or do I have to do API hooking to make it work? I'm Really looking for a simple POC, so again, I'd prefer not to have to figure out a metric buttload of C++ just to test a theory.

3 Answers 3

5

Windows has a concept of trusted libraries to hamper attacks like these:

Dynamic-Link Library Search Order

Citing from the search order:

If the DLL is on the list of known DLLs for the version of Windows on which the application is running, the system uses its copy of the known DLL (and the known DLL's dependent DLLs, if any) instead of searching for the DLL. For a list of known DLLs on the current system, see the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs.

So for your case, I would suggest giving API hooking a try ;) It really isn't too hard (Windows to the rescue for all your shady needs).

edit:

some pointers for hooking

You may go ahead and use Windows Hooking API

However, it is quiet straight forward to do yourself:

  1. Use GetProcAddress to find GetDebuggerPresent in your address space (Windows does not like ASLR). You can assume it is at the same location in the other process.

  2. Backup the first few bytes (ReadProcessMemory), insert any hook (WriteProcessMemory) and you code (VirtualProtectEx).

side node: you may need to elevate the permissions of your process first (OpenProcessToken, ...).

edit 2:

I found some of my old code. You can find it here. Please note this code was written for a research project to avoid Sandbox detection and that I was a student at the time (i.e. the code may not be high quallity).

2
  • Fair enough. Any chance you could point me in the direction of a decent tutorial? When I say that I don't know C++, please understand that on the few occasions I've written anything in C++, I have to disassemble them to understand what they are doing, and if they'll do what I want. High-level languages have never really made any sense to me. Commented Feb 7, 2017 at 17:31
  • See my second edit ;) Its clean C code.
    – Nordwald
    Commented Feb 8, 2017 at 7:33
1

As mentioned above, just placing the DLL in the same directory won't be enough for certain windows DLLs, as windows searches for those in specific paths as documented about Dynamic-Link Library Search Order.

However, there's some potential trickery with the knownDlls list you can manipulate to succeed in your DLL replacing attempts:

  1. You could remove specific DLLs from the list, allowing yourself (and others, thus exposing the machine to some potential risk) to load said DLL from the application's location.

  2. You could replace the DLL name stored as the value of the key in the same registry path. Instead of a DLL name, simply place a full path and the DLL will be loaded from your specified location for all processes.

Although this might not be advised as there's a risk of a malicious entity exploiting those changes to hijack DLLs on your machine, it's definitely an easy way to test your endeavors without writing any API hooking code, as requested :)

Another approach would be searching for some pre-made API hooking utilities (there, are, plenty)

3
  • yes, but (1) and (2) are ugly hacks that have system-wide implications, like visiting someone's house and changing their carpet. The changes should be limited to the current process. Commented Feb 10, 2017 at 20:03
  • Yes. I mentioned that in my original answer. These approaches answer OPs original request: a easy way that will not require hooking, and I would think is perfectly fine when done in a VM or as part of a one time limited test (as is implied by OPs POC remark).
    – NirIzr
    Commented Feb 10, 2017 at 20:10
  • Some of those DLLs seem to be hardcoded these days (I suppose into the smss binary or so). Point being that the registry isn't the sole source for the setting of what DLL is a known DLL.
    – 0xC0000022L
    Commented Jun 13, 2022 at 7:19
0

You could attempt the indirect route instead. IsDebuggerPresent() merely checks the respective field in the Process Environment Block (PEB) to find out whether a process is being debugged.

So instead of modifying a single function from a particular DLL to return the result, you could manipulate the source used by said function to retrieve its result (yes, there are other functions that consult this very data field).

Looking at a recent version of kernelbase.dll (10.0.19041.804) we find via IDA:

IsDebuggerPresent proc near
                mov     rax, gs:60h
                movzx   eax, byte ptr [rax+2]
                retn
IsDebuggerPresent endp

... which in its annotated form would be something like:

IsDebuggerPresent proc near
                mov     rax, gs:60h     ; address to PEB
                movzx   eax, [rax+PEB.BeingDebugged]
                retn
IsDebuggerPresent endp

... and as pseudo-code:

BOOL __stdcall IsDebuggerPresent()
{
  return NtCurrentPeb()->BeingDebugged;
}

Simply modifying the "remote" PEB would be one way of achieving what you want.

In order to retrieve the "remote" PEB you can use

PROCESS_BASIC_INFORMATION::PebBaseAddress (enum member ProcessBasicInformation) via NtQueryInformationProcess() whose declarations you should also be able to glean from the winternl.h header which is part of modern Windows SDKs. Then the usual WriteProcessMemory() method should work to set this value in the remote process.

You could also try a typical DLL placement attack on some dependency of your target program (e.g. version.dll which isn't a known DLL) and have that loaded DLL do the manipulation of the PEB for you from within the remote process.


And always keep in mind that in order to do effective reverse engineering, you should first have a firm grasp of forward engineering 😉

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.