Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Implementing Global Injection and Hooking in Windows (m417z.com)
72 points by ingve on April 20, 2022 | hide | past | favorite | 26 comments


Code injection like this is why we have historically been unable to enable stronger process mitigations for Chrome that might improve security and stability. It's a real pity :(

https://bugs.chromium.org/p/chromium/issues/detail?id=851565...

The flag we (still) can't enable by default is

--enable-features=BrowserDynamicCodeDisabled


Didn't Microsoft do this in the old pre-Chromium Edge? It probably would've caused more of an outcry from users if anyone actually used the old Edge as their primary browser. Personally, I feel like this is the "wrong way" to enhance browser security. Should the browser, as important as it is, behave fundamentally differently than all other processes within an OS? What about other VIPs (Very Important Programs)? Who's to decide which apps are important enough? The right way, to me, would be for the Chrome/Chromium team (along with other browser vendors) to lobby and/or work with OS vendors such as MS, Apple, Canonical, etc. to come up with sensible OS mechanisms to limit dynamic code, with appropriate user control and override options. Sure, that's a bigger undertaking and "some users will be confused" as always. But it's not worth it to me to keep shrinking what part of my personal computer I can actually control just to gain a little bit more security and stability. I want to be the one to make the choices and strike a balance that's personally right for me. So for that reason, I hope this is one feature flag you will never enable by default.


Have to agree with you. You can find some good posts (blog posts? I forget) where an MS engineer explains why the desktop on Windows is as messy as it is. The gist of it was, they did actually try basically everything else and had various types of security, but anything but having the desktop as a single security boundary (at least as far as interaction was concerned) made everything too complicated and brittle.

For this reason I highly doubt wayland will really work as intended. We're going to end up with a middle shim layer that basically acts as X11 but doesn't look like it.


Love to hear more about this?


macOS has been moving this direction for a while. To inject code into an appropriately prepared process on that platform, you will need to generally want to run as root, have to attach to the process as a debugger, and then patch it. Plus there are APIs to suspend processes at creation and such.


I'm curious if you could attempt to "fend off" such hooks into your address space?


Kind of, but it is very brittle, and you are doing something the OS does not intend you to do.


If you need to hook methods in a remote process (and also inject payload), you may also consider the Detours library [1]. It has a straightforward API and its repository contains many interesting samples. One thing I was missing in the library was a function to inject code into a running process. So I wrote takedetour [2] which I use as a template for my other projects. Maybe you will find it useful as well.

[1] https://github.com/microsoft/Detours

[2] https://github.com/lowleveldesign/takedetour


Even not being Microsoft, our hooking engines are also extremely robust and has additional features (higher level interface to hook in any language and hooking COMs and .NET): https://github.com/nektra/Deviare2 https://github.com/nektra/Deviare-InProc, and https://github.com/nektra/RemoteBridge

They are being used in well known security companies and intelligence organizations.


Fun fact: in the #winprog irc channel on efnet in the 90s/early 00s, "how do I hook into another program's messages?" was the most common question asked by people new to the channel.

Baby's first keyloggers.


Wow, this looks amazing. I just might try to make a mod that disables apps’ ability to steal keyboard focus (unless someone beats me to it).


Oh all the lost arts from the past...

My preferred method was manipulating IAT table (Import Address Table) where the code injected into process is hooking CreateProcess and LoadLibrary (and similar) to further propagate injection into other processes/library spawned by current process(es) and using debug privileges to also inject into system processes (like login process on windows 2000, to survive logoff)

Anyway Microsoft Detours is the way to go, they actually modify the code of hooked function using trampolines, I don't think anything can be more efficient than that.


Lost? Past? The Windows world still runs on this stuff, and there are still plenty of people who know how it works and make money from knowing.

That said, MS have unintentionally (I think) done a pretty good job of scrubbing the internet clean of useful information about it by breaking all their links multiple times. I keep a personal copy of some things, such as Matt Pietrek's classic two-parter "An In-Depth Look into the Win32 Portable Executable File Format", lest they disappear completely while the technologies they describe continue to run the world.

Edit: MS only appear to have part 2 of that article in their archive, and it contains broken links (of course). Both parts can still be read at [1] and [2] and remain as relevant as they were the day they were written

[1] https://bytepointer.com/resources/pietrek_in_depth_look_into...

[2] https://bytepointer.com/resources/pietrek_in_depth_look_into...


Does anyone know about something similar on macOS? Environment variables like DYLD_INSERT_LIBRARIES or functions like mach_inject, dl_open and others are automatically disabled for processes protected by hardened runtime. I'm wondering if it's possible to inject to process only by exploiting the OS.


You will need to disable SIP (and library validation) to do this, because your code signature will not match the target process's, which is kind of what this is intended to prevent. This is also why you cannot attach a debugger to arbitrary processes when those protections are engaged. But once you turn that off, there's a lot you can do, here's one of my projects that might give you an idea of one way to do this: https://gist.github.com/a70d44951cb72f82efee3317d80ac07f


I think that disabling SIP can break some programs and it's hard to do for a normal user right? I'm curious how anti-malware software is doing this, because it's doing a lot of fancy stuff, maybe I should look into it by reverse engineering one of them. Thanks for the link I'll definitely check it out.


The hardest thing to wrap my head around in Windows is how perfectly normal and common to load new code into existing processes. There are well-known APIs to do it.


Much of this is borne out of not having source for code critical to your business. So, you inject patches.


This is within process access limits.

Non elevated process can't inject into elevated process. X user process can't inject into Y user process.

If user has access to process, they have very well access to modify by decompiling or reverse engineering it. Dynamic injection makes it much more seamless and less painful.


You'd be correct!

https://docs.microsoft.com/en-us/windows/win32/winstation/wi...

https://docs.microsoft.com/en-us/windows/win32/winstation/de...

https://docs.microsoft.com/en-us/windows/win32/procthread/pr...

https://docs.microsoft.com/en-us/windows/win32/procthread/th...

https://docs.microsoft.com/en-us/windows/win32/fileio/file-s...

Here https://news.ycombinator.com/item?id=31092978 suggests its not possible to prevent code injection aka system or app hooks. Preventing system and app hooks is very possible and the MS api's gve you all you need to block them, people just need to come up with innovative ways to deploy them!


I don't think the comment by wfh is saying that it's not possible to prevent these hooks. In fact, wfh is saying the opposite, i.e. that they already have the mitigation in place, but cannot enable it because there are legitimate use cases for hooking/injection, and users who use programs that depend on these techniques would be (rightly) upset if Chrome unilaterally decided to block all such use cases. The comment is lamenting the fact that the author of the blog post is creating yet more such use cases and will make it even harder for Chrome to ever enable the feature to prevent code injection.


You can ptrace() on Linux as well, it just isn't as easy: https://blog.xpnsec.com/linux-process-injection-aka-injectin...


Hi, author here. AMA!


I don't have a question, but I wanted to let you know that you can enumerate processes and threads via NtQuerySystemInformation instead of CreateToolhelp32Snapshot, and it's much faster. The latter is slow only due to weird file section mapping behavior and not due to the actual query.


Thanks for the tip, I tried that. It might be a bit faster, but in my tests, it wasn't significant, and it still enumerates all system threads which means that it becomes slower the more threads your system has.

A truly fast and documented solution is using PssCaptureSnapshot, it can enumerate only threads of the target process. It uses NtGetNextThread under the hood. The downside: it's only available from Windows 8.1.

Using NtGetNextThread is not only fast and available from Windows Vista, it also allows avoiding race conditions - what happens if a new thread is created after the snapshot is created? A snapshot returns thread ids, what happens if one of the threads is destroyed? What happens if the thread id is reused (unlikely but possible)? I believe all the benefits I'm getting by using NtGetNextThread are worth using an undocumented function.

See also the research that I linked in the blog post: https://github.com/diversenok/Suspending-Techniques#snapshot...


mactype uses easyhook and has problems hooking uwp and some system stuff that might clear up by switching to this minhook




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: