Game Accessibility Library logo SourceForge.net Logo
Game Accessibility Suite: CAT/CATDLLInjector.h Source File

CATDLLInjector.h

Go to the documentation of this file.
00001 /// \file  CATDLLInjector.h
00002 /// \brief DLL Injection functions for Win32
00003 /// \ingroup CAT
00004 ///
00005 /// This class includes utilities useful for injecting DLLs into remote processes on Win32-based
00006 /// platforms.
00007 ///
00008 /// Copyright (c) 2007-2008 by Michael Ellison.
00009 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00010 ///
00011 // $Author: mikeellison $
00012 // $Date: 2008-01-27 12:56:42 -0600 (Sun, 27 Jan 2008) $
00013 // $Revision:   $
00014 // $NoKeywords: $
00015 
00016 #include "CATInternal.h"
00017 
00018 #ifdef CAT_CONFIG_WIN32
00019 
00020 #ifndef _CATDLLInjector_H_
00021 #define _CATDLLInjector_H_
00022 
00023 /// \class CATDLLInjector
00024 /// \brief Collection of utility functions for injecting a DLL into a process.
00025 /// \ingroup CAT
00026 ///
00027 /// This class contains utility functions to inject a DLL into a process.
00028 ///
00029 /// There are several methods available to do this, and all of them have 
00030 /// tradeoffs. The two I expect to be most used are the CreateRemoteThread() 
00031 /// method to force a LoadLibrary() call on a new thread into the target process, 
00032 /// and the CreateProcess() method of creating a process in a halted state, 
00033 /// inserting the DLL, then continuing execution.  The first is embodied in 
00034 /// CATDLLInjector::InjectIntoProcess(), the latter in 
00035 /// CATDLLInjector::StartDLLWithProcess().
00036 ///
00037 /// Much of the information on how to do DLL Injection and function hooking
00038 /// was gleaned from Jeffrey Richter's 
00039 /// "Programming Applications for Microsoft Windows" (1572319968). 
00040 /// Additional information is available in John Robbins'
00041 /// "Debugging Applications for Microsoft .NET and Microsoft Windows" (0735615365)
00042 /// and Feng Yuan's
00043 /// "Windows Graphics Programming: Win32 GDI and DirectDraw" (0130869856).
00044 ///
00045 /// I'm avoiding the debugger methods and windows hook methods currently for
00046 /// a few reasons (although they may prove useful in the future and will get 
00047 /// tossed in here if so).
00048 ///
00049 /// -# Easier to detect, so some games' anti-cheat/anti-crack logic might be
00050 ///    more likely to trigger on it than the techniques I've used.
00051 ///    ... and some antivirus software for that matter, although I'm not sure why
00052 ///    they don't appear to trigger on these techniques.  I'm using F-Secure 2008,
00053 ///    and while it complains horribly when some applications toss DLLs into
00054 ///    others with hooks, so far it seems ok when my apps do the same with 
00055 ///    these techniques...
00056 /// -# Ideally, we want the option to exit the injector process immediately.
00057 ///    Both the debugger and windows hook methods of injection make that
00058 ///    somewhat more difficult.
00059 /// -# I hadn't found a pretty implementation of the StartDLLWithProcess technique
00060 ///    that I liked. Richter discusses the idea, but doesn't give implementation 
00061 ///    details in his books that I've seen. Enjoy :) 
00062 ///
00063 /// When using StartDLLWithProcess, you'll need the following undecorated function
00064 /// exported from your injected DLL (e.g. use a .def file for it too):
00065 /// \code
00066 /// extern "C" {
00067 ///    void*        gPassedData    = 0;
00068 ///    unsigned int gPassedDataLen = 0;
00069 ///    void _declspec(dllexport) UnpatchProcess(void*        passData,
00070 ///                                             unsigned int passDataLen,
00071 ///                                             void*        startLoc,
00072 ///                                             unsigned int patchSize,
00073 ///                                             void*        hostBuffer,
00074 ///                                             unsigned int hostProcId)
00075 ///    {
00076 ///        // Open host process and read the stored bytes into our 
00077 ///        // hooked process over the start location, restoring the
00078 ///        // original executable code.
00079 ///        HANDLE hostProcess = ::OpenProcess(PROCESS_ALL_ACCESS,
00080 ///                                           FALSE,
00081 ///                                           hostProcId);
00082 ///        if (hostProcess != 0)
00083 ///        {
00084 ///            DWORD amountRead = 0;
00085 ///            ReadProcessMemory(hostProcess,hostBuffer,startLoc,patchSize,&amountRead);
00086 ///            if (passDataLen && passData)
00087 ///            {
00088 ///                gPassedDataLen = passDataLen;
00089 ///                gPassedData = new BYTE[passDataLen];
00090 ///                ::ReadProcessMemory(hostProcess,passData,gPassedData,passDataLen,&amountRead);
00091 ///            }
00092 ///            CloseHandle(hostProcess);
00093 ///        }
00094 ///        // Got the data from the parent. Open the wait event and set it.
00095 ///        CATWChar eventName[64];
00096 ///        wsprintf(eventName,L"UnpatchProcess_%d",hostProcId);
00097 ///        HANDLE waitEvent = ::OpenEvent(GENERIC_READ|GENERIC_WRITE,FALSE,eventName);
00098 ///        if (waitEvent != 0)
00099 ///        {
00100 ///            SetEvent(waitEvent);
00101 ///            CloseHandle(waitEvent);
00102 ///        }
00103 ///        // Now, restore the stack and go back to the starting location                
00104 ///        __asm
00105 ///        {         
00106 ///            mov esp,ebp  // Get original base pointer
00107 ///            pop ebp      
00108 ///            add esp,0x1c // Restore stack point to start of our code
00109 ///            popfd
00110 ///            popad
00111 ///            ret
00112 ///        }
00113 ///    }
00114 ///}
00115 /// \endcode
00116 ///
00117 /// \todo
00118 /// Add named-pipe parameter passing (or similar) to injection by pid.
00119 class CATDLLInjector
00120 {
00121     public:
00122         /// Retrieves a process id for a process name.
00123         /// If multiple processes matching the name are present, it
00124         /// will return the first one.
00125         ///
00126         /// \param  processName     process name (e.g. Notepad.exe)
00127         /// \param  pid             ref to pid, set on success.
00128         /// \param  procIndex       optional index of process if multiple
00129         /// \return CATResult       CAT_SUCCESS on success. 
00130         ///                         CAT_STAT_MULTIPLE_PROCS if multiple.
00131         static CATResult GetProcessId( const CATWChar* processName,
00132                                        CATUInt32&      pid,
00133                                        CATUInt32       procIndex = -1);
00134 
00135         /// Injects the specified DLL into the process.
00136         /// 
00137         /// \param  dllPath     Path to DLL file to inject into process
00138         /// \param  pid         Process ID to inject DLL into
00139         /// \return CATResult   0 on success
00140         static CATResult InjectIntoProcess   (const CATWChar* dllPath, 
00141                                               CATUInt32       pid);
00142 
00143 
00144         
00145         /// Creates a process using the specified execFile path and 
00146         /// injects the DLL into the process at startup.
00147         ///
00148         /// \param  dllPath      Path to DLL file to inject into process
00149         /// \param  execFile     Path of executable file to start
00150         /// \param  commandLine  full command line to pass
00151         /// \param  passData     Ptr to data to pass to DLL, or null for none.
00152         /// \param  passDataLen  Length of data to pass, or 0 for none.
00153         /// \return CATResult    0 on success
00154         static CATResult StartDLLWithProcess (const CATWChar* dllPath, 
00155                                               const CATWChar* execFile,
00156                                               const CATWChar* commandLine,
00157                                               const void*     passData      = 0,
00158                                               CATUInt32       passDataLen   = 0);
00159 
00160     private:
00161 };
00162 
00163 
00164 
00165 #endif //_CATDLLInjector_H_
00166 
00167 #endif //CAT_CONFIG_WIN32

Generated on Mon Feb 11 04:09:43 2008 for Game Accessibility Suite by doxygen 1.5.4