Of what possible legitimate use are functions like CreateRemoteThread, WriteProcessMemory, and VirtualProtectEx?

There are a bunch of functions that allow you to manipulate the address space of other processes, like Write­Process­Memory and Virtual­Alloc­Ex. Of what possible legitimate use could they be? Why would one process need to go digging around inside the address space of another process, unless it was up to no good?

These functions exist for debuggers. For example, when you ask the debugger to inspect the memory of the process being debugged, it uses Read­Process­Memory to do it. Similarly, when you ask the debugger to update the value of a variable in your process, it uses Write­Process­Memory to do it. And when you ask the debugger to set a breakpoint, it uses the Virtual­Protect­Ex function to change your code pages from read-execute to read-write-execute so that it can patch an int 3 into your program.

If you ask the debugger to break into a process, it can use the Create­Remote­Thread function to inject a thread into the process that immediately calls Debug­Break. (The Debug­Break­Process was subsequently added to make this simpler.)

But for general-purpose programming, these functions don't really have much valid use. They tend to be used for nefarious purposes like DLL injection and cheating at video games.

[Raymond is currently away; this message was pre-recorded.]

Comments (26)
  1. Skyborne says:

    And the arms race between debuggers and anti-debug techniques begins….

    Back in the day, parts of AmigaOS would crash the system if the 68000's trace bit was set, to get in the way of you understanding how it did "privileged" operations in a system without an MMU.

    IIRC, it actually worked like this: the OS causes an exception, the vector points to a handler in the OS, and the exception frame indicates the faulting address.  If the handler recognizes that address (both sides of this game are fixed in ROM) then it performs the operation.

  2. Mmm says:

    Define good and nefarious.

    >> nefarious purposes like DLL injection and cheating at video games

    If I'm the user of the PC and I want to do it, it's not nefarious. It's good.

    [My definition here is "supported, adhering to sound engineering practices." -Raymond]
  3. Chris B says:

    Just out of curiosity, are there any numbers related to the number of exploits that use these functions vs. other means?  I'm mostly curious if it would be worthwhile for UAC or similar to monitor calls to these functions so that if they were called on my grandmother's computer, it would pop up an alert, but on mine I could disable said warnings since I would be using debuggers and such.

    Of course, I am assuming that my grandmother is capable of understanding the UAC warning, which seems highly unlikely.

  4. Adam Rosenfield says:

    Well you could start an arms race to make these functions more difficult to abuse, but I don't think that'd help much.  You could, say, make those functions only succeed on processes being actively debugged by the current process (malware/cheaters would just initiate a fake debugging session).  You could then only allow a process to debug another process under more restricted conditions, but I can't think of anything that wouldn't result in either "Why do I have to be an administrator to debug another process?" or "Why do I have to buy a code-signing certificate from Microsoft to run my awesome homemade debugger?" etc.

    End result: just skip the arms race and hope that code uses these functions for good and not for evil.

    Unix has the same problem.  If a process can debug another with ptrace(2), it can just as easily write data into the other process with PTRACE_POKETEXT.  Doing a CreateRemoteThread or VirtualProtectEx is a little harder, but it can be done by breaking the debuggee, setting up a fake stack frame that calls pthread_create(3) or mmap(2) and a return address of the current IP, and switching the current IP to one of those functions with PTRACE_SETREGS.

  5. Dan Bugglin says:

    @Adam Last I checked users have to be in the Debugger Users group to use a debugger.  I don't know if it's tied to these APIs, but it is most certainly tied to being able to cross a security boundary by debugging an elevated process.

    So Limited Users should be somewhat safe by default I would hope.

    ["Debugger Users" is not a standard group. It was probably added by your IDE. You can debug any process you own; the SeDebugPrivilege is for debugging processes you don't own. -Raymond]
  6. Mmm says:

    > My definition here is "supported, adhering to sound engineering practices." -Raymond

    Under that definition it totally makes sense.

  7. Anonymous Coward says:

    Back in NT 3.x, I'm pretty sure that CSRSS sometimes used Read­/WriteProcess­Memory to access buffers in the client processes, rather than passing the data over LPC.  Was that "nefarious"? :-)

    [You made me stop my vacation so I could go back and check: Yup, I wrote "tend to". -Raymond]
  8. JDP says:

    Why are you even checking blog comments on your vacation? Go enjoy a recital.

  9. Matt says:

    Can we be clear that "debuggers" doesn't just include traditional "disassembling" debuggers like WinDbg and OllyDbg. It also includes tools like SysInternal's VmMap, invasive heap viewers and so on.

    These functions are also only as "evil" as detouring functions – another technique often used by malware but also used by Microsoft to perform app-compat of doddery old programs.

    And also, not only are these functions useful for malware – they're also useful for beating malware. If you want to scan another process to see what modules it has loaded in its process (to see if it loaded malware.dll), you're probably going to have to use ReadProcessMemory or install a kernel mode driver to do so. (EnumProcessModules is a nice wrapper for ReadProcessMemory in this specific example).

    These functions are integrity-level protected and require VM_READ/VM_WRITE permission to execute. If you're allowed to call CreateRemoteThread or VirtualAllocEx or Read/WriteProcessMemory on a foreign process, that foreign process is part of your current "owned" set of programs. Malware only uses these functions once it's already owned your system.

  10. AC says:

    The cases you state in the 2nd paragraph seem straight forward enough:

    Using Read­Process­Memory doesn't affect the debugee, the patched int 3 is undone by the debugger and the changed memory by Write­Process­Memory was a result of the user wanting to do exactly that.

    But the other scenario seems more complex. Creating a remote thread to call DebugBreak? Doesn't that change the underlying process in non-obvious manners, such that the application might behave differently under a debugger?! I would have guessed the debugger would just suspend all of the process's threads, like process explorer does.

  11. Matt says:

    Oh and another class of program that use it: Crash dump programs like watson.exe use ReadProcessMemory to take a mini dump.

  12. Gabe says:

    Matt has hit upon the reason that even your grandmother's PC has reason to be running these potentially nefarious APIs. Since even Windows Error Reporting needs to use them, you can't just restrict their use by people who aren't developers, for example.

  13. Kevin says:

    @Gabe: Watson.exe is a rather different case from MySuperAwesomeDebugger.exe…

  14. Goran says:

    @Chris B: I'd be surprised that these functions cause any exploits. The thing is, whoever is doing it, has to have quite a bit of privileges first. That is the root problem, the rest is mechanics.

  15. jader3rd says:

    While I certainly wouldn't want a UAC prompt every time I spun up a debugger I could see there being something beneficial with having to register debuggers. At install time, prompt that this debugging executable is being added to the special list of programs that are allowed to use nefarious api's. Sure, it'll be annoying for debugger devs, but it seems like an overall positive action that would help the Windows ecosystem overall.

  16. dave says:

    The concept that "only program X can use API Y" does not currently exist in Windows, and adding a new security mechanism is not something to undertake lightly.

    How is "program X" to be securely identified? What happens when program X is updated? Does this preclude using these APIs from DLLs?

    I'm pretty sure that Raymond has written prior articles on the folly of security-by-restricting-my-callers…

  17. Remus Rusanu says:

    LSA also uses read/write into process memory as a means to bypass large block transfers over LPC

  18. I used a few of those functions in an automation scenario, where UIAutomation was not enough and I had to rely on SendMessage and other WinSDK functions that – as I found out – only work on memory from within the process for non-marshalled data. (Which makes a lot of sense. Afterwards.)

    Still, I thought about some fun applications, like enabling buttons that are disabled, changing text and the like.. so going back to the original post, yes, you can do some things with it that probably no one thought of.

  19. Myria says:

    I've used such functions in cases where you have two processes that communicate and need to do it quickly.  It's not just debuggers that they're useful for.

    I would have qualified CreateRemoteThread: when Win7 added extended parameters for creating threads, only one API was added, CreateRemoteThreadEx.  If you want to use these settings, you have to use CreateRemoteThreadEx, even when you are creating the thread in your current process.

    It's kind of sad that Apple went the path of requiring administrator privileges to call the equivalent of OpenProcess (task_for_pid) even on processes of the same privilege level.

  20. SpecLad says:

    I remember when Winamp had an API where you sent it a window message and got back an address for an object in Winamp's address space, so you had to use ReadProcessMemory to get it. IIRC, the documentation outright told you to do that.

  21. Why should a user need admin privileges to debug their own process?  Some comments from Raymond about airtight hatchways are in order, although I can't recall how he puts it.  Debugging might make the steps for doing something "malicious" slightly easier, but an attack is probably still possible somehow.  Start by considering, for example, that you can SendMessage to another process's message pump – and you can probably make the process crash or do other bad things by doing this.  Maybe even (*gasp*) arbitrary code execution.  I think this is by design, because the processes on a user's desktop are not isolated from each other from a security perspective.  If this is a problem, start reading up on UIPI.  I don't know much about UIPI, but I would imagine there are restrictions in place to prevent lower processes from debugging higher ones.

    Consider that you need to elevate to admin in order to debug services, another user's stuff, or your own elevated programs.

  22. I once used these to fix a compatability issue. Since I could always get in early enough, I used something that I wrote myself to patch the IAT of an application. This was to replace a broken function with a fixed one in an application that would never get updated.

    Other than that, I've used it a couple of times for nefarious purposes and once to do something but later found a better way of doing it. The nefarious things were just me playing around though, mainly along the lines of "let's see if I can do this". Nothing big ever came out of it though.

  23. cody says:

    > The concept that "only program X can use API Y" does not currently exist in Windows

    It used to – for .NET applications – with CAS (Code Access Security).  CAS has been replaced/simplified by a sandboxing model: msdn.microsoft.com/…/ee677170.aspx

  24. Random User 9237462 says:

    [Cody: It used to – for .NET applications – with CAS (Code Access Security).]

    And, if my experience is at all representative, it went away precisely because most developers effectively ignored it. I can't count the number of times I've seen instruction for adding FullTrust using CasPol in a FAQ or KB article.

  25. Gabest says:

    As already mentioned, you can only send window messages to another process with pointer parameters if you allocate/read/write their address space. I'm surprised that this most obvious usage is not the first one to come into people's mind when hearing about these functions.

  26. dashesy says:

    I am an avid fan of "Win7 Taskbar Tweaker" that fixes some of the design problems with Win7 taskbar, using those dll injections I suppose. Only because of this application I can use my PC nowadays.

Comments are closed.

Skip to main content