An interesting and non-obvious usecase: debugging python code.
Standard debuggers use ptrace to implement breakpoints by replacing instructions in debugged process with the assembly code INT3 (or equivalents). This makes the cpu trap when it reaches that instruction which transfers control to the kernel who pauses the process and notifies the debugger.
This approach doesn't work for Python because there are no native assembly instructions for the Python code - only for the C interpreter.
Most Python debuggers attach to already running processes by injecting a few lines of native code (ptrace on Linux, CreateRemoteThread on Windows) which then bootstraps a new Python thread that actually implements the debugger. (As the linked article mentions, on Linux you can inject code using ptrace today but it isn't the most convenient.)
This is also the trick that tools like pyrasite take to inject python code into running processes.
On that note, if anyone wants to easily debug/profile code running on kubernetes clusters with no prior setup, I'm looking for beta testers for an open source framework my cofounder and I are developing. It enables general application maintenance on kubernetes and not just debugging/profiling, but that's the part we need testers for right now
I implemented a debugger for an interpreted language (not Python, but similar design problem). I added a C "API" to the interpreter that was designed to be easily callable via GDB. IIRC it consisted of just three functions: "break on script line", "catch break here", and "why did I break?"
My "debugger" was a shim or wrapper around GDB. For debugging C/C++ code, it just piped standard in/out with GDB. However if it recognized a "set breakpoint" that was actually for a line of script code, it would intercept it. Instead of telling GDB to set a breakpoint there, it would do two things:
It would use GDB to manually call a function in the target program instructing the interpreter to watch for that script line ("set script breakpoint"). Then it would set a normal (native) breakpoint, but in the special function the interpreter would call from its main loop ("catch break here").
Conversely while relaying output from GDB back to the IDE, if it saw it hit a breakpoint in the "catch break here" function, it wouldn't report that. Instead the shim would use GDB to call the "why did I break" function and report the result of that back to the IDE. It was like magic getting to see the IDE bring up the correct script file and line as if the debugger hit it!
Other extensions like single stepping are obvious from these primitives.
One of the many dll injection methods possible in Windows, if I recall correctly.
Although I do usually just end up hijacking a dll already used by the program when I want to sneak my own code within a process that I don't have the source for, for the sake of future usability. (When patching the executable on-disk isn't desirable, and you don't want to go insane running an injector each time you start the process.)
> end up hijacking a dll already used by the program
That’s hard to do for an OS component, due to the anti-viral measures in the OS. Modern windows freaks out when you replace DLLs in c:/Windows/System32 directory.
Last time I used CreateRemoteThread was when a client wanted Windows 7 equivalent of Desktop Duplication API (introduced in Windows 8). I injected my DLL into the desktop compositor (dwm.exe process), hooked IDXGISwapChain.Present and IDXGISwapChain.ResizeBuffers methods, and wrote some C++ to copy desktop image into another ID3D10Texture2D in VRAM, and share the copy with the video capturing process.
Usually, you don't need to replace a system dll at all. You can just drop an alter ego in exe's own directory or even in a launch directory. Default search order in Windows is such that it'll pick up from the latter two first and check PATH second.
Once the process is up and running it has the control over this (with LoadLibraryEx and SetDefaultDllDirectories) and it's also possible to tighten search logic at the OS level (with a registry patch), but if the machine is under attacker's control, the only option is to validate loaded module list from within the app.
dwm.exe is in the same directory, c:/Windows/System32. The process is launched by Windows automatically, immediately after login. The desktop capture app I was working on is launched way later than that, by user.
What is trivial to protect against and how? I'm not aware of a general way to prevent an attacker within your user from accessing your process's memory, on any OS, except for a few newer capabilities on Windows, which are also bypassable.
Some software (mostly games) attempts to hook things like CreateRemoteThread or abort when they get the dll load/thread start events, but you can always patch those detection hooks to not run before you start your thread
Ends up being a cat-and-mouse game, but the power dynamics are even more unbalanced towards the red team: not only do they have control of the hardware, they also control your executable.
It's also why "anti-cheat drivers" have never gone away, they allow a greater level of control over what's done to your protected processes.
I'm not sure I am okay with that - there's only so much I'm willing to put up with to play some game - but I do understand why developers/producers would want such draconian solutions. In some game genres, cheating is rampant.
As per GP comment's context - it's trivial to detect system DLLs replacement, which is a common way to inject code without the use of trainers, loaders or exe patching.
But the nefarious potential its so obvious that no one with that intention would do DLL injection that way when there are other thousand of ways to get in
In our operating system (threos [1] ) this is the way the loader works (page fault exception handling code is from the loader task, mapped and running in the owner context)
Also if you have permission, you can call CreateThread [2] system call and start a thread in other task. (Normally you don't have permission.)
Solaris has had a notion called an "agent thread" for a long time. Basically a debugger can attach to a process and start an "agent thread" in the victim process to run text that is sent to the agent thread to run. This has been used for all sorts of magical features like redirecting a running process' standard I/O handles.
This is sufficiently hard to use that it was roundly hated. What you really want is a whole, parallel linker-loader environment in the agent thread so you could say "load this shared object and call this function in it with these arguments".
[1]: https://docs.microsoft.com/en-us/windows/win32/api/processth...