Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / Win32

Subclassing using DLL Injection

Rate me:
Please Sign up or sign in to vote.
4.95/5 (12 votes)
13 Feb 2013CPOL4 min read 47.2K   1.4K   49   25
Subclassing a window using the DLL Injection technique.

Introduction

There are several articles presented on DLL Injection. But still I wanted to do a simple example which will be easy for a novice programmer.

Background

As you know there are several uses of DLL injection like hot patching, logging, subclassing, etc. This article focuses on subclassing a window using DLL injection. Subclassing is redefining the behavior of the window by changing the window procedure. To change the window procedure, the window procedure should reside in the process which created the window. I planned to mimic the hacking by scrambling the window behavior without the knowledge of the process which created the window. There are three modules involved in this article.

  1. Injectee: This is a target process which created the window. I call this "Injectee" to which the DLL ("Injection" ) is being injected. This is a simple Win32 application which has a window and whenever the left mouse button is pressed, a circle is being drawn. That's all!!!!
  2. Injection: This is a DLL which has the new window procedure to be hooked to the window of the Injectee.
  3. Injector: This is the process which actually injects the injection into the injectee. This is a simple console application.

Using the code

As mentioned earlier, the source code has three modules.

  1. Make sure to build the Injection first so that the DLL is ready to be injected. Once the Injection module is built successfully, the resulting DLL is copied to the x86 directory.
  2. Then build the Injectee and launch it. Now when you do left click on the screen using mouse, circles are drawn on the click location and it will continue to work fine. When the injector is built, the DLL is copied from the x86 directory to the Debug/Release directory of the Injectee project.
  3. Build the Injector and launch it. The injector will inject the injection DLL into the injectee's process and terminates.
  4. Now if you left click on the screen, you won't see the circle, rather a bizarre message "UR HACKED".
  5. The source code for the Injetee is nothing special. It's just a plain vanilla code to create a window using the SDK.

Let's see the source code for the Injection. As we know, the Injection is a simple DLL and when DllMain is called with reason as DLL_PROCESS_ATTACH, I'm doing the hack.

C++
//
case DLL_PROCESS_ATTACH:
{
   //Find the window of the Injectee using its title
   HWND hwnd = ::FindWindow(NULL,TEXT("Injectee") );
 
   //If the window found, then change it's window proc
   if( hwnd )
   {
    oldWindowProc = ::SetWindowLongPtr( hwnd, GWL_WNDPROC, (LONG_PTR) HackingWndProc );
   }
   break;
}

The new window procedure looks something like this:

C++
LRESULT CALLBACK HackingWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch( message ) 
 {
  case WM_LBUTTONDOWN:
   {
    int x = GET_X_LPARAM(lParam);
    int y = GET_Y_LPARAM(lParam);
    HDC hDC = ::GetDC( hWnd );
    //::Rectangle(  hDC,x,y,(x+50),(y+50) );
    DrawText( hDC,x,y);
    break;
   }
  case WM_RBUTTONDOWN:
   {
     int x = GET_X_LPARAM(lParam);
     int y = GET_Y_LPARAM(lParam);
     HDC hDC = ::GetDC( hWnd );
     ::Ellipse( hDC,x,y,(x+50),(y+50));
     break;
   }
  case WM_DESTROY:
   {
    PostQuitMessage(0);
    break;
   }
  default:
   return DefWindowProc(hWnd, message, wParam, lParam);
 }
 return 0;
}

Next let's see the source code for the Injector.

This code is simple. First we should know the name of the DLL (injection) to be injected in the target process (injectee).

  • This DLL name should be known by the target process. So this has to be written in the target process' address space.
  • Find out the window of the Injectee using its window title.
  • Next get the handle of the process which created the window using GetWindowThreadProcessId.
  • Open the injectee's process using its handle.
  • Then allocate memory in the injectee's address space to write the name of the DLL to be injected.
  • Write the name of the DLL to be injected.
  • Get the address of the LoadLibrary method. This is the method to be invoked by the thread which is going to be created in the the injectee's address space.
  • Then call CreateRemoteThread to create a thread inside the injectee's address space. This thread is going to execute the LoadLibrary function with the library name as the injection DLL.
  • As the thread calls the LoadLibrary method to load the DLL, DllMain is called with reason as DLL_PROCESS_ATTACH. Refer the Injection's code to see what happens when DllMain is called.
  • Wait for the remote thread to execute before calling the VirtualFree method, otherwise when the remote thread looks for the name of the DLL, the name of the address block which holds the DLL name is already freed by the injector process which may cause a crash!
C++
int _tmain(int argc, _TCHAR* argv[])
{
 //Name of the dll to be injected into the target process [ hereafter "Injectee" ] 
 char* szInjectionDLLName  = TEXT("Injection.dll");

 DWORD dwProcessID;
 
 //Find the main window of the Injectee
 HWND hwnd = ::FindWindow(NULL,TEXT("Injectee") );

 //Get the process hanlde of injectee
 GetWindowThreadProcessId(hwnd, &dwProcessID ); 

 //Open the process
 HANDLE hProcess = ::OpenProcess(  PROCESS_ALL_ACCESS,false, dwProcessID);

 //Allocate the memory in the Injectee's address space
 void* baseAddress =  VirtualAllocEx( hProcess,NULL,
   strlen(szInjectionDLLName), MEM_COMMIT, PAGE_READWRITE );

 //Write the name of the dll to be injected into the Injectee
 SIZE_T nbBytesWritten = 0;
 WriteProcessMemory( hProcess,baseAddress,szInjectionDLLName,
   strlen(szInjectionDLLName),&nbBytesWritten );

 //Get the load libraries address
 FARPROC pLoadLib = GetProcAddress( GetModuleHandle(TEXT("kernel32.dll") ), "LoadLibraryA");

 //Create the remote thread in the target process
 DWORD dwThreadID = 0;
 HANDLE hRemoteThread = CreateRemoteThread(hProcess,NULL,0,
   (LPTHREAD_START_ROUTINE)pLoadLib, baseAddress,0, &dwThreadID );

 //Wait for the remote thread till it finish its job.
 //Otherwise, the next statement [ VirtualFreeEx ] will be called
 //which release the address in the target process
 //and when remote thread refers the address it leads to crashing!!!
 WaitForSingleObject( hRemoteThread,INFINITE );

 //Now free the memory allocated in the injectee's address space
 VirtualFreeEx( hProcess, baseAddress,0, MEM_RELEASE );

 //DONE!!!!!!!!!!!.
 return 0;
}

History

Version1: [ 02/13/2013 ]

This is the first version of the article. Will keep updated based on the viewer's comments.

Version2: [ 09/18/2015 ]

There was an issue/bug with the files uploaded in the first version. I have fixed the issues and uploading the files as version2.

Note: When you want to run in debug mode,make sure to build the Injection (dll)  in debug mode and run the Injector as well as the Injectee in debug mode. The same applies to release mode as well.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
I'm working as Senior software Engineer since 7 years and interested in MFC and COM programming.

Comments and Discussions

 
GeneralNot able to inject dll in 32 bit process in 64 bit machine Pin
Member 100142335-May-13 0:50
professionalMember 100142335-May-13 0:50 
GeneralRe: Not able to inject dll in 32 bit process in 64 bit machine Pin
Babu_Abdulsalam4-Jun-13 2:02
Babu_Abdulsalam4-Jun-13 2:02 
GeneralRe: Not able to inject dll in 32 bit process in 64 bit machine Pin
Anh Tuan gmail20-May-17 8:04
Anh Tuan gmail20-May-17 8:04 
GeneralMy vote of 5 Pin
Joezer BH22-Apr-13 1:32
professionalJoezer BH22-Apr-13 1:32 
GeneralRe: My vote of 5 Pin
Babu_Abdulsalam30-Apr-13 4:47
Babu_Abdulsalam30-Apr-13 4:47 
QuestionInjection fails Pin
Member 443327425-Mar-13 23:26
Member 443327425-Mar-13 23:26 
GeneralMy vote of 2 Pin
Cristian Amarie8-Feb-13 21:27
Cristian Amarie8-Feb-13 21:27 
QuestionPostQuitMessage ? Pin
Cristian Amarie8-Feb-13 21:25
Cristian Amarie8-Feb-13 21:25 
AnswerRe: PostQuitMessage ? Pin
Babu_Abdulsalam9-Feb-13 1:12
Babu_Abdulsalam9-Feb-13 1:12 
GeneralRe: PostQuitMessage ? Pin
Cristian Amarie9-Feb-13 7:03
Cristian Amarie9-Feb-13 7:03 
AnswerRe: PostQuitMessage ? Pin
Babu_Abdulsalam9-Feb-13 1:14
Babu_Abdulsalam9-Feb-13 1:14 
GeneralRe: PostQuitMessage ? Pin
Cristian Amarie9-Feb-13 7:06
Cristian Amarie9-Feb-13 7:06 
GeneralRe: PostQuitMessage ? Pin
Babu_Abdulsalam10-Feb-13 18:33
Babu_Abdulsalam10-Feb-13 18:33 
QuestionGood Pin
sl65agm23-Jan-13 17:29
sl65agm23-Jan-13 17:29 
Oh, Brother III, that great.
QuestionIt doesn't work in my computer Pin
ruiwng19-Jan-13 15:20
ruiwng19-Jan-13 15:20 
AnswerRe: It doesn't work in my computer Pin
Babu_Abdulsalam22-Jan-13 17:43
Babu_Abdulsalam22-Jan-13 17:43 
GeneralRe: It doesn't work in my computer Pin
ruiwng23-Jan-13 0:44
ruiwng23-Jan-13 0:44 
GeneralRe: It doesn't work in my computer Pin
Babu_Abdulsalam23-Jan-13 22:30
Babu_Abdulsalam23-Jan-13 22:30 
GeneralRe: It doesn't work in my computer Pin
ruiwng23-Jan-13 23:49
ruiwng23-Jan-13 23:49 
AnswerRe: It doesn't work in my computer Pin
Cristian Amarie9-Feb-13 7:07
Cristian Amarie9-Feb-13 7:07 
AnswerRe: It doesn't work in my computer Pin
Chad3F20-Feb-13 15:50
Chad3F20-Feb-13 15:50 
GeneralMy vote of 5 Pin
zssure17-Jan-13 2:23
zssure17-Jan-13 2:23 
QuestionI love Codeproject Pin
Matth Moestl16-Jan-13 0:43
professionalMatth Moestl16-Jan-13 0:43 
QuestionDidactic example Pin
_Flaviu15-Jan-13 19:43
_Flaviu15-Jan-13 19:43 
AnswerRe: Didactic example Pin
Babu_Abdulsalam15-Jan-13 20:29
Babu_Abdulsalam15-Jan-13 20:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.