歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

獲取其它進程密碼框中的密碼

程序編寫的過程中,往往有些功能需要由其它的進程權限才能夠完成這些工作,如得到其它進程中某個窗口的標題;建立隱藏的守護進程來監測本進程的運行情況;在Win7下,利用其它有高UAC權限的進程來完成一些功能等等。都需要使用到其它進程來完成這些工作。本文就來講解如何獲取其它進程中密碼框中的密碼。

以上代碼實現及理論均為Win32平台為主。

A. 為什麼選擇遠程線程 ?

我們知道,遠程線程就是想讓其它線程執行我們自己的代碼,如果要想使自己的代碼被其它進程執行,首先能想到的就是DLL,因為DLL可以被其它進程附加,並且可以執行所有的功能。但強大的功能也需要一個導火索來給它這個機會爆發,因為在進程運行進來後,LoadLibrary仍然可以使一個動態庫附加映射進某個進程,但當我們執行LoadLibrary時,是在自己進程中執行的,無法使其它進程有機會執行這個代碼,從而也就沒機會使我們的代碼附加到其它進程中,結果就是,強大的代碼永遠沒有得到一個可以執行的機會。

而遠程線程就是系統提供給我們的一個伯樂,它可以在你創建線程時,指定一個起始運行的入口,這樣LoadLibrary就有了執行的機會,從而,DLL裡面的代碼就是會一氣呵成的執行。

所以遠程線程是必須的。

B. 一些必須了解的概念

1.  地址空間

在Win32平台下(Linux及主流平台),每個進程擁有4GB獨立的地址空間,一般叫做線程地址空間,相對於每個進程來說,在自己的空間內訪問一些地址內容,即訪問變                量的值及執行一些代碼都是非常方便的有效的,每個進程完成自己的工作,相互不會產生任何干擾。

2.  遠程線程

一般而言,線程是線程可調試,實際完成一些工作(即執行一些代碼)的最小實體,一個進程可以包含一個及以上的線程,這些線程並行工作,完成實際的功能。而遠                程線程,故名思議,即非本進程的線程。假設有A,B兩個進程,遠程線程就是由A進程創建,但運行於B進程的地址空間中,擁有B進程的進程權限。

3.  代碼注入

代碼注入就是,將精心准備好的代碼(即數據)放進某個進程的地址空間中。

C.  為什麼不選擇DLL的方式 ?

前面已經提到過,DLL裡面就是可以執行的代碼,我們只需要將DLL附加進進程就得以機會去執行這些代碼。但DLL是以文件形式存放在磁盤中,有些功能可能會很                    小,或者有些功能需要隱藏一些實現細節,如果附加一個DLL的話,效果並不是那麼的友好,所以如果有機會不用DLL,依然能夠使遠程線程實現強大的功能,那自然                是最佳選擇,但這也使得代碼編寫起來更難,也就需要更強的編程的基本功。

D. 需要使用到的主要API(以Win32平台為例)

OpenProcess:打開一個進程,得到該進程的句柄。

VirtualAllocEx:簡言之為在指定的進程中申請一些空間。

WriteProcessMemory:簡言之為在指定進程中寫入一些數據。

CreateRemoteThread:在指定的進程中創建一個線程。

E.      具體實現 -- Talk is cheap, show me the code! (Linus)

以得到其它進程中某一窗體的標題為例,來簡單的介紹遠程線程的用法。

得到一個窗口的標題,一般會調用 GetWindowText,它的使用方法如下:

The GetWindowText function copies the text of the specified window's titlebar (if it has one) into a buffer. If the specified window is a control, thetext of the control is copied. However, GetWindowText cannot retrievethe text of a control in another application.

上面的使用方法是摘自MSDN上GetWindowText的描述,從描述中可以看到,GetWindowText不能夠得到其它應用程序的標題,即一個進程的程序不能獲得其它進程窗口的句柄。但如果那段代碼是由其它進程來執行,執行後我們再得到結果,是不是就可以做到了呢。

假設我們的進程為A,我們想得到B進程中某一個控制的標題,要想完成以上功能,首先我們要能讓我們的代碼放到B進程的地址空間中,其次讓B執行這些代碼,最後從B進程中得到執行的結果。

代碼實現如下(為突出有效代碼,合法性檢測都沒有添加):

#include <iostream>
#include <windows.h>

using namespace std;

void Test();

void main()
{
 Test();
}


__declspec(naked) void __stdcall GetWindowTextSpy(DWORD dwParam)
{
 _asm
 {
  mov  eax, [esp + 4]        // 得到傳入的參數 dwParam, 此時為窗口句柄
  push    [eax + 0]        // 緩沖區長度
  mov  ebx, eax
  add  ebx, 8
  push    ebx       // 緩沖區地址
  push  [eax + 4]     // 目標窗口句柄
  call GetWindowText
  ret  4
 }
}

__declspec(naked) void __stdcall EndLabel(DWORD dwParam)
{
}


void Test()
{

 // 得到目標窗口所在進程的ID,篇幅原因假設已經知道窗口句柄
 HWND hwnd  = (HWND)0x000108F8;
 DWORD dwProcessID;
 DWORD dwTitleSize = 0x20;
 DWORD dwDataLen = 0x30;

 GetWindowThreadProcessId(hwnd, &dwProcessID);

 HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
          PROCESS_VM_READ, FALSE, dwProcessID);
 // 在B 進程中申請空間以存放返回的窗口標題
 LPBYTE pData  = (LPBYTE)VirtualAllocEx(hProcess, 0, dwDataLen, MEM_COMMIT, PAGE_READWRITE);

 // 填充參數
 WriteProcessMemory(hProcess, pData, &dwTitleSize, 4, NULL);
 WriteProcessMemory(hProcess, pData + 4, &hwnd, 4, NULL);

 // 注入的代碼長度
 DWORD dwCodeLen = 0;

#ifdef _DEBUG
 const DWORD dwSpyRealAddr = *(LPDWORD)((LPBYTE)(&GetWindowTextSpy)+1) + (DWORD)(&GetWindowTextSpy) + 5;
 const DWORD dwEndReadAddr = *(LPDWORD)((LPBYTE)(&EndLabel)+1) + (DWORD)(&EndLabel) + 5;
#else
 const DWORD dwSpyRealAddr = (DWORD)GetWindowTextSpy;
 const DWORD dwEndReadAddr = (DWORD)EndLabel;
#endif

 dwCodeLen = dwEndReadAddr - dwSpyRealAddr;

 LPBYTE pCode = (LPBYTE)VirtualAllocEx(hProcess, 0, dwCodeLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 LPBYTE pCodeBuff = (LPBYTE)malloc(dwCodeLen);
 memcpy((LPVOID)pCodeBuff, (LPVOID)dwSpyRealAddr, dwCodeLen);

 // 調整代碼
 LPBYTE p = pCodeBuff;
 while(*p != 0xE8){p++;}

    *(DWORD*)(p+1) = (DWORD)&GetWindowText - (DWORD)(p - (LPBYTE)pCodeBuff + (LPBYTE)pCode) - 5;
 WriteProcessMemory( hProcess, pCode, pCodeBuff, dwCodeLen, NULL);

 HANDLE hRThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, 0);
 WaitForSingleObject(hRThread, INFINITE);

 char szTitle[100] = {0};
 DWORD dwReadBytes  = 0;
 ReadProcessMemory(hProcess, pData + 8, szTitle, dwTitleSize, &dwReadBytes);

 cout << szTitle << endl;

 CloseHandle(hRThread);
 free(pCodeBuff);
 VirtualFreeEx(hProcess, pCode, dwCodeLen, MEM_RELEASE);
 VirtualFreeEx(hProcess, pData, dwDataLen, MEM_RELEASE);   
 CloseHandle(hProcess);
}

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-06/103650p2.htm

Copyright © Linux教程網 All Rights Reserved