Yet another dll injector.. menu

User Tag List

Results 1 to 11 of 11
  1. #1
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Yet another dll injector..

    Some of you are probably thinking something like "Not another one.. Why?" by now.
    Simply put, I wanted to code a dll injector just to better understand what happens "under the hood", and I figured maybe someone will find this useful so I decided to release it here. Plus I've learned a lot from this forum section so this is my way of saying thanks.

    What it can do
    * Injects native and managed dlls (without using a bootstrapper dll) in to 32-bit processes
    * Crappy GUI
    * All the injection code is in a class library if you want to replace the crappy GUI
    * Source included

    What it can't do (yet)
    * Inject in to 64-bit processes.

    Usage
    Command line arguments:
    -inject <path to dll>
    -function <function to call> (optional for native dlls, although you should be aware of the limits of doing stuff in DllMain)
    -args <string argument to pass to 'function'> (optional)
    -silent (don't show the message box indicating success or failure, only write status to the console)

    GUI version (if injector is started without arguments):
    Well, shouldn't be to hard to figure out how the gui works I hope.


    Credits
    * Cypher/RaptorFactor - The EnsureCleanup library
    EnsureCleanup – Now with GCC support and move semantics | The Raptor Factor
    (The EnsureRelease and EnsureVirtualFree classes are added by me so don't blame Cypher if they are buggy or low quality code)
    * Petr Kobalicek - AsmJit
    asmjit - Project Hosting on Google Code
    * sPeC! - For his example on .Net v4 injection
    http://www.mmowned.com/forums/world-...ml#post1940144

    Source code licence
    The licences EnsureCleanup and AsmJit was released with obviously still apply. As far as my code goes, do whatever you want with it.

    External dependencies needed
    * .Net v4.0
    * Boost, specifically boost/noncopyable.hpp which EnsureCleanup needs

    Binaries: http://dl.dropbox.com/u/12654979/Injector_binaries.rar
    Source: http://dl.dropbox.com/u/12654979/Injector_source.rar C#/WPF GUI + C++/CLI class library

    Only tested under win7-x64 but I think it should run under any NT-based os that has .Net 4
    Comments, bug reports and complaints welcomed.
    / Mike

    Yet another dll injector..
  2. #2
    DarkLinux's Avatar Former Staff
    CoreCoins Purchaser Authenticator enabled
    Reputation
    1601
    Join Date
    May 2010
    Posts
    1,832
    Thanks G/R
    189/533
    Trade Feedback
    16 (100%)
    Mentioned
    6 Post(s)
    Tagged
    0 Thread(s)
    Looks kool but the source code would look better. +Rep

  3. #3
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by DarkLinux View Post
    Looks kool but the source code would look better. +Rep
    What do you mean? There is a link to the source.
    Or do you mean the code looks bad?

  4. #4
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey, just fyi, there's actually already an 'EnsureVirtualFree' class in the code, I just called it something different. It's under the name 'EnsureReleaseRegion', which in retrospect was a pretty stupid name, I should've just called it EnsureVirtualFree.

    Also, it's fairly trivial to drop the Boost.NonCopyable dependency if you want. Just comment out all the private inheritance of 'boost::noncopyable' and add a private copy-constructor and copy-assignment operator to all the classes.

    Anyway, that out of the way, apart from a few minor bugs and a potential leak or two you've done a great job. Love the use of AsmJit to do managed DLL injection without a bootstrap DLL. Great work.

  5. #5
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Cypher View Post
    Hey, just fyi, there's actually already an 'EnsureVirtualFree' class in the code, I just called it something different. It's under the name 'EnsureReleaseRegion', which in retrospect was a pretty stupid name, I should've just called it EnsureVirtualFree.
    Haha I can't believe I missed that one I even tried looking in case you had named it something else but I obviously didn't look closely enough.

    Originally Posted by Cypher View Post
    Also, it's fairly trivial to drop the Boost.NonCopyable dependency if you want. Just comment out all the private inheritance of 'boost::noncopyable' and add a private copy-constructor and copy-assignment operator to all the classes.
    Yes, it wasn't really an issue of how to do it but I couldn't find any licence for the header file on your blog so I was unsure if I was allowed to distribute a modified version of it or not.

    Originally Posted by Cypher View Post
    Anyway, that out of the way, apart from a few minor bugs and a potential leak or two you've done a great job. Love the use of AsmJit to do managed DLL injection without a bootstrap DLL. Great work.
    Mind sharing where the resource leaks are? I tried making sure I wrapped all allocations and handles etc in auto cleanup wrappers but I must have missed something then?
    And thank you for the feedback.

    On a side note, I'm currently trying to update this to be able to inject 64bit dlls in to 32bit processes (for no real reason other than that I'm bored) but tracing through LdrLoadDll to find out why the dll refuses to load is a sloow process for me. windbg is confusing for a beginner and I don't know of any other debugger that can handle mixed 32 & 64bit code.
    Last edited by _Mike; 10-04-2010 at 02:18 PM. Reason: spelling

  6. #6
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, WinDbg is a bitch to learn at first, but once you're comfortable with it it's amazing. Far more powerful than any other Windows debugger. Check out the book 'Advanced Windows Debugging'. It's an awesome tutorial and reference for WinDbg.

    As for the leaks, I can only find one on my second review. Either I'm overlooking something or the first time I didn't look closely enough. Either way I'm really busy today, so I'll take a better look tomorrow.

    The one I did find is not technically a 'leak' in the sense you normally use the word, but personally I'd classify it as such as you're 'leaking' a process if something fails. In 'LaunchAndInject' you call 'ResumeThread' after the call to 'InjectAndRun'. What if 'InjectAndRun' throws (don't forget that the STL can throw, even if you don't)? You will have created a zombie process. Do what I do, put everything after the 'CreateProcess' call in a try/catch block. That way if something goes wrong you can terminate the process.

    Not a leak, but one particularly dangerous snippet of code:
    Code:
    DWORD CreateInstanceAddress = reinterpret_cast<DWORD>(GetProcAddress(Runtime, CLRCreateInstanceName.c_str())) - (DWORD)(HMODULE)Runtime;
    Don't cast pointers to a DWORD! Even under x64 a DWORD is only 4 bytes. If you need to cast a pointer type to an integer type use DWORD_PTR, otherwise you risk truncating your address under x64.

    You're using PROCESS_ALL_ACCESS but haven't set the Windows version flags in your compiler settings. Set the flags to pre-Vista or any time that your code is compiled using a Vista+ SDK it will only work on Vista+. This is because the size of the PROCESS_ALL_ACCESS flag changed across SDK versions.

    One other thing I noticed is that you're taking strings by reference. Change that to reference-to-const where possible, as right now you're 'breaking' a lot of otherwise valid code.

    There are a bunch of other things I'd like to point out, but I don't have the time at the moment. If you want me to go over the other stuff I noticed let me know, and I'll do it tomorrow or something.

    Lastly, injection of 64-bit DLLs into 32-bit processes is something I wanted to do as well eventually. Let me know how you go, it looks like an interesting job.

  7. #7
    sPeC!'s Avatar Member
    Reputation
    23
    Join Date
    Jun 2009
    Posts
    20
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Looking good. Nice Job! I may already have use for it... hehe

    Cheers,

  8. #8
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @Cypher:
    Thanks for the bug report, I'll get around to fixing them when I find the motivation for it. This 64bit injection is far more interesting at the moment

    Originally Posted by Cypher View Post
    There are a bunch of other things I'd like to point out, but I don't have the time at the moment. If you want me to go over the other stuff I noticed let me know, and I'll do it tomorrow or something.
    Sure, I'd like that. But you really don't have to do it as soon as tomorrow, I don't want to steal your time away from your own projects.

    Originally Posted by Cypher View Post
    Lastly, injection of 64-bit DLLs into 32-bit processes is something I wanted to do as well eventually. Let me know how you go, it looks like an interesting job.
    I have the injection partially working, but when trying to load any dll which depends on kernel32 then LdrLoadDll fails with STATUS_CONFLICTING_ADDRESSES. Dlls which only makes use of ntdll works fine.
    I haven't really looked in to it yet, but I'm guessing this is because the 32bit version of kernel32 is already loaded.
    Next step is to remove kernel32.dll from the PEB module list before calling LdrLoadDll. This isn't really a good solution though as any 32bit call to GetModuleHandle("kernel32") would fail, but at least it allows me to see if that is indeed the problem.
    But that's a thing for tomorrow though, I need to get some sleep first. I'll report back on how it works out later.

  9. #9
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Have you tried 'manually' injecting the 64-bit version of Kernel32 before attempting to inject your module? (As opposed to relying on the loader to do that for you, which is obviously failing.)

  10. #10
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I would if I knew how to Guess I'll have to look in to that a bit more because what I'm doing now feels like a big failure.
    I found why kernel32 refuses to load though. In the dll loader there's a string compare between <dll to load> and "c:\windows\system32\kernel32.dll" and if they match then the loader returns the STATUS_CONFLICTING_ADDRESSES status code. Patching out that conditional jump is easy enough but now I'm getting a weird crash a bit later on in the loader.
    Code:
    (13ac.1818): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    ntdll!RtlCaptureContext+0x86:
    00000000`771ff2d5 0fae8100010000  fxsave  [rcx+100h]    ds:00000000`0022ed48=dd
    
    0:000> !vprot @rcx+100h
    BaseAddress:       000000000022e000
    AllocationBase:    0000000000130000
    AllocationProtect: 00000004  PAGE_READWRITE
    RegionSize:        0000000000002000
    State:             00001000  MEM_COMMIT
    Protect:           00000004  PAGE_READWRITE
    Type:              00020000  MEM_PRIVATE
    
    0:000> k
    Child-SP          RetAddr           Call Site
    00000000`0022ec08 00000000`771c6078 ntdll!RtlCaptureContext+0x86
    00000000`0022ec18 00000000`7724d849 ntdll!RtlRaiseException+0x48
    00000000`0022f258 00000000`77283eaa ntdll!ntdll!vDbgPrintExWithPrefixInternal+0x537c9
    00000000`0022f598 00000000`77227237 ntdll!LdrpLogDbgPrint+0xda
    00000000`0022f6f8 00000000`01351534 ntdll!LdrLoadDll+0x42ac7
    00000000`0022f768 00000023`013514ea testapp1!load+0x54
    
    0:000> g
    (13ac.1818): Access violation - code c0000005 (!!! second chance !!!)
    ntdll!RtlCaptureContext+0x86:
    00000000`771ff2d5 0fae8100010000  fxsave  [rcx+100h]    ds:00000000`0022ed48=dd
    My experience with assembler is very limited, and I have no idea why fxsave is failing when the memory (the stack in this case) is marked as writable.

    Edit:
    I realized that "Have you tried 'manually' injecting the 64-bit version of Kernel32 before attempting to inject your module?" can be interpreted in 2 ways..
    If you mean if I have called LdrLoadDll("kernel32") before my own dll, then yes.
    If you mean if I have tried to manually map kernel32 in to the target, then no.

    Also, the crt isn't initialized at this point so that might be why I'm crashing? But I don't think I actually need the crt if I'm making calls in to ntdll directly.

    Edit2:
    Ignore all of the above, it was just a stupid error on my part. I assumed my stack frame had to be 8 byte aligned when if fact sse instuctions require 16 byte alignment.
    All the dlls are being mapped in to the target now without any error codes, but DllMain isn't being called for any of the dlls in the dependency chain. Trying to find out why at the moment..
    Last edited by _Mike; 10-06-2010 at 06:26 AM.

  11. #11
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Status update:
    The injection itself is working fine now. Here are the patches needed for the dll loader.
    In ntdll!LdrpFindOrMapDll
    Code:
    00000000`771eab4c 488d152da20c00  lea     rdx,[ntdll!LdrpKernel32DllName (00000000`772b4d80)]
    00000000`771eab53 488d8c2498000000 lea     rcx,[rsp+98h]
    00000000`771eab5b 41b001          mov     r8b,1
    00000000`771eab5e e86da40100      call    ntdll!RtlEqualUnicodeString (00000000`77204fd0)
    00000000`771eab63 84c0            test    al,al
    00000000`771eab65 0f8561e80000    jne     ntdll!LdrpFindOrMapDll+0x824 (00000000`771f93cc)
    00000000`771eab6b 4032ed          xor     bpl,bpl
    Get rid of the jne to make sure kernel32 loads
    bpl is tested a bit later in the beginning of ntdll!LdrpRelocateImage and if it's not zero it fails, so I think it's some kind of "don't relocate this dll" flag.
    Set the byte ntdll!LdrpLdrDatabaseIsSetup to 1
    Call LdrLoadDll
    And now we get this in the debugger:
    Code:
    1c48:22e0 @ 275166171 - LdrpRunInitializeRoutines - INFO: Calling init routine 00000000005633E0 for DLL "C:\Windows\system32\KERNELBASE.dll"
    1c48:22e0 @ 275166171 - LdrpRunInitializeRoutines - INFO: Calling init routine 000000000045EFF0 for DLL "C:\Windows\system32\KERNEL32.dll"
    1c48:22e0 @ 275166234 - LdrpRunInitializeRoutines - INFO: Calling init routine 0000000055475C10 for DLL "C:\Windows\SYSTEM32\MSVCR100D.dll"
    1c48:22e0 @ 275166234 - LdrpRunInitializeRoutines - INFO: Calling init routine 0000000000031520 for DLL "C:\Users\Micke\Documents\Visual Studio 2010\Projects\Injector\x64\Debug\test64.dll"
    1c48:22e0 @ 275166234 - LdrpLoadDll - RETURN: Status: 0x00000000
    1c48:22e0 @ 275166250 - LdrLoadDll - RETURN: Status: 0x00000000


    But now the part where I'm stuck at the moment..
    My DllMain is a simple
    Code:
    BOOL WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID reserved)
    {
    	OutputDebugString(L"In 64bit DllMain!\n");
    	return TRUE;
    }
    If I run it through windbg things work fine, but when running the injector directly and trying to view the output in sysinternals' dbgview OutputDebugString causes an unhandled exception crash for exception 40010006 (DBG_PRINTEXCEPTION_C)
    I can stop the crash by installing my own exception handler with RtlAddVectoredExceptionHandler but this also stops the debug string from being caught by dbgview.
    I've searched for the default exception handler to find out how to handle that exception because OutputDebugString works from the 32bit code, but I can't find it because AddVectoredExceptionHandler never gets called by the crt. Are there any other ways to install exception handlers?

Similar Threads

  1. Yet another gold scam
    By XeroZ in forum WoW Scam Prevention
    Replies: 2
    Last Post: 09-26-2006, 10:41 PM
  2. Yet another request...
    By DarkMoogle666 in forum WoW ME Questions and Requests
    Replies: 1
    Last Post: 09-24-2006, 09:38 AM
  3. Yet another gold scam!
    By McKeough in forum WoW Scam Prevention
    Replies: 10
    Last Post: 09-06-2006, 02:58 PM
  4. Yet another hearthstone trick
    By lvlrbojang1es in forum World of Warcraft Exploits
    Replies: 4
    Last Post: 06-19-2006, 02:48 PM
  5. Yet Another Ony Guide
    By Amedis in forum World of Warcraft Guides
    Replies: 0
    Last Post: 06-04-2006, 10:14 AM
All times are GMT -5. The time now is 05:00 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search