DLL injection

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."

Are you talking about Richter's article?

Andy
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.

The articles I read were
http://en.wikipedia.org/wiki/DLL_injection
http://www.blizzhackers.cc/viewtopic.php?p=2483118
http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
http://www.thehackerslibrary.com/?tag=dll-injection
http://www.codeproject.com/KB/threads/winspy.aspx
Last edited on
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)

Three Ways to Inject Your Code into Another Process
http://www.codeproject.com/KB/threads/winspy.aspx

And maybe this one?

InjLib - A Library that implements remote code injection for all Windows versions
http://www.codeproject.com/KB/library/InjLib.aspx?msg=1245338

Loads of them!

Andy

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...)
Last edited on
Thanks; I'm going to look at how InjLib does it.
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 >:) ?
Last edited on
@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?
Last edited on
@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...
Last edited on
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).
Last edited on
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.
Last edited on
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!

Andy

P.S. You are using '7 ??
andywestken wrote:
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!"

Yes, I'm using Windows 7.
Same as me -- but I use a console app, being a luddite.

I don't have access to a Windows 7 system, so I can't give it a go. But I wouldn't be surprised if the security has been tightened up even more.

Do you have access to a 'Vista or 'XP machine?
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)).
Last edited on
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.
Topic archived. No new replies allowed.