1. 程式人生 > >win32進程概念之句柄表,以及內核對象.

win32進程概念之句柄表,以及內核對象.

truct 打開 導出 進程信息 input 互斥體 map bool create

          句柄表跟內核對象

一丶什麽是句柄表什麽是內核對象.

1.句柄表的生成

我們知道.我們使用CreateProcess 的時候會返回一個進程句柄.以及線程句柄. 其實在調用CreateProcess的時候.內核中會新建一個EPROCESS結構來存儲我們的進程信息.

例如如下圖:

  技術分享圖片

但是有一個問題.怎麽給三環使用.難道直接返回EPROCESS?

其實不是這樣的. 第一EPROCESS在高兩G. 三環程序是不可以訪問的.所以返回的地址是高兩G所以不能使用. 但是為了解決這一問題.

windows創建了一個表格. 返回這個表格的索引. 而我們使用的就是這個索引.

2.什麽是內核對象.

內核對象就是我們上面所說的EPROCESS. 有很多內核對象.具體可以看下CloseHandle. 這個API表示他可以關閉什麽內核對象.

  • Access token
  • Communications device
  • Console input
  • Console screen buffer
  • Event
  • File
  • File mapping
  • I/O completion port
  • Job
  • Mailslot
  • Memory resource notification
  • Mutex
  • Named pipe
  • Pipe
  • Process
  • Semaphore
  • Thread
  • Transaction
  • Waitable timer

可以操作事件 文件 互斥體 線程. 等等....

二丶多進程共用內核對象

1.第一種方法. 使用OpenProcess

在windows程序中.我們操作的都是內核對象. 我們可以通過OpenProcess API來打開一個已有進程的內核對象.

如下圖:

  技術分享圖片

每個進程裏面的句柄表都是私有的. 例如第一張表. 句柄索引位1. 對應內核對象為A. 那麽將索引傳給B進程是沒用用的.

B進程只有使用API打開之後才能獲得 A內核對象.

其中中間的紫色表代表引用計數. 也就是說這個內核對象引用一次 這個值則會+1

而CloseHandle作用就是 使內核對象的引用計數-1 如果都關閉了.那麽此時內核對象沒有人使用. 也沒有執向了.所以就會銷毀這個內核對象了.也就是說.當內核對象的引用計數位為0了.那麽此時的內核對象

才是真正的銷毀.

而線程是特例: 當線程的內核對象引用計數為0的時候也不會關閉. 此時必須先關閉線程.在使用CloseHandle 是引用計數 -1才可以.

2.使用繼承句柄技術

在windows程序中. A創建 B .或者帶有內核對象的 API在創建的時候. 都有一個SD屬性.也就是安全屬性.這個屬性可以表示你創建的這個句柄是否可以繼承.

例如:

  CreateEvent()創建事件. 先不用管API的作用.我們看下API的參數吧.

HANDLE CreateEventA(
  LPSECURITY_ATTRIBUTES lpEventAttributes,     安全屬性結構體 主要介紹他
  BOOL                  bManualReset,
  BOOL                  bInitialState,
  LPCSTR                lpName
);

第一個就是安全屬性結構體.如果我們不指定.默認就是父進程的.

安全屬性結構體.

typedef struct _SECURITY_ATTRIBUTES {
  DWORD  nLength;                                         當前結構體大小.windows擴展使用的
  LPVOID lpSecurityDescriptor;                        表明這個句柄給誰用誰可以訪問.誰可以關閉.不重要 具體可以看下API中的結構體的定義.不重要不列出來了.
  BOOL   bInheritHandle;                                重要.表明句柄是否可以被繼承.
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

如下圖所示:

技術分享圖片

如果我們的句柄可以被繼承. 那麽句柄表的第一項就填1.表示這個句柄可以被繼承.如果不能繼承.則為0

此時我們的子進程就可以繼承父進程的 所有可繼承的句柄表了. 註意.是所有可繼承. 可以是共享的了. 如下圖所示.

技術分享圖片

A進程創建的 B D是可以繼承的. 所以 子進程可以完全復制A進程 可繼承句柄表. 不允許繼承的為0 都賦值為0

二丶進程PID解析

在windows任務管理器中.有PID選項.我們可以選中查看. 而且在windows中也常常聽到進程ID的概念.

那麽進程ID到底是個什麽東西.

其實進程ID是全局的句柄表的一個索引. 上面所講的句柄表.都是自己私有的句柄表. PID是全局句柄表裏面的.

這個句柄表裏面記錄了所有的正在運行進程的句柄.而且是唯一的. 如果進程死亡那麽這個pid可能會執向別的句柄. 但也是唯一的.如下圖所示.

技術分享圖片

而這個全局句柄表才是真正有意義的.為什麽這樣說.

我們可以做個測試.

1.使用OpenProcess打開進程句柄.

2.使用TerminlateProcess結束進程.

OpenProcess(訪問權限,句柄是否可以繼承,進程PID)

TerminlateProcess(進程句柄,自定義的退出碼) 結束進程.

使用上面的兩個API可以測試一下我們已有的進程是否可以被關閉. 如果測試過後你會發現.

只有PID獲得句柄才是有用了.也就是說全局句柄表. 而上面所講的都是子進程的句柄表.

三丶常用進程操作API

1. GetModuleFileName() 獲取當前模塊路徑 例如: c:\\1.exe

2.GetCurretDirectory() 獲取當前的工作目錄 例如: c:\text\abc

3.OpenProcess() 根據進程PID打開進程.獲取進程句柄.

4.FindWindow() 根據類名以及文件名.返回窗口句柄.

5.GetWindowsThreadProcessId() 根據窗口句柄.獲取進程PID

6.EnumProcesses 遍歷所有進程.返回進程PID 具體參考MSDN 有提供的例子.

7.GetCommandLine() 獲取命令行參數

8.CreateToolHelp32Snapshot() 創建進程快照. 如果懂逆向的就知道.FS寄存器中的TEB PEB結構中有存儲當前模塊的或者進程的鏈表.這個是保存當前這一時刻的快照.

我們可以進行遍歷. 具體參考MSDN或者本博客.

四丶編寫windows程序遇到的問題.

我們在編寫windows程序的時候.會包含windows.h 但是有的函數可能就沒有. 比如上面我們說的第八個函數. 快照函數.

此時我們要查詢MSDN. 我們可以搜索一下網頁的.

技術分享圖片

我們可以在下邊看到所需要的頭文件 是 tlhelp32.h 此時我們包含一下即可.

遇到的問題2.

有的時候我們頭文件也包含了也去使用了.但是調用API的時候出錯了.為什麽?

原因是 有的API在高版本中才有.低版本中使用的時候是沒有導出的.此時使用就會出錯.提示沒有這個API.

解決方法: 如果學過win32的 說的這個方法你們就理解了.如果沒學過也沒關系.一般這個問題很少遇見. 博主也才預見過一次.

可以使用 loadlibary加載所需要的dll. 然後使用 GetProcAddress獲取函數地址. 使用函數指針來使用這個函數.

win32進程概念之句柄表,以及內核對象.