So, I was bored today and decided to try hacking Minesweeper. I found some articles on DLL injection, wrote a DLL and a program to inject it. But it didn't work. Some searching has revealed that "In Windows Vista [and presumably Windows 7], Microsoft introduced the notion of a protected process. Such processes are (almost) immune from DLL Injection" (Wikipedia). Does anyone know any methods that still work, as per the "almost"?
Well, I don't think that Minesweeper will have been updated to be a protected process quite yet.
MSDN says that the only 4 protected process (so far) are media foundation, audio engine, Windows error reporting, and system. And that the mechanism is "not currently available for non-Microsoft binaries."
Oh cool, I assumed from the Wikipedia page that it was an OS feature that was applied to all processes (like software DEP), rather than something the individual programs have be set up to do.
I used Richter's book Advanced Windows to learn about DLL injection.
Turns out you can get the code from a rather data back of issue of MSJ. I looks like the same code, but it would probably needs some adjustments to work with modern Windows (see PS...).
But this one looks interesting (I see you already have it)
P.S. The old code is here, but I would be wary of it!
http://www.microsoft.com/msj/backissues86.aspx
May 1994 — Vol 9 No 5
CODE MSJMAY94 (115,179 Bytes)
Load Your 32-bit DLL into Another Process's Address Space Using INJLIB
Jeffrey Richter
(Source inside the seelf exracting zip file...)
After a quick glance at the articles you linked to one thing that they do not necessarily make immediatly clear is that the entry point for a Windows DLL is DllMain. So unless something in the target program calls some function from you DLL, or you put some runable code in DllMain(), then all you'll be doing is loading code into the target process. Of course you can "tell" the target process to call the function, this is what "CreateRemoteThread()" is for.
That "winspy" article that both you and andywestken linked to is a great resource. Out of the methods that author mentions though I find Thread Injection to be a bit more interesting. Maybe because I've NEVER seen an AV suite that blocks injected threads; after all how would they scan a processes memory if they did >:) ?
@Computergeek01 - as you say, CreateRemoteThread() is the key to Richters (and others) technique. He injects a small code fragment at a known address and then uses CreateRemoteThread() to run it. The fragment call LoadLibrary on your DLL, which triggers its DllMain. It exploits the fact that as kernel32.dll is mapped into a process's memory so early, it always loads at its preferred address.
Regarding virus checkers: could they use ReadProcessMemory to inspect the memory from outside?
@andywestken: They could use ReadProcessMemory() to check the contents of the running processes, this seems to be a horribly inefficent way to do it but AV suite's don't seem to mind that approach anyway. I've noticed that they DO seem to "block" the injection of DLL's into certain processes though, I haven't played around with it too much because having to continuously reboot is a PITA, but I'm pretty sure the AV is what caused it because it threw up a warning and logged an event prior to the restart.
EDIT: This was at least a few years ago now that I think about it. I've come a long way since then maybe it's time to revisit this aspect of programming...
I had a quick look on my hard drive and found my copy of Richter's InjLib sample (the MSJ code I mentioned above) lurking in the "maybe useful one day" folder.
It just ran on Windows XP; on Windows Vista it only worked -- as expected -- when I used the admin account (I opened a console with Run as admin...).
(I think my possible use was injecting white box unit tests into a process, to avoid compiling them in. But I've never gotten around to trying this approach)
Andy
P.S. Out of curiosity I had a quick look at adding run as admin code to the sample. I didn't follow through, but the almost 400 lines sample will need about an extra 650 to sort that out (see sample code pointed at by MSDN entry for CreateProcessAsUser).
My DLL had a DllMain() function, as well as some other functions to open a console so that the user could interact with the DLL (not sure if that code works though). Nothing happened when the DLL was injected, even though there was a call to MessageBox() in the DllMain() which should have been done as soon as DllMain() was called. I'm pretty sure the problem was with the injector. I tried turning MSE (my av program) off but it didn't change anything (I didn't expect it to, either, since there were no warnings, messages or log entries from MSE about my injection attempts).
I also tried run as administrator but it didn't change anything.
Well, the only things I could add here are the obvious!
I did add quite a bit of debug logging code to Richter's sample when I first looked at it, so I could follow what was going on. But I don't think you get much (any?) feedback from the remote process if things go wrong.
As with yours, my AV seems totally oblious to the goings on!
I did add quite a bit of debug logging code to Richter's sample when I first looked at it, so I could follow what was going on. But I don't think you get much (any?) feedback from the remote process if things go wrong.
I added a few MessageBox's to say things like
"Minesweeper.exe found: pid <x>" or "Minesweeper.exe not found, is Minesweeper running?"
"Injected!" or "Injection failed!"
and whenever an API function returned a failure code it would say, "Error: FooBar(): <x>"
Some of those messages could be turned off (by compiling with DEBUG defined to 0), so all it would say is "Start Minesweeper and then press OK", "Minesweeper.exe found [...]" or "[...] not found [...]" and then either "Injected!" or "Injection failed!"
If you are wondering if your DLL even loaded into the target process I just use "Tasklist /M DLLNAME.dll". This is run from the command line and will list your target process if that DLL is loaded into memory. I don't see why you would go through the trouble of trying to get a pop-up box out of the target process.
@andywestken,
No, but I could gain access "legally" to a free version of Vista or XP.
Computergeek01 wrote:
Tasklist /M DLLNAME.dll
I didn't know about this. I've been using Process Explorer to look at the target process' threads (since my injector uses CreateRemoteThread and process explorer tells you what module is running in the thread (fun fact: minesweeper.exe uses two threads, plus two for dsound.dll (DirectSound) and a few other Windows DLLs; it runs about 13 threads in total).
Computergeek01 wrote:
I don't see why you would go through the trouble of trying to get a pop-up box out of the target process.
Well, I tend to write programs as though someone else is going to use them (plus I was planning to stick this on Sourceforge when I get it done), and I want the target process to say something about how it had loaded the DLL (btw the MessageBoxes above were for debugging reasons and they were made by the injector process, not the target process) and then open a console for the user to interact with (to load more DLLs, actually; I wanted to get a plugin system going :P)).
I'm not sure I understand what you mean by trouble? I always assumed that Richter's sample was using this method because it was the easiest way to prove the DLL had been loaded into the target process.