獲取系統中全部進程&線程信息

 

讀書筆記--[計算機病毒解密與對抗]

目錄:

  1. 遍歷進程&線程程序
  2. 終止進程
  3. 獲取進程信息
  4. 獲取進程內模塊信息
  5. 獲取進程命令行參數

 

代碼運行環境:Win7 x64css

    VS2012 Update3windows


遍歷系統中全部進程api

 

  1. #include <stdio.h>  
  2. #include <windows.h>  
  3. #include <TlHelp32.h>  
  4.   
  5. int main()  
  6. {  
  7.     // 爲進程的全部線程拍個快照  
  8.     HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  
  9.     if( hSnapshort==INVALID_HANDLE_VALUE )  
  10.     {  
  11.         printf("CreateToolhelp32Snapshot調用失敗!\n");  
  12.         return -1;  
  13.     }  
  14.   
  15.     // 得到線程列表,裏面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每一個線程信息  
  16.     PROCESSENTRY32 stcProcessInfo;  
  17.     stcProcessInfo.dwSize = sizeof(stcProcessInfo);  
  18.   
  19.     BOOL  bRet = Process32First(hSnapshort, &stcProcessInfo);  
  20.   
  21.     printf("進程名\t\t\t 進程ID\t 線程數\t 父進程ID\n");  
  22.   
  23.     while (bRet)  
  24.     {  
  25.         printf("%ls\t\t %d\t %d\t %d\n", stcProcessInfo.szExeFile, stcProcessInfo.th32ProcessID, stcProcessInfo.cntThreads, stcProcessInfo.th32ParentProcessID);  
  26.   
  27.         bRet = Process32Next(hSnapshort, &stcProcessInfo);  
  28.     }  
  29.   
  30.     CloseHandle(hSnapshort);  
  31.   
  32.     system("pause");  
  33.     return 0;  
  34. }  
#include <stdio.h>
#include <windows.h>
#include <TlHelp32.h>

int main()
{
    // 爲進程的全部線程拍個快照
    HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if( hSnapshort==INVALID_HANDLE_VALUE )
    {
        printf("CreateToolhelp32Snapshot調用失敗!\n");
        return -1;
    }

    // 得到線程列表,裏面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每一個線程信息
    PROCESSENTRY32 stcProcessInfo;
    stcProcessInfo.dwSize = sizeof(stcProcessInfo);

    BOOL  bRet = Process32First(hSnapshort, &stcProcessInfo);

    printf("進程名\t\t\t 進程ID\t 線程數\t 父進程ID\n");

    while (bRet)
    {
        printf("%ls\t\t %d\t %d\t %d\n", stcProcessInfo.szExeFile, stcProcessInfo.th32ProcessID, stcProcessInfo.cntThreads, stcProcessInfo.th32ParentProcessID);

        bRet = Process32Next(hSnapshort, &stcProcessInfo);
    }

    CloseHandle(hSnapshort);

    system("pause");
    return 0;
}

 


遍歷系統中全部線程架構

 

  1. #include <stdio.h>  
  2. #include <windows.h>  
  3. #include <TlHelp32.h>  
  4.   
  5. int main()  
  6. {  
  7.     // 爲進程的全部線程拍個快照  
  8.     HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);  
  9.     if( hSnapshort==INVALID_HANDLE_VALUE )  
  10.     {  
  11.         printf("CreateToolhelp32Snapshot調用失敗!\n");  
  12.         return -1;  
  13.     }  
  14.   
  15.     // 得到線程列表,裏面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每一個線程信息  
  16.     THREADENTRY32 stcThreadInfo;  
  17.     stcThreadInfo.dwSize = sizeof(stcThreadInfo);  
  18.   
  19.     BOOL  bRet = Thread32First(hSnapshort, &stcThreadInfo);  
  20.     DWORD dwProId = -1;  // 保存上一個線程的進程ID   
  21.     unsigned unCount=0;  
  22.   
  23.     while (bRet)  
  24.     {  
  25.         if( dwProId!=stcThreadInfo.th32OwnerProcessID )  
  26.         {  
  27.   
  28.             // 記錄PID與所屬PID不一樣,遍歷至不屬於同一進程的線程  
  29.             if( dwProId!=-1 )  
  30.             {  
  31.                 // 不是第一次遍歷  
  32.                 printf("\n進程%d的線程總數:%d\n", dwProId, unCount);  
  33.                 unCount = 0;  
  34.                 printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n");  
  35.             }     
  36.   
  37.             dwProId = stcThreadInfo.th32OwnerProcessID;  
  38.             printf("進程%d:\n\n ", dwProId);  
  39.             printf("線程TID\t\t線程所屬進程PID\t\t線程優先級\n");  
  40.         }  
  41.   
  42.         printf("  %d\t\t\t%d\t\t\t %d\n",stcThreadInfo.th32ThreadID, stcThreadInfo.th32OwnerProcessID, stcThreadInfo.tpBasePri);  
  43.         unCount++;  
  44.   
  45.         bRet = Thread32Next(hSnapshort, &stcThreadInfo);  
  46.     }  
  47.   
  48.     printf("\n進程%d的線程總數:%d\n", dwProId, unCount);  
  49.     unCount = 0;  
  50.     printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n");  
  51.   
  52.     CloseHandle(hSnapshort);  
  53.   
  54.     system("pause");  
  55.     return 0;  
  56. }  
#include <stdio.h>
#include <windows.h>
#include <TlHelp32.h>

int main()
{
    // 爲進程的全部線程拍個快照
    HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if( hSnapshort==INVALID_HANDLE_VALUE )
    {
        printf("CreateToolhelp32Snapshot調用失敗!\n");
        return -1;
    }

    // 得到線程列表,裏面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每一個線程信息
    THREADENTRY32 stcThreadInfo;
    stcThreadInfo.dwSize = sizeof(stcThreadInfo);

    BOOL  bRet = Thread32First(hSnapshort, &stcThreadInfo);
    DWORD dwProId = -1;  // 保存上一個線程的進程ID 
    unsigned unCount=0;

    while (bRet)
    {
        if( dwProId!=stcThreadInfo.th32OwnerProcessID )
        {

            // 記錄PID與所屬PID不一樣,遍歷至不屬於同一進程的線程
            if( dwProId!=-1 )
            {
                // 不是第一次遍歷
                printf("\n進程%d的線程總數:%d\n", dwProId, unCount);
                unCount = 0;
                printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n");
            }   

            dwProId = stcThreadInfo.th32OwnerProcessID;
            printf("進程%d:\n\n ", dwProId);
            printf("線程TID\t\t線程所屬進程PID\t\t線程優先級\n");
        }

        printf("  %d\t\t\t%d\t\t\t %d\n",stcThreadInfo.th32ThreadID, stcThreadInfo.th32OwnerProcessID, stcThreadInfo.tpBasePri);
        unCount++;

        bRet = Thread32Next(hSnapshort, &stcThreadInfo);
    }

    printf("\n進程%d的線程總數:%d\n", dwProId, unCount);
    unCount = 0;
    printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n");

    CloseHandle(hSnapshort);

    system("pause");
    return 0;
}

在win程序設計中除了使用ToolHelp函數能夠完成進程的遍歷操做以外(程序須要包含tlhelp32.h),還可使用Psapi函數EnumProcess函數,可是它只能獲取進程的ID。

 


進程相關操做--終止進程

  1. void  WINAPI  ExitProcess(  
  2.     UINT  uExitCode;  // 進程退出碼  
  3. );  
void  WINAPI  ExitProcess(
    UINT  uExitCode;  // 進程退出碼
);
在程序的任意一個地方調用這個函數都會當即終止自身進程的運行。在C/C++中應避免直接調用這個函數,由於C/C++運行期庫得不到通知,∴沒有機會去調用全局或靜態C/C++對象的析構函數。

ExitProcess不能終止其餘進程,應使用TerminateProcess函數。
  1. BOOL WINAPI TerminateProcess(  
  2.     HANDLE hProcess,  // 要結束的進程句柄  
  3.     UINT uExitCode    // 指定目標進程的退出碼  
  4. );  
BOOL WINAPI TerminateProcess(
    HANDLE hProcess,  // 要結束的進程句柄
    UINT uExitCode    // 指定目標進程的退出碼
);

咱們必須經過獲取目標進程的ID,而後再獲取這個進程句柄,而後纔可使用這個句柄操做此進程。可使用以下函數:
  1. HANDLE WINAPI OpenProcess(  
  2.     DWORD dwDesiredAccess,  // 指定獲得的句柄具備的訪問權限  
  3.     BOOL  bInheritHandle,   // 指定返回的句柄是否可被繼承  
  4.     DWORD dwProcessId       // 指定要打開的進程ID  
  5. );  
HANDLE WINAPI OpenProcess(
    DWORD dwDesiredAccess,  // 指定獲得的句柄具備的訪問權限
    BOOL  bInheritHandle,   // 指定返回的句柄是否可被繼承
    DWORD dwProcessId       // 指定要打開的進程ID
);
這個函數打開一個存在的進程,返回具備指定權限的句柄。


獲取進程的其餘信息

  • 獲取進程對應的可執行程序路徑
  1. DWORD  WINAPI  GetProcessImageFileNameA (  
  2.     _In_ HANDLE hProcess,                       // 要得到文件路徑的進程句柄  
  3.     _Out_writes_(nSize) LPSTR lpImageFileName,  // 保存文件路徑的內存首地址  
  4.     _In_ DWORD nSize<span style="white-space:pre">              </span>// 保存文件路徑的內存大小  
  5.     );  
DWORD  WINAPI  GetProcessImageFileNameA (
    _In_ HANDLE hProcess,                       // 要得到文件路徑的進程句柄
    _Out_writes_(nSize) LPSTR lpImageFileName,  // 保存文件路徑的內存首地址
    _In_ DWORD nSize// 保存文件路徑的內存大小
    );
注意使用上述函數獲取的路徑並非磁盤驅動器的路徑,而是內核路徑,形如: " \Device\HarddiskVolume1\WINDOWS\System32\notepad.exe ",一般此路徑中的Device表示硬盤驅動器,HarddiskVolume表示分區數字表示具體分區號(1表C 2表D。。。),因此對路徑須要進行轉換。
  1. #include <stdio.h>  
  2. #include <windows.h>  
  3. #include <tchar.h>  
  4. #include <TlHelp32.h>  
  5. #include <Psapi.h>  
  6.   
  7. #pragma comment(lib, "psapi.lib")  
  8.   
  9. void TransPath(PTCHAR pPath)  
  10. {  
  11.     // 獲取驅動器字符串位置  
  12.     PTCHAR pFind = _tcsstr(pPath, _T("HarddiskVolume"));  
  13.     if( pFind==NULL )  
  14.         return;  
  15.   
  16.     TCHAR tcDriver[5] = {'C''D''E''F''G'};  // 可寫滿24個字符,這裏只是一個demo  
  17.   
  18.     int nNum = pFind[_tcslen(_T("HarddiskVolume"))] - 0x30;  
  19.   
  20.     PTCHAR pTemp = _tcsstr(pFind, _T("\\"));  
  21.   
  22.     // 拼接字符串的緩衝區  
  23.     TCHAR tcBuffer[MAX_PATH];  
  24.     memset(tcBuffer, 0, MAX_PATH*sizeof(TCHAR));  
  25.   
  26.     _stprintf_s(tcBuffer, _T("%c:%s"), tcDriver[nNum-1], pTemp);  
  27.     memset(pPath, 0, _tcslen(pPath));  
  28.     _tcscpy_s(pPath, 256, tcBuffer);  
  29. }  
  30.   
  31. int main()  
  32. {  
  33.     // 傳入\Device\HarddiskVolume1\WINDOWS\System32\notepad.exe   
  34.     DWORD dwNeed;  
  35.     PDWORD pdwMem = new DWORD[4000];  
  36.     BOOL bRet = EnumProcesses(pdwMem, 4000, &dwNeed);  
  37.   
  38.     if( !bRet )  
  39.     {  
  40.         if(pdwMem!=NULL)  
  41.         {  
  42.             delete[] pdwMem;  
  43.             pdwMem = nullptr;  
  44.             return -1;  
  45.         }  
  46.     }  
  47.   
  48.     int nNumProc = dwNeed/4;  
  49.     HANDLE hProcess = NULL;  
  50.     DWORD dwPathLength = 0;  
  51.     TCHAR tcBuffer[256] = {0};  
  52.   
  53.     forint i=0; i<nNumProc; i++ )  
  54.     {  
  55.         hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pdwMem[i]);  
  56.   
  57.         if( hProcess==NULL )  
  58.             continue;  
  59.   
  60.         memset(tcBuffer, 0, 256*sizeof(TCHAR));  
  61.         dwPathLength = GetProcessImageFileName(hProcess, tcBuffer, 256);  
  62.   
  63.         if( dwPathLength!=0 )  
  64.         {  
  65.             TransPath(tcBuffer);  
  66.             printf("%08d %ls\n",pdwMem[i], tcBuffer);  
  67.         }  
  68.   
  69.         CloseHandle(hProcess);  
  70.     }  
  71.   
  72.     if( pdwMem!=NULL )  
  73.     {  
  74.         delete[] pdwMem;  
  75.         pdwMem = NULL;  
  76.     }  
  77.   
  78.     system("pause");  
  79.     return 0;  
  80. }  
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <TlHelp32.h>
#include <Psapi.h>

#pragma comment(lib, "psapi.lib")

void TransPath(PTCHAR pPath)
{
    // 獲取驅動器字符串位置
    PTCHAR pFind = _tcsstr(pPath, _T("HarddiskVolume"));
    if( pFind==NULL )
        return;

    TCHAR tcDriver[5] = {'C', 'D', 'E', 'F', 'G'};  // 可寫滿24個字符,這裏只是一個demo

    int nNum = pFind[_tcslen(_T("HarddiskVolume"))] - 0x30;

    PTCHAR pTemp = _tcsstr(pFind, _T("\\"));

    // 拼接字符串的緩衝區
    TCHAR tcBuffer[MAX_PATH];
    memset(tcBuffer, 0, MAX_PATH*sizeof(TCHAR));

    _stprintf_s(tcBuffer, _T("%c:%s"), tcDriver[nNum-1], pTemp);
    memset(pPath, 0, _tcslen(pPath));
    _tcscpy_s(pPath, 256, tcBuffer);
}

int main()
{
    // 傳入\Device\HarddiskVolume1\WINDOWS\System32\notepad.exe 
    DWORD dwNeed;
    PDWORD pdwMem = new DWORD[4000];
    BOOL bRet = EnumProcesses(pdwMem, 4000, &dwNeed);

    if( !bRet )
    {
        if(pdwMem!=NULL)
        {
            delete[] pdwMem;
            pdwMem = nullptr;
            return -1;
        }
    }

    int nNumProc = dwNeed/4;
    HANDLE hProcess = NULL;
    DWORD dwPathLength = 0;
    TCHAR tcBuffer[256] = {0};

    for( int i=0; i<nNumProc; i++ )
    {
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pdwMem[i]);

        if( hProcess==NULL )
            continue;

        memset(tcBuffer, 0, 256*sizeof(TCHAR));
        dwPathLength = GetProcessImageFileName(hProcess, tcBuffer, 256);

        if( dwPathLength!=0 )
        {
            TransPath(tcBuffer);
            printf("%08d %ls\n",pdwMem[i], tcBuffer);
        }

        CloseHandle(hProcess);
    }

    if( pdwMem!=NULL )
    {
        delete[] pdwMem;
        pdwMem = NULL;
    }

    system("pause");
    return 0;
}

  • 獲取進程內模塊信息
一個可執行程序要執行就必須運行起來造成一個進程,即把自身加載到內存,咱們把這段內存稱爲該進程的主模塊。but並非程序的全部功能都位於主模塊中,也有部分功能位於動態連接庫中,程序運行後也會把輔助功能的DLL加載到內存造成其餘的模塊。摒棄一個進程中能夠存在多個模塊用於輔助主模塊完成各類任務。有些病毒把自身代碼以模塊形式加載到正常進程中去而後偷偷執行。

使用ToolHelp系列函數獲取進程模塊和遍歷進程模塊
首先給某個進程的模塊拍個快照,這樣便可獲得這個進程的模塊列表,裏面記錄了每一個模塊的詳細信息。而後使用 Module32FirstModule32Next便可遍歷快照列表中記錄的模塊信息。

使用Psapi函數操做
使用EnumProcessModules函數。這個函數只能獲得每一個模塊的句柄,不能獲得模塊的名稱和路徑,因此須要使用GetModuleFileNameEx函數經過模塊句柄去得到模塊的路徑。在枚舉進程中的模塊時,第一個模塊是進程的主模塊,用主模塊句柄獲得的模塊路徑就是進程文件的路徑。

  • 獲取進程命令行參數
命令行參數即進程啓動時傳遞給它的參數,經過這個參數可知道金城個啓動狀況。例如系統服務中,凡是服務對應模塊是DLL文件狀況,都須要svchost.exe去加載啓動,這樣系統中就有不少svchost進程,每一個svchost進程對應一類服務,這時就是經過命令行參數來區分他們。獲取本進程命令行參數API:
  1.   
 
  
  1. // 返回命令行參數字符串的首地址  
  2. LPTSTR  GetCommandLine(VOID);  
// 返回命令行參數字符串的首地址
LPTSTR  GetCommandLine(VOID);

獲取指定進程的命令行參數,可使用OD隨意調試一個Win程序,如notepad.exe。在command窗口輸入follow GetCommandLineA命令便可定位到該函數的實現代碼。能夠看到實現代碼僅一行
  1. mov  ax, dword ptr [7C8835F4]  
  2. // 我的作測試的時候地址好像是7C8855F4  
mov  ax, dword ptr [7C8835F4]
// 我的作測試的時候地址好像是7C8855F4
也就是說進程的命令行參數被保存在內存中的固定位置,只要定位到GetCommandLineA的入口地址,跳過一個字節後取出一個dword值,這個值是一個指針,指向的內容即命令行參數的地址。如今的問題即獲得遠程進程中GetCommandLineA函數的入口地址便可獲得該進程的命令行參數。獲取指定模塊中某個Win32API函數地址的函數是GetProcAddress。but這個函數僅可獲取當前進程中API函數的地址,要得到遠程進程中某個函數的地址就必須在遠程進程中執行這個函數,須要使用遠線程方法,本文暫時不涉及這個內容。 換個思路:GetCommandLineA使用Kernel32.dll提供,這個庫是系統基本庫,幾乎全部程序都會加載這個模塊。並且對於NT架構全部進程加載Kernel32.dll的模塊基址基本都是一致的,而GetCommandLineA在其庫中的地址也是固定的。因此咱們在本進程中獲得的此函數地址和遠程進程中該函數的地址是一致的(這個方法在個人電腦Win7x64中實驗失敗,應該由於程序的加載基址不固定了)。 獲取遠程進程中數據使用ReadProcessMemory函數。
  1. BOOL  WINAPI  ReadProcessMemory(  
  2.     _In_ HANDLE hProcess, <span style="white-space:pre">                    </span>         // 遠程進程句柄  
  3.     _In_ LPCVOID lpBaseAddress,<span style="white-space:pre">                       </span> // 目標進程內存空間首地址  
  4.     _Out_writes_bytes_to_(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer,  // 本進程內存空間首地址,存儲讀出的數據  
  5.     _In_ SIZE_T nSize,<span style="white-space:pre">                            </span> // 要讀取的字節數  
  6.     _Out_opt_ SIZE_T * lpNumberOfBytesRead<span style="white-space:pre">                </span> // 實際讀取的字節數  
  7.     );  
BOOL  WINAPI  ReadProcessMemory(
    _In_ HANDLE hProcess,          // 遠程進程句柄
    _In_ LPCVOID lpBaseAddress, // 目標進程內存空間首地址
    _Out_writes_bytes_to_(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer,  // 本進程內存空間首地址,存儲讀出的數據
    _In_ SIZE_T nSize, // 要讀取的字節數
    _Out_opt_ SIZE_T * lpNumberOfBytesRead // 實際讀取的字節數
    );
爲保證此方法成功,應判斷當前系統是不是NT系統,使用GetVersion函數獲取當前系統的版本。返回值表示系統的版本信息,如果NT/2k/xp則返回值小於0x80000000,不然大於該值。虛擬機中XP實驗成功。
jpg改rar 
相關文章
相關標籤/搜索