win32进程概念之句柄表,以及内核对象.

Posted ibinary

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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: extabc

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进程概念之句柄表,以及内核对象.的主要内容,如果未能解决你的问题,请参考以下文章

第三章--Win32程序的执行单元(部分概念及代码讲解)(中-线程同步

win32之进程概念

羽夏看Win系统内核——句柄表篇

零基础逆向工程39_Win32_13_进程创建_句柄表_挂起方式创建进程

Windows程序设计笔记1:第2章:win32程序运行原理

Windows API之DuplicateHandle