65.9K
CodeProject 正在变化。 阅读更多。
Home

通过 DLL 注入进行子类化

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (11投票s)

2013年1月15日

CPOL

4分钟阅读

viewsIcon

50547

downloadIcon

1448

使用 DLL 注入技术对窗口进行子类化。

引言

已经有很多关于 DLL 注入的文章。但我仍然想做一个简单的例子,这对新手程序员来说很容易。

背景

如你所知,DLL 注入有很多用途,如热补丁、日志记录、子类化等。本文重点介绍使用 DLL 注入对窗口进行子类化。子类化通过更改窗口过程来重新定义窗口的行为。要更改窗口过程,窗口过程应该驻留在创建窗口的进程中。我计划通过在创建窗口的进程不知情的情况下扰乱窗口行为来模拟黑客行为。本文涉及三个模块。

  1. Injectee(被注入者):这是创建窗口的目标进程。我称之为 "Injectee",DLL("Injection")将被注入到它。这是一个简单的 Win32 应用程序,它有一个窗口,并且每当按下鼠标左键时,就会绘制一个圆圈。仅此而已!!!!
  2. Injection(注入):这是一个 DLL,它具有要钩入 Injectee 窗口的新窗口过程。
  3. Injector(注入器):这是实际将注入 DLL 注入到被注入者进程中的进程。这是一个简单的控制台应用程序。

使用代码

如前所述,源代码有三个模块。

  1. 确保先构建 Injection,以便 DLL 准备好被注入。成功构建 Injection 模块后,将生成的 DLL 复制到 *x86* 目录。
  2. 然后构建 Injectee 并启动它。现在,当你使用鼠标在屏幕上进行左键单击时,圆圈将被绘制在点击位置,并且它将继续正常工作。构建 Injector 时,DLL 会从 *x86* 目录复制到 Injectee 项目的 *Debug/Release* 目录。
  3. 构建 Injector 并启动它。注入器会将注入 DLL 注入到被注入者的进程中并终止。
  4. 现在,如果你在屏幕上左键单击,你将看不到圆圈,而是一个奇怪的消息 "UR HACKED"。
  5. Injetee 的源代码没有什么特别的。它只是一个使用 SDK 创建窗口的普通代码。

让我们看看 Injection 的源代码。正如我们所知,Injection 是一个简单的 DLL,并且当以 DLL_PROCESS_ATTACH 作为原因调用 DllMain 时,我就在进行黑客行为。

//
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;
}

新的窗口过程看起来像这样

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;
}

接下来让我们看看 Injector 的源代码。

此代码很简单。首先我们应该知道要注入到目标进程(被注入者)中的 DLL(注入)的名称。

  • 此 DLL 名称应为目标进程所知。因此,必须将其写入目标进程的地址空间。
  • 使用窗口标题找出 Injectee 的窗口。
  • 接下来,使用 GetWindowThreadProcessId 获取创建窗口的进程的句柄。
  • 使用其句柄打开被注入者的进程。
  • 然后在被注入者的地址空间中分配内存以写入要注入的 DLL 的名称。
  • 写入要注入的 DLL 的名称。
  • 获取 LoadLibrary 方法的地址。这是要在被注入者的地址空间中创建的线程调用的方法。
  • 然后调用 CreateRemoteThread 以在被注入者的地址空间内创建一个线程。此线程将使用库名称作为注入 DLL 执行 LoadLibrary 函数。
  • 由于线程调用 LoadLibrary 方法来加载 DLL,因此会以 DLL_PROCESS_ATTACH 为原因调用 DllMain。请参阅 Injection 的代码,以了解调用 DllMain 时会发生什么。
  • 在调用 VirtualFree 方法之前,请等待远程线程执行,否则当远程线程查找 DLL 名称时,保存 DLL 名称的地址块已被注入器进程释放,这可能会导致崩溃!
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;
}

历史

版本1:[ 2013年2月13日 ]

这是文章的第一个版本。会根据查看者的评论保持更新。

版本2:[ 2015年9月18日 ]

第一个版本中上传的文件存在问题/错误。我已经修复了这些问题并将文件作为版本2上传。

注意:当您想在调试模式下运行时,请确保在调试模式下构建 Injection (dll)  并在调试模式下运行 Injector 以及 Injectee。同样适用于发布模式。

© . All rights reserved.