自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

網(wǎng)絡安全編程:遠程線程編程

安全
關于遠程線程的知識,本文介紹3個例子,分別是DLL的注入、卸載遠程DLL和不依賴DLL進行代碼注入。

[[385466]]

 Windows操作系統(tǒng)下,為了避免各個進程相互影響,每個進程地址空間都是被隔離的。所謂 “遠程線程”,并不是跨計算機的,而是跨進程的。簡單來說,就是進程A要在進程B中創(chuàng)建一個線程,這就叫遠程線程。

遠程線程被木馬、外掛等程序廣泛使用,反病毒軟件中也離不開遠程線程的技術。技術應用的兩面性取決于自己的個人行為意識,良性的技術學習對自己的人生發(fā)展是非常有好處的,就算談不上好處,至少不會給自己帶來不必要的麻煩。

關于遠程線程的知識,本文介紹3個例子,分別是DLL的注入、卸載遠程DLL和不依賴DLL進行代碼注入。

1. DLL遠程注入

木馬或病毒編寫的好壞取決于其隱藏的程度,而不在于其功能的多少。無論是木馬還是病毒,都是可執(zhí)行程序。如果它們是EXE文件的話,那么在運行時必定會產(chǎn)生一個進程,就很容易被發(fā)現(xiàn)。為了不被發(fā)現(xiàn),在編寫木馬或病毒時可以選擇將其編寫為DLL文件。DLL文件的運行不會單獨創(chuàng)建一個進程,它的運行被加載到進程的地址空間中,因此其隱蔽性相對較好。DLL文件如果不被進程加載又如何在進程的地址空間中運行呢?方式是強制讓某進程加載DLL文件到其地址空間中去,這個強制的手段就是現(xiàn)在要介紹的遠程線程。

創(chuàng)建遠程線程的函數(shù)CreateRemoteThread()的定義如下: 

  1. HANDLE CreateRemoteThread(  
  2.  HANDLE hProcess,  
  3.  LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  4.  DWORD dwStackSize,  
  5.  LPTHREAD_START_ROUTINE lpStartAddress,  
  6.  LPVOID lpParameter,  
  7.  DWORD dwCreationFlags,  
  8.  LPDWORD lpThreadId  
  9. ); 

該函數(shù)的功能是創(chuàng)建一個遠程的線程。我們把CreateThread()函數(shù)和CreateRemoteThread()函數(shù)進行比較。對于CreateThread()函數(shù)來說,CreateRem oteThread()函數(shù)比其多了一個hProcess參數(shù),該參數(shù)是指定要創(chuàng)建線程的進程句柄。其實CreateThread()函數(shù)的內(nèi)容實現(xiàn)就是依賴于CreateRemoteThread()函數(shù)來完成的。CreateThread()函數(shù)的代碼實現(xiàn)如下: 

  1. /*  
  2.   * @implemented  
  3. */  
  4. HANDLE  
  5. WINAPI  
  6. CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  7.   DWORD dwStackSize, 
  8.   LPTHREAD_START_ROUTINE lpStartAddress,  
  9.   LPVOID lpParameter,  
  10.   DWORD dwCreationFlags,  
  11.   LPDWORD lpThreadId)  
  12.  
  13.   /* 創(chuàng)建遠程線程  
  14.   return CreateRemoteThread(NtCurrentProcess(), 
  15.     lpThreadAttributes,  
  16.     dwStackSize,  
  17.     lpStartAddress, 
  18.     lpParameter,  
  19.     dwCreationFlags,  
  20.     lpThreadId);  

在上面的代碼中,NtGetCurrentProcess()函數(shù)的功能是獲得當前進程的句柄。

CreateRemoteThread()函數(shù)是給其他進程創(chuàng)建線程使用的,其第一個參數(shù)是指定某進程的句柄,獲取進程的句柄使用API函數(shù)OpenProcess(),該函數(shù)需要提供PID作為參數(shù)。

除了hProcess參數(shù)以外,剩余的關鍵參數(shù)就只有l(wèi)pStartAddress和lpParameter兩個了。lpStartAddress指定線程函數(shù)的地址,lpParameter指定傳遞給線程函數(shù)的參數(shù)。前面提到,每個進程的地址空間是隔離的,那么新創(chuàng)建的線程函數(shù)的地址也應該在目標進程中,而不應該在調(diào)用CreateRemoteThread()函數(shù)的進程中。同樣,傳遞給線程函數(shù)的參數(shù)也應該在目標進程中。

如何讓線程函數(shù)的地址在目標進程中呢?如何讓線程函數(shù)的參數(shù)也可以傳遞到目標進程中呢?在討論這個問題以前,先來考慮線程函數(shù)要完成的功能。這里主要完成的功能是注入一個DLL文件到目標進程中,那么線程函數(shù)的功能就是加載DLL文件。加載DLL文件使用的是LoadLibrary()函數(shù)。LoadLibrary()函數(shù)的定義: 

  1. HMODULE LoadLibrary(  
  2.  LPCTSTR lpFileName  
  3. );  
  4. 看一下線程函數(shù)的定義格式,具體如下: 
  5. DWORD WINAPI ThreadProc(  
  6.  LPVOID lpParameter  
  7. ); 

比較兩個函數(shù)可以發(fā)現(xiàn),除了函數(shù)的返回值類型和參數(shù)類型以外,其函數(shù)格式是相同的。這里只考慮其相同的部分。因為其函數(shù)的格式相同,首先調(diào)用約定相同,都是WINAPI(也就是__stdcall方式);其次函數(shù)個數(shù)相同,都只有一個。那么,可以直接把LoadLibrary()函數(shù)作為線程函數(shù)創(chuàng)建到指定的進程中。LoadLibrary()的參數(shù)是欲加載的DLL文件的完整路徑,只要在CreateRemoteThread()函數(shù)中賦值一個指向DLL文件完整路徑的指針給LoadLibrary()函數(shù)即可。這樣使用CreateRemoteThread()函數(shù)就可以創(chuàng)建一個遠程線程了。不過,還有兩個問題沒有解決,首先是如何將LoadLibrary()函數(shù)的地址放到目標進程空間中讓CreateRemoteThread()調(diào)用,其次是傳遞給LoadLibrary()函數(shù)的參數(shù)也需要在目標進程空間中,并且要通過CreateRemoteThread()函數(shù)指定給LoadLibrary()函數(shù)。

首先解決第1個問題,即如何將LoadLibrary()函數(shù)的地址放到目標進程空間中。LoadLibrary()函數(shù)是系統(tǒng)中的Kernel32.dll的導出函數(shù),Kernel32.dll這個DLL文件在任何進程中的加載位置都是相同的,也就是說,LoadLibrary()函數(shù)的地址在任何進程中的地址都是相同的。因此,只要在進程中獲得LoadLibrary()函數(shù)的地址,那么該地址在目標進程中也可以使用。CreateRemoteThread()函數(shù)的線程地址參數(shù)直接傳遞LoadLibrary()函數(shù)的地址即可。

其次解決第2個問題,即如何將欲加載的DLL文件完整路徑寫入目標進程中。這需要借助WriteProcessMemory()函數(shù),其定義如下: 

  1. BOOL WriteProcessMemory(  
  2.  HANDLE hProcess, // handle to process  
  3.  LPVOID lpBaseAddress, // base of memory area  
  4.  LPVOID lpBuffer, // data buffer  
  5.  DWORD nSize, // number of bytes to write  
  6.  LPDWORD lpNumberOfBytesWritten // number of bytes written  
  7. ); 

該函數(shù)的功能是把lpBuffer中的內(nèi)容寫到進程句柄是hProcess進程的lpBaseAddress地址處,寫入長度為nSize。

參數(shù)說明如下。

hProcess:該參數(shù)是指定進程的進程句柄。

lpBaseAddress:該參數(shù)是指定寫入目標進程內(nèi)存的起始地址。

lpBuffer:該參數(shù)是要寫入目標進程內(nèi)存的緩沖區(qū)起始地址。

nSize:該參數(shù)是指定寫入目標內(nèi)存中的緩沖區(qū)的長度。

lpNumberOfBytesWritten:該參數(shù)用于接收實際寫入內(nèi)容的長度。

該函數(shù)的功能非常強大,比如在破解方面,用該函數(shù)可以實現(xiàn)一個“內(nèi)存補丁”;在開發(fā)方面,該函數(shù)可以用于修改目標進程中指定的值(比如游戲修改器可以修改游戲中的錢、紅、藍等)。

使用該函數(shù)可以把DLL文件的完整路徑寫入到目標進程的內(nèi)存地址中,這樣就可以在目標進程中用LoadLibrary()函數(shù)加載指定的DLL文件了。解決了上面的兩個問題,還有第3個問題需要解決。WriteProcessMemory()函數(shù)的第2個參數(shù)是指定寫入目標進程內(nèi)存的緩沖區(qū)起始地址。這個地址在目標進程中,那么這個地址在目標進程的哪個位置呢?目標進程中的內(nèi)存塊允許把DLL文件的路徑寫進去嗎?

第3個要解決的問題是如何確定應該將DLL文件的完整路徑寫入目標進程的哪個地址。對于目標進程來說,事先是不會準備一塊地址讓用戶進行寫入的,用戶能做的是自己在目標進程中申請一塊內(nèi)存,然后把DLL文件的路徑進行寫入,寫入在目標進程新申請到的內(nèi)存空間中。在目標進程中申請內(nèi)存的函數(shù)是VirtualAllocEx(),其定義如下: 

  1. LPVOID VirtualAllocEx(  
  2.  HANDLE hProcess,  
  3.  LPVOID lpAddress,  
  4.  SIZE_T dwSize,  
  5.  DWORD flAllocationType,  
  6.  DWORD flProtect  
  7. ); 

VirtualAllocEx()函數(shù)的參數(shù)說明如下。

hProcess:該參數(shù)是指定進程的進程句柄。

lpAddress:該參數(shù)是指在目標進程中申請內(nèi)存的起始地址。

dwSize:該參數(shù)是指在目標進程中申請內(nèi)存的長度。

flAllocationType:該參數(shù)指定申請內(nèi)存的狀態(tài)類型。

flProtect:該參數(shù)指定申請內(nèi)存的屬性。

該函數(shù)的返回值是在目標進程申請到的內(nèi)存塊的起始地址。

到此,關于編寫一個DLL注入的所有知識都已經(jīng)具備了?,F(xiàn)在開始編寫一個DLL注入的工具,其界面如圖1所示。

圖1  DLL注入/卸載器

該工具有2個作用,分別是注入DLL和卸載被注入的DLL。關于卸載被注入的DLL的功能,將在后面進行介紹。在界面上要求輸入兩部分內(nèi)容,第1部分是欲注入的DLL文件的完整路徑(一定要是完整路徑),第2部分是進程的名稱。

首先看一下關于界面的操作,代碼如下: 

  1. void CInjectDllDlg::OnBtnInject()  
  2.  
  3.   // 添加處理程序代碼  
  4.   char szDllName[MAX_PATH] = { 0 };  
  5.   char szProcessName[MAXBYTE] = { 0 };  
  6.   DWORD dwPid = 0 
  7.   GetDlgItemText(IDC_EDIT_DLLFILE, szDllName, MAX_PATH);  
  8.   GetDlgItemText(IDC_EDIT_PROCESSNAME, szProcessName, MAXBYTE);  
  9.   // 由進程名獲得 PID  
  10.   dwPid = GetProcId(szProcessName);  
  11.   // 注入 szDllName 到 dwPid  
  12.   InjectDll(dwPid, szDllName);  

代碼中調(diào)用了另外兩個函數(shù),第1個是由進程名獲得PID的函數(shù),第2個是用于DLL注入的函數(shù)。GetProcId()函數(shù)的代碼如下: 

  1. DWORD CInjectDllDlg::GetProcId(char *szProcessName)  
  2.  
  3.   BOOL bRet;  
  4.   PROCESSENTRY32 pe32;  
  5.   HANDLE hSnap;  
  6.   hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);  
  7.   pe32.dwSize = sizeof(pe32);  
  8.   bRet = Process32First(hSnap, &pe32);  
  9.   while ( bRet )  
  10.   {  
  11.     // strupr()函數(shù)是將字符串轉化為大寫  
  12.     if ( lstrcmp(strupr(pe32.szExeFile),strupr(szProcessName)) == 0 )  
  13.     {  
  14.       return pe32.th32ProcessID;  
  15.     }  
  16.     bRet = Process32Next(hSnap, &pe32);  
  17.   }  
  18.   return 0;  
  19. } +

InjectDll()函數(shù)的代碼如下: 

  1. VOID CInjectDllDlg::InjectDll(DWORD dwPid, char *szDllName)  
  2.  
  3.   if ( dwPid == 0 || lstrlen(szDllName) == 0 ) 
  4.   {  
  5.     return ;  
  6.   }  
  7.   char *pFunName = "LoadLibraryA" 
  8.   // 打開目標進程  
  9.   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwPid);  
  10.   if ( hProcess == NULL )  
  11.   {  
  12.     return ;  
  13.   }  
  14.   // 計算欲注入 DLL 文件完整路徑的長度  
  15.   int nDllLen = lstrlen(szDllName) + sizeof(char);  
  16.   // 在目標進程申請一塊長度為 nDllLen 大小的內(nèi)存空間  
  17.   PVOID pDllAddr = VirtualAllocEx(hProcess,NULL, nDllLen,MEM_COMMIT,PAGE_READWRITE);  
  18.   if ( pDllAddr == NULL )  
  19.   {  
  20.     CloseHandle(hProcess);  
  21.     return ;  
  22.   }  
  23.   DWORD dwWriteNum = 0 
  24.   // 將欲注入 DLL 文件的完整路徑寫入在目標進程中申請的空間內(nèi)  
  25.   WriteProcessMemory(hProcess, pDllAddr, szDllName,nDllLen, &dwWriteNum);  
  26.   // 獲得 LoadLibraryA()函數(shù)的地址  
  27.   FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),pFunName);  
  28.   // 創(chuàng)建遠程線程  
  29.   HANDLE hThread = CreateRemoteThread(hProcess,NULL, 0,(LPTHREAD_START_ROUTINE)pFunAddr,pDllAddr, 0, NULL);  
  30.   WaitForSingleObject(hThread, INFINITE);  
  31.   CloseHandle(hThread);  
  32.   CloseHandle(hProcess);  

InjectDll()函數(shù)有 2 個參數(shù),分別是目標進程的 ID 值和要被注入的 DLL 文件的完整路徑。在代碼中獲得的不是 LoadLibrary()函數(shù)的地址,而是 LoadLibraryA()函數(shù)的地址。在系統(tǒng)中其實沒有 LoadLibrary()函數(shù),有的只是 LoadLibraryA()和 LoadLibraryW()兩個函數(shù)。這兩個函數(shù)分別針對 ANSI 字符串和 UNICODE 字符串。而 LoadLibrary()函數(shù)只是一個宏。在編寫程序的時候,直接使用該宏是可以的。如果要獲取 LoadLibrary()函數(shù)的地址,就要明確指定是獲取 LoadLibraryA()還是 LoadLibraryW()。

LoadLibrary()宏定義如下: 

  1. #ifdef UNICODE  
  2. #define LoadLibrary LoadLibraryW  
  3. #else  
  4. #define LoadLibrary LoadLibraryA  
  5. #endif // !UNICODE 

只要涉及字符串的函數(shù),都會有相應的ANSI版本和UNICODE版本;其余不涉及字符串的函數(shù),沒有ANSI版本和UNICODE版本的區(qū)別。

為了測試DLL加載是否成功,在代碼的DllMain()函數(shù)中加入如下代碼: 

  1. case DLL_PROCESS_ATTACH:  
  2.  
  3.   MsgBox("!DLL_PROCESS_ATTACH!");  
  4.   break;  
  5. }  

現(xiàn)在測試一下注入的效果,如圖2和圖3所示。

圖2  DLL文件被注入成功的提示

圖3  查看進程中的DLL列表確認被裝載成功

在圖2中,彈出的對話框是DLL程序在DLL_PROCESS_ATTACH時出現(xiàn)的。其所在的進程為notepad.exe。從圖2中可以看出,彈出提示框的標題處是notepad.exe進程的路徑。圖3是用工具查看進程中所加載的DLL文件列表,可以看出,通過注入工具注入的DLL文件已經(jīng)被加載到notepad.exe的進程空間中。

如果要對系統(tǒng)進程進行注入的話,由于進程權限的關系是無法注入成功的。在打開目標進程時用到了OpenProcess()函數(shù),由于權限不夠,會導致無法打開進程并獲得進程句柄。通過調(diào)整當前進程的權限,可以打開系統(tǒng)進程并獲得進程句柄。如果在Win8或更高版本上運行注入程序的話,需要選中注入工具單擊右鍵,選擇“以管理員身份運行”才可以完成注入。

2. 卸載被注入的DLL文件

DLL注入如果應用在木馬方面,危害很大,這里完成一個卸載被注入DLL的程序。卸載被注入DLL程序的思路和注入的思路是一樣的,而且代碼的改動也非常小。區(qū)別在于現(xiàn)在的功能是卸載,而不是注入。

DLL卸載使用的API函數(shù)是FreeLiabrary(),其定義如下: 

  1. BOOL FreeLibrary(  
  2.  HMODULE hModule // handle to DLL module  
  3. ); 

該函數(shù)的參數(shù)是要卸載的模塊的句柄。

FreeLibrary()函數(shù)使用的模塊句柄可以通過Module32First()和Module32Next()兩個函數(shù)獲取。在使用Module32First()和Module32Next()兩個函數(shù)的時候,需要用到MODULEENTRY32結構體,該結構體中保存了模塊的句柄。MODULEENTRY32結構體的定義如下: 

  1. typedef struct tagMODULEENTRY32 {  
  2.  DWORD dwSize;  
  3.  DWORD th32ModuleID;  
  4.  DWORD th32ProcessID;  
  5.  DWORD GlblcntUsage;  
  6.  DWORD ProccntUsage;  
  7.  BYTE * modBaseAddr;  
  8.  DWORD modBaseSize;  
  9.  HMODULE hModule;  
  10.  TCHAR szModule[MAX_MODULE_NAME32 + 1];  
  11.  TCHAR szExePath[MAX_PATH];  
  12.  } MODULEENTRY32;  
  13. typedef MODULEENTRY32 *PMODULEENTRY32; 

該結構體中的hModule為模塊的句柄,szModule為模塊的名稱,szExePath是完整的模塊的名稱(所謂完整,包括路徑和模塊名稱)。

卸載遠程進程中DLL模塊的代碼如下: 

  1. VOID CInjectDllDlg::UnInjectDll(DWORD dwPid, char *szDllName)  
  2.  
  3.   if ( dwPid == 0 || lstrlen(szDllName) == 0 )  
  4.   { 
  5.     return ;  
  6.   }  
  7.   HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwPid);  
  8.   MODULEENTRY32 me32;  
  9.   me32.dwSize = sizeof(me32);  
  10.   // 查找匹配的進程名稱  
  11.   BOOL bRet = Module32First(hSnap, &me32);  
  12.   while ( bRet )  
  13.   {  
  14.     if ( lstrcmp(strupr(me32.szExePath),  
  15.     strupr(szDllName)) == 0 )  
  16.     {  
  17.       break;  
  18.     }  
  19.     bRet = Module32Next(hSnap, &me32);  
  20.   }  
  21.   CloseHandle(hSnap);  
  22.   char *pFunName = "FreeLibrary" 
  23.   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwPid);  
  24.   if ( hProcess == NULL )  
  25.   {  
  26.     return ;  
  27.   }  
  28.   FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),pFunName);  
  29.   HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,  
  30.     (LPTHREAD_START_ROUTINE)pFunAddr,me32.hModule, 0, NULL);  
  31.   WaitForSingleObject(hThread, INFINITE);  
  32.   CloseHandle(hThread);  
  33.   CloseHandle(hProcess);  

卸載遠程進程中DLL的實現(xiàn)代碼比DLL注入的代碼要簡單,這里就不做過多的介紹了。

3. 無DLL的代碼注入

DLL文件的注入與卸載都完成了,整個注入與卸載的過程其實就是讓遠程線程執(zhí)行一次LoadLibrary()函數(shù)或FreeLibrary()函數(shù)。遠程線程裝載一個DLL文件,通過DllMain()調(diào)用DLL中的具體功能代碼,這樣注入DLL后就可以讓DLL做很多事情了。是否可以不依賴DLL文件直接向目標進程寫入要執(zhí)行的代碼,以完成特定的功能呢?答案是可以。

要在目標進程中完成一定的功能,就需要使用相關的API函數(shù),不同的API函數(shù)實現(xiàn)在不同的DLL中。Kernel32.dll文件在每個進程中的地址是相同的,但是并不代表其他DLL文件在每個進程中的地址都是一樣的。這樣,在目標進程中調(diào)用API函數(shù)時,必須使用LoadLibrary()函數(shù)和GetProcAddress()函數(shù)動態(tài)調(diào)用用到的每個API函數(shù)。把想要使用的API函數(shù)及API函數(shù)所在的DLL文件都封裝到一個結構體中,直接寫入目標進程的空間中。同時也直接把要在遠程執(zhí)行的代碼也寫入目標進程的內(nèi)存空間中,最后調(diào)用CreateRemoteThread()函數(shù)即可將其運行。

通過實現(xiàn)一個簡單的例子讓遠程線程彈出一個提示對話框,但是不借助于DLL。本程序所使用的API函數(shù)在前面都已經(jīng)介紹過了。根據(jù)前面的步驟先來定義一個結構體,其定義如下: 

  1. #define STRLEN 20  
  2. typedef struct _DATA  
  3.  
  4.  DWORD dwLoadLibrary;  
  5.  DWORD dwGetProcAddress;  
  6.  DWORD dwGetModuleHandle;  
  7.  DWORD dwGetModuleFileName;  
  8.  char User32Dll[STRLEN];  
  9.  char MessageBox[STRLEN];  
  10.  char Str[STRLEN];  
  11. }DATA, *PDATA; 

該結構體中保存了LoadLibraryA()、GetProcAddress()、GetModuleHandle()和GetModu leFileName()四個API函數(shù)的地址。這四個API函數(shù)都屬于Kernel32.dll的導出函數(shù),因此可以在注入前進行獲取。User32Dll中保存“User32.dll”字符串,因為MessageBoxA()函數(shù)是由User32.dll的導出函數(shù)。Str中保存的是通過MessageBoxA()函數(shù)彈出的字符串。

注入代碼類似于前面介紹的注入代碼,不過需要在注入代碼中定義一個結構體變量,并進行相應的初始化,代碼如下: 

  1. VOID CNoDllInjectDlg::InjectCode(DWORD dwPid)  
  2.  
  3.   // 打開進程并獲取進程句柄  
  4.   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwPid);  
  5.   if ( hProcess == NULL )  
  6.   {  
  7.     return ;  
  8.   }  
  9.   DATA Data = { 0 };  
  10.   // 獲取 kernel32.dll 中相關的導出函數(shù)  
  11.   Data.dwLoadLibrary = (DWORD)GetProcAddress(  
  12.     GetModuleHandle("kernel32.dll"),"LoadLibraryA");  
  13.   Data.dwGetProcAddress = (DWORD)GetProcAddress(  
  14.     GetModuleHandle("kernel32.dll"),"GetProcAddress");  
  15.   Data.dwGetModuleHandle = (DWORD)GetProcAddress(  
  16.     GetModuleHandle("kernel32.dll"),"GetModuleHandleA");  
  17.   Data.dwGetModuleFileName = (DWORD)GetProcAddress(  
  18.     GetModuleHandle("kernel32.dll"),"GetModuleFileNameA");  
  19.   // 需要的其他 DLL 和導出函數(shù)  
  20.   lstrcpy(Data.User32Dll, "user32.dll");  
  21.   lstrcpy(Data.MessageBox, "MessageBoxA");  
  22.   // MessageBoxA()彈出的字符串  
  23.   lstrcpy(Data.Str, "Inject Code !!!");  
  24.   // 在目標進程申請空間  
  25.   LPVOID lpData = VirtualAllocEx(hProcess, NULL, sizeof(Data),  
  26.     MEM_COMMIT | MEM_RELEASE,PAGE_READWRITE);  
  27.   DWORD dwWriteNum = 0 
  28.   WriteProcessMemory(hProcess, lpData, &Data,  
  29.     sizeof(Data), &dwWriteNum);  
  30.   // 在目標進程空間申請的用于保存代碼的長度  
  31.   DWORD dwFunSize = 0x4000 
  32.   LPVOID lpCode = VirtualAllocEx(hProcess, NULL, dwFunSize,  
  33.     MEM_COMMIT,PAGE_EXECUTE_READWRITE); 
  34.   WriteProcessMemory(hProcess, lpCode, &RemoteThreadProc,  
  35.     dwFunSize, &dwWriteNum); 
  36.   HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0 
  37.     (LPTHREAD_START_ROUTINE)lpCode,lpData, 0, NULL);  
  38.   WaitForSingleObject(hThread, INFINITE);  
  39.   CloseHandle(hThread);  
  40.   CloseHandle(hProcess);  

上面的注入代碼除了對結構體變量初始化外,還將線程函數(shù)代碼寫入目標進程空間的內(nèi)存中。線程函數(shù)的代碼如下: 

  1. DWORD WINAPI RemoteThreadProc(LPVOID lpParam)  
  2.  
  3.   PDATA pData = (PDATA)lpParam;  
  4.   // 定義 API 函數(shù)原型  
  5.   HMODULE (__stdcall *MyLoadLibrary)(LPCTSTR); 
  6.    FARPROC (__stdcall *MyGetProcAddress)(HMODULE, LPCSTR);  
  7.   HMODULE (__stdcall *MyGetModuleHandle)(LPCTSTR);  
  8.   int (__stdcall *MyMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT);  
  9.   DWORD (__stdcall *MyGetModuleFileName)(HMODULE, LPTSTR, DWORD);  
  10.   // 對各函數(shù)地址進行賦值  
  11.   MyLoadLibrary = (HMODULE (__stdcall *)(LPCTSTR))  
  12.     pData->dwLoadLibrary;  
  13.   MyGetProcAddress = (FARPROC (__stdcall *)(HMODULE, LPCSTR))  
  14.     pData->dwGetProcAddress;  
  15.   MyGetModuleHandle = (HMODULE (__stdcall *)(LPCSTR))  
  16.     pData->dwGetModuleHandle;  
  17.   MyGetModuleFileName = (DWORD (__stdcall *)(HMODULE, LPTSTR, DWORD))  
  18.     pData->dwGetModuleFileName;  
  19.   // 加載 User32.dll  
  20.   HMODULE hModule = MyLoadLibrary(pData->User32Dll);  
  21.   // 獲得 MessageBoxA 函數(shù)的地址  
  22.   MyMessageBox = (int (__stdcall *)(HWND, LPCTSTR, LPCTSTR, UINT))  
  23.     MyGetProcAddress(hModule, pData->MessageBox);  
  24.   char szModuleFileName[MAX_PATH] = { 0 };  
  25.   MyGetModuleFileName(NULL, szModuleFileName, MAX_PATH);  
  26.   MyMessageBox(NULL, pData->Str, szModuleFileName, MB_OK);  
  27.   return 0; 
  28. }

上面就是無DLL注入的全部代碼,編譯連接并運行它。啟動一個記事本程序來進行測試,可惜報錯了。問題出在哪里呢?VC6的默認編譯是Debug版本,這樣會加入很多調(diào)試信息。而某些調(diào)試信息并不存在于代碼中,而是在其他DLL模塊中。這樣,當執(zhí)行到調(diào)試相關的代碼時會訪問不存在的DLL模塊中的代碼,就導致了報錯。

將以上代碼使用Release方式進行編譯連接,然后可以無誤地執(zhí)行,如圖4所示。

圖4  Release方式下編譯注入成功

編譯的Debug版也可以進行無DLL的注入,只是實現(xiàn)起來略有不同。 

 

責任編輯:龐桂玉 來源: 計算機與網(wǎng)絡安全
相關推薦

2021-03-01 11:20:13

網(wǎng)絡安全多線程代碼

2021-03-03 12:20:42

網(wǎng)絡安全DLL編程

2021-01-26 13:45:03

網(wǎng)絡安全Winsock編程

2021-02-21 18:19:43

網(wǎng)絡安全網(wǎng)絡安全編程創(chuàng)建進程

2021-02-23 10:20:07

網(wǎng)絡安全進程代碼

2016-10-10 00:18:27

2021-06-18 09:55:09

網(wǎng)絡安全目錄監(jiān)控

2021-04-30 18:50:44

網(wǎng)絡安全PE編程添加節(jié)區(qū)

2021-04-26 10:32:38

網(wǎng)絡安全PE編程工具

2021-01-18 10:35:18

網(wǎng)絡安全Windows代碼

2021-06-15 11:16:24

網(wǎng)絡安全U盤軟件

2021-04-19 10:26:41

網(wǎng)絡安全PE文件

2021-02-04 10:50:11

網(wǎng)絡安全非阻塞模Winsock編程

2021-06-24 08:37:34

網(wǎng)絡安全內(nèi)核代碼

2021-05-12 14:57:13

網(wǎng)絡安全密碼代碼

2021-05-24 11:55:55

網(wǎng)絡安全Windows鉤子函數(shù)

2021-04-28 14:35:48

網(wǎng)絡安全PE編程代碼

2021-04-25 21:25:09

網(wǎng)絡安全網(wǎng)絡安全編程PE編程

2022-10-08 07:30:17

網(wǎng)絡安全編程語言C++

2021-06-11 13:40:17

網(wǎng)絡安全專殺工具病毒
點贊
收藏

51CTO技術棧公眾號