成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

網絡安全編程:遠程線程編程

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

[[385466]]

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

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

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

1. DLL遠程注入

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

創建遠程線程的函數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. ); 

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

  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.   /* 創建遠程線程  
  14.   return CreateRemoteThread(NtCurrentProcess(), 
  15.     lpThreadAttributes,  
  16.     dwStackSize,  
  17.     lpStartAddress, 
  18.     lpParameter,  
  19.     dwCreationFlags,  
  20.     lpThreadId);  

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

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

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

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

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

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

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

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

  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. ); 

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

參數說明如下。

hProcess:該參數是指定進程的進程句柄。

lpBaseAddress:該參數是指定寫入目標進程內存的起始地址。

lpBuffer:該參數是要寫入目標進程內存的緩沖區起始地址。

nSize:該參數是指定寫入目標內存中的緩沖區的長度。

lpNumberOfBytesWritten:該參數用于接收實際寫入內容的長度。

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

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

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

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

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

hProcess:該參數是指定進程的進程句柄。

lpAddress:該參數是指在目標進程中申請內存的起始地址。

dwSize:該參數是指在目標進程中申請內存的長度。

flAllocationType:該參數指定申請內存的狀態類型。

flProtect:該參數指定申請內存的屬性。

該函數的返回值是在目標進程申請到的內存塊的起始地址。

到此,關于編寫一個DLL注入的所有知識都已經具備了。現在開始編寫一個DLL注入的工具,其界面如圖1所示。

圖1  DLL注入/卸載器

該工具有2個作用,分別是注入DLL和卸載被注入的DLL。關于卸載被注入的DLL的功能,將在后面進行介紹。在界面上要求輸入兩部分內容,第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);  

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

  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()函數是將字符串轉化為大寫  
  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()函數的代碼如下: 

  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 大小的內存空間  
  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 文件的完整路徑寫入在目標進程中申請的空間內  
  25.   WriteProcessMemory(hProcess, pDllAddr, szDllName,nDllLen, &dwWriteNum);  
  26.   // 獲得 LoadLibraryA()函數的地址  
  27.   FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),pFunName);  
  28.   // 創建遠程線程  
  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()函數有 2 個參數,分別是目標進程的 ID 值和要被注入的 DLL 文件的完整路徑。在代碼中獲得的不是 LoadLibrary()函數的地址,而是 LoadLibraryA()函數的地址。在系統中其實沒有 LoadLibrary()函數,有的只是 LoadLibraryA()和 LoadLibraryW()兩個函數。這兩個函數分別針對 ANSI 字符串和 UNICODE 字符串。而 LoadLibrary()函數只是一個宏。在編寫程序的時候,直接使用該宏是可以的。如果要獲取 LoadLibrary()函數的地址,就要明確指定是獲取 LoadLibraryA()還是 LoadLibraryW()。

LoadLibrary()宏定義如下: 

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

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

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

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

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

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

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

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

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

2. 卸載被注入的DLL文件

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

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

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

該函數的參數是要卸載的模塊的句柄。

FreeLibrary()函數使用的模塊句柄可以通過Module32First()和Module32Next()兩個函數獲取。在使用Module32First()和Module32Next()兩個函數的時候,需要用到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的實現代碼比DLL注入的代碼要簡單,這里就不做過多的介紹了。

3. 無DLL的代碼注入

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

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

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

  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函數的地址。這四個API函數都屬于Kernel32.dll的導出函數,因此可以在注入前進行獲取。User32Dll中保存“User32.dll”字符串,因為MessageBoxA()函數是由User32.dll的導出函數。Str中保存的是通過MessageBoxA()函數彈出的字符串。

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

  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 中相關的導出函數  
  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 和導出函數  
  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);  

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

  1. DWORD WINAPI RemoteThreadProc(LPVOID lpParam)  
  2.  
  3.   PDATA pData = (PDATA)lpParam;  
  4.   // 定義 API 函數原型  
  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.   // 對各函數地址進行賦值  
  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 函數的地址  
  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版本,這樣會加入很多調試信息。而某些調試信息并不存在于代碼中,而是在其他DLL模塊中。這樣,當執行到調試相關的代碼時會訪問不存在的DLL模塊中的代碼,就導致了報錯。

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

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

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

 

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

2021-03-03 12:20:42

網絡安全DLL編程

2021-03-01 11:20:13

網絡安全多線程代碼

2021-01-26 13:45:03

網絡安全Winsock編程

2021-02-21 18:19:43

網絡安全網絡安全編程創建進程

2021-02-23 10:20:07

網絡安全進程代碼

2016-10-10 00:18:27

2021-06-18 09:55:09

網絡安全目錄監控

2021-04-30 18:50:44

網絡安全PE編程添加節區

2021-04-26 10:32:38

網絡安全PE編程工具

2021-01-18 10:35:18

網絡安全Windows代碼

2021-02-04 10:50:11

網絡安全非阻塞模Winsock編程

2021-05-12 14:57:13

網絡安全密碼代碼

2021-04-19 10:26:41

網絡安全PE文件

2021-06-15 11:16:24

網絡安全U盤軟件

2021-06-24 08:37:34

網絡安全內核代碼

2021-05-24 11:55:55

網絡安全Windows鉤子函數

2021-04-25 21:25:09

網絡安全網絡安全編程PE編程

2021-04-28 14:35:48

網絡安全PE編程代碼

2021-03-01 11:38:15

網絡安全進程代碼

2021-05-06 16:35:12

網絡安全網絡安全編程文件補丁
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩视频精品在线 | 国产精品久久久久久久久久妞妞 | 男女下面一进一出网站 | 丝袜美腿av | 97视频免费 | 亚洲欧洲色视频 | 毛片一区二区三区 | 熟女毛片| 在线亚州 | 国产精品欧美一区二区 | 玖玖爱365 | 国产精品日日摸夜夜添夜夜av | 国产日韩在线观看一区 | 亚洲一一在线 | 天天操天天舔 | 国内精品99| 成人午夜电影在线观看 | 国产精品亚洲一区 | 国产精品久久久久久一区二区三区 | 欧美成年人网站 | 日韩av手机在线观看 | 欧美激情网站 | 中文字幕精品一区久久久久 | 精品久久国产 | 九色 在线 | 五月婷婷视频 | 午夜伦4480yy私人影院 | 亚洲免费一区 | 日韩精品无码一区二区三区 | 美女爽到呻吟久久久久 | 18av在线播放 | 久草电影网 | www.9191 | 九色网址 | 国产在线小视频 | 亚洲精品久久久久久久久久久 | 精品在线一区二区三区 | 成人精品一区二区三区中文字幕 | 欧美日韩亚洲一区 | 日韩在线视频免费观看 | 色综合网站 |