zoukankan      html  css  js  c++  java
  • 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获取函数地址. 使用函数指针来使用这个函数.

  • 相关阅读:
    监视用户是保存用户编辑还是放弃参照编辑
    AutoCAD: 添加鼠标快捷键/鼠标右键
    C# List<T>集合布尔运算
    List<T>的用法详解
    天正的坑
    C#札记
    AUTOCAD2013 以上利用ACCORECONSOLE+ SCR后台批量清理图纸
    BaiduSitemap
    三一邮件群发
    Windows+IIS+Mysql+php安装
  • 原文地址:https://www.cnblogs.com/iBinary/p/9571964.html
Copyright © 2011-2022 走看看