Nim on the Attack: Process Injection Using Nim and the Windows API
huskyhacks.devInteresting to see Nim used here. I participate a bit in its community because it's a fun language, but I had not yet heard that it was used in opsec circles.
I wonder why people are writing shell codes for that?
When I need to inject my code into another process, I write a DLL and only inject LoadLibrary function call. Much more reliable this way: the OS applies relocation table, I have C and C++ runtimes in the injected code, the result is compatible with ASLR, if my DLL has other DLL dependencies the OS will load them first, etc.
One reason (not the only one) is if you write a DLL then you need an EXE to be able to spawn it on-demand. That results in 2 files to deal with which is rather inconvenient. Actually 3 files if you want to be both x64- and x86-compatible.
Almost all production-quality software I’m making needs multiple executable files anyway, and uses an installer. For Windows, usually this one https://wixtoolset.org/
Sure, and in your case you might not need something like this this.
Sometimes I do. Microsoft has not made CreateRemoteThread API to support malware, it has many legitimate uses.
For instance, one time a client wanted to have a functional equivalent of desktop duplication API working on Windows 7. I wrote a DLL that’s injected into dwm.exe, hooks IDXGISwapChain.Present and ResizeBuffers methods, copies video frames into another D3D texture, and uses DXGI surface sharing to feed frames in VRAM to the capturing/encoding process.
How do you account for dll checksum? Every C++ app I’ve worked on that relies on a dll would checksum the dll against a list of acceptable versions. If the checksum failed the dll wasn’t loaded and the app would close.
> Every C++ app I’ve worked on that relies on a dll would checksum the dll against a list of acceptable versions
Never worked on any software which does that. Checking DLLs the way you described is a guaranteed way to break software after a windows update, or a driver update.
There’re many reasons why foreign DLLs can be loaded into your process. CreateRemoteThread is on the exotic side of things, other reasons are way more common.
Direct3D runtime loads user-mode DLLs implemented by nVidia/Intel/AMD/vmware/etc. MediaFoundation runtime loads quite a few DLLs, some of them third-party, implementing various transforms like codecs and containers. Many security-related software like firewalls load their DLLs into every process to check things. Some system software implements custom network protocols in DLLs, e.g. both HyperV and VMWare do that for their virtual networks. Apps like spy++ are using system-wide hooks, again that’s a foreign DLL loaded into every GUI program on that desktop. Many productivity apps like MS Office or Photoshop support scripting, users can often consume arbitrary DLLs in these scripts using LoadLibrary, COM and/or .NET.
I get what you mean. So those “public” are known vulnerabilities, the signed/checksumed dlls where typically vender dlls or our custom dlls that touched business logic and had to be resistant to injection.
> So those “public” are known vulnerabilities
Yep, and there’s way too many of them. I forgot the most frequently used ones — shell extensions. Every time you embed a shell by calling GetOpenFileName/GetSaveFileName/ShBrowseForFolder/etc. you’re loading not just shell32.dll but also a bunch of third-party DLLs who adding their custom context menu entries, or rendering preview thumbnails for their file types, or similar. Technically, every such DLL can do whatever it pleases with your process, with both code and data.
> the signed/checksumed dlls where typically vender dlls or our custom dlls that touched business logic and had to be resistant to injection.
That’s better than nothing, but too many ways to workaround, still. I’m afraid the level of security you want is impossible for consumer-targeted software. Only possible sometimes in enterprise environments, where you can use legal/political methods to solve most of these issues: deny end users from being administrators of the computers they’re using, use group policies to restrict which software they may install, use other group policies to configure Windows security to be way more annoying but slightly more secure, stuff like that.
What exactly do you mean by compatible with ASLR? And would you mind going into a little detail on how injecting a DLL works, compared to what's being done here?
Sorry to bother, just very interested in this stuff!
> What exactly do you mean by compatible with ASLR?
The code being injected doesn't need to hardcode any absolute addresses of the dependent functions. It works fine when the OS kernel randomizes virtual addresses of all DLLs.
> how injecting a DLL works, compared to what's being done here?
Very similar, the main difference is what's injected.
The OP is injecting code and running it. The injected code needs to be position-independent, in practice this means it needs to be written in assembly, which is very hard to do for non-trivial things.
I normally use VirtualAlloc to allocate a UTF-16 buffer for the path of a DLL I made, then use CreateRemoteThread to run LoadLibrary function.
This way I can use normal C++ with all the features in the code being injected.
That's a great idea!
I already know where I can use this, which would make my code a lot easier (and more robust) to write.
Thanks heaps.
See this answer for slightly more info https://stackoverflow.com/a/54855964/126995
Just don’t use `LoadLibraryA` like the OP, that API is only there for compatibility with software written for Windows 95/98/Me. Use UTF-16 encoding for the path instead, and `LoadLibraryW` function for the remote thread address.
This is all fantastic info and I will likely fold this into the next post in the series about maldev with Nim. Thank you for linking to the StackOverflow page!
Yes, that makes perfect sense.
With ANSI/OEM encoding you will have problems eventually.
Also thanks for the link, some good tips in there too.
I followed the link to the Nim site and downloaded the official 64 bit version.
Windows Defender (Win10) reports a severe threat in nim-1.4.8\bin\vccexe.exe - Trojan:Win32/Wacatac.B!ml - which allows remote code execution.
It may be a false positive - but the whole post is about exploits so I'll probably not risk it.
Hey, OP here! Sorry about Defender flagging on this. I'm putting it through some tests and will tweet the Nim devs to see why this is an issue. I've used Nim for a while now and never had any problems. And from some light googling, it looks like this is a known false positive issue. In any case, apologies for the scare!
No worries. Now you've mentioned it I can see in their forums it is an ongoing issue with Defender specifically.
I'm very much averse to trusting the supplier of an installer enough to disable security checks, especially for a development toolkit where on the remote chance it is real it propagates into what I build on that toolchain, so I'll probably revisit at a later date.
As a fan of Modula-2 and Pascal I've always found the look of the Nim syntax appealing, so I'm quite looking forward to another way of coding cross-platform desktop apps (I avoid Electron and Mono, which usually leaves Lazarus) and your post reads quite interesting in that regard.
Yes, unfortunately it is likely a false positive. The devs are aware but it appears to be difficult to fix.