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


          句柄表跟內核對象

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

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獲取函數地址. 使用函數指針來使用這個函數.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM