枚举系统中打开的句柄

删除系统中的文件会提示 有进程已经打开了这个文件会导致不能删除该文件

在网上找到了在ring3下实现文件碎甲的一篇介绍:在ring3上实现文件碎甲功能

其中首先需要实现的就是需要枚举出系统中每个进程打开的文件句柄

枚举进程 枚举句柄 这些功能都需要用到从Ntdll.dll中导出系统内核函数

比如函数 ZwQuerySystemInformation ZwQueryInformationProcess等

其中有些函数是M$未公开函数 但是大多都可以从网上查到文档

首先从NtDll.dll中导出函数ZwQuerySystemInformation和函数RtlAdjustPrivilege

ZwQuerySystemInformation原型如下:

typedef   NTSTATUS   (__stdcall   *ZwQuerySystemInformation1)(
IN   ULONG   SysInfoClass,
IN   OUT   PVOID   SystemInformation,
IN   ULONG   SystemInformationLength,
OUT   PULONG   RetLen
);

RtlAdjustPrivilege函数原型如下:

typedef NTSTATUS (__stdcall *RtlAdjustPrivilege1)
                               (DWORD,BOOL,DWORD,PBOOLEAN);

导出函数:

ZwQueryObject1 ZwQueryObject;
ZwQueryObject = (ZwQueryObject1)
GetProcAddress(hNtDll,"ZwQueryObject");

RtlAdjustPrivilege函数也是类似

RtlAdjustPrivilege函数用于提高当前进程的权限

RtlAdjustPrivilege(20, TRUE, FALSE, NULL);

20表示赋予当前进程Debug权限 在打开其他进程和复制句柄时会用到

ZwQuerySystemInformation可以用于获得很多系统信息 第一个参数用于标示需要获得何种信息

这里使用5作为第一个参数标示获取当前系统中所有进程的信息

获得的信息是第二个参数 是一块内存块 需要将其转换为结构体SYSTEM_PROCESS

typedef struct _SYSTEM_PROCESSES {
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved1[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters;
SYSTEM_THREADS Threads[1];
} SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

如果给定的内存块不足以存下所有进程信息则函数返回0xC0000004L

被获取的进程信息以链表的形式存放在给出的内存块中

并且每个进程由一个SYSTEM_PROCESS结构体表示

在SYSTEM_PROCESS中 NextEntryDelta表示从第一个进程信息结构到下一个结构的偏移

若其为0则表示为最后一个进程

由此我们得到了系统中所有进程的信息

现在就可以遍历每个进程中的句柄了

由于在遍历时需要打开进程句柄 所以需要跳过当前进程本身

由于已经得到了进程id所以可以使用ring3下的函数OpenProcess来打开进程句柄

HANDLE hProcess = OpenProcess(PROCESS_SUSPEND_RESUME |
                            PROCESS_QUERY_INFORMATION |
                            PROCESS_DUP_HANDLE, FALSE, Pid);

在打开的时候标示了需要用到的一些权限 如复制句柄等

在打开进程后 需要用函数ZwSuspendProcess将其暂时挂起

但是对于系统进程System(PID:4)不能将其挂起

然后通过函数ZwQueryInformationProcess获得该进程所拥有的句柄信息

ZwQueryInformationProcess函数原型如下:

typedef NTSTATUS (__stdcall *ZwQueryInformationProcess1)(
                               HANDLE, PROCESSINFOCLASS,
                               LPVOID, DWORD, PDWORD);

其中PROCESSINFOCLASS是一个枚举类型

这里需要用到的值是ProcessHandleCount(20)用于获取进程所打开的句柄数

ZwQueryInformationProcess(hProcess,
                               ProcessHandleCount, &hc,
                               sizeof(hc), NULL)

hc就是该进程打开的句柄数

然后就可以通过DuplicateHandle来复制出句柄了

DuplicateHandle(hProcess,
(HANDLE)h, GetCurrentProcess(),
&ho, 0, FALSE, DUPLICATE_SAME_ACCESS)

这里h就是需要复制的句柄的值 由于并没有对系统中所有的句柄进行遍历

所以这里并不知道每个句柄的值

但是我们知道进程中所有句柄的值都是从4开始 然后每4递增的

就是说每个进程中的句柄值必定为4 8 12 16....等等

但是不一定每个4的倍数都是一个有效的句柄值

如果你把一个无效的句柄值传入Duplicatehandle 该函数会返回错误

这样就相当于系统帮助我们判断了句柄是否存在

在遍历时如果DuplicateHandle成功则表明复制了一个有效句柄

直到复制出hc个有效句柄时 该进程就遍历完成了

由此我们就遍历出了 系统中每个进程所打开的句柄

Windows系统中句柄有很多种类型 XP系统下有如下:


1 Type
2 Directory
3 SymbolicLink
4 Token
5 Process
6 Thread
7 Job
8 DebugObject
9 Event
10 EventPair
11 Mutant
12 Callback
13 Semaphore
14 Timer
15 Profile
16 KeyedEvent
17 WindowStation
18 Desktop
19 Section
20 Key
21 Port
22 WaitablePort
23 Adapter
24 Controller
25 Device
26 Driver
27 IoCompletion
28 File
29 WmiGuid
30 FilterConnectionPort
31 FilterCommunicationPort

对于复制出来的句柄 我们可以通过函数ZwQueryObject来获取其类型信息

以及名字

但是由于使用ZwQueryObject时有可能引起系统死锁

所以需要将该操作放入一个单独的线程中处理 并设置超时

(__stdcall *ZwQueryObject1)(
                IN HANDLE ObjectHandle,
                IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
                OUT PVOID ObjectInformation,
                IN ULONG Length,
                OUT PULONG ResultLength );

如果其中ObjectInformationClass参数为ObjectTypeInformation(2)则表示获取类型信息
存于结构体

typedef struct _OBJECT_TYPE_INFORMATION{
                UNICODE_STRING          TypeName;
                ULONG                   TotalNumberOfHandles;
                ULONG                   TotalNumberOfObjects;
                WCHAR                   Unused1[8];
                ULONG                   HighWaterNumberOfHandles;
                ULONG                   HighWaterNumberOfObjects;
                WCHAR                   Unused2[8];
                ACCESS_MASK             InvalidAttributes;
                GENERIC_MAPPING         GenericMapping;
                ACCESS_MASK             ValidAttributes;
                BOOLEAN                 SecurityRequired;
                BOOLEAN                 MaintainHandleCount;
                USHORT                  MaintainTypeList;
                POOL_TYPE               PoolType;
                ULONG                   DefaultPagedPoolCharge;
                ULONG                   DefaultNonPagedPoolCharge;
                BYTE                    Unknown2[16];
        } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

如果为ObjectNameInformation(1)则获取名字信息 存于结构体

typedef struct _UNICODE_STRING {
        USHORT  Length;
        USHORT  MaximumLength;
        PWSTR  Buffer;
} UNICODE_STRING,*PUNICODE_STRING;

由此我们就可以获得系统中所有进程打开的句柄了 也就可以从中得到时哪些进程打开了某个文件

对于挂起的进程一定要使用ZwResumeProcess将其恢复


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vc 是 Visual C++ 编程语言的简称,可以用于开发 Windows 系统的应用程序。 在 Visual C++ ,要枚举所有串口,可以使用 Win32 API 来完成。以下是一种实现方法: 首先,需要引入 Windows.h 头文件,该头文件包含了访问串口的相关函数和结构体。 然后,使用 CreateFile 函数打开串口,通过遍历端口号来获取每个串口的句柄。例如,端口号 COM1 对应的句柄为"\\\\.\\COM1"。 接着,使用 GetCommState 函数获取当前串口的配置信息,可以得到波特率、数据位、奇偶校验等参数。 随后,将获取到的串口信息存储到一个数组,即可完成所有串口的枚举。 最后,使用 CloseHandle 函数关闭串口句柄,释放资源。 下面是示例代码: ```cpp #include <Windows.h> #include <iostream> int main() { for (int i = 1; i <= 255; i++) { std::string portName = "\\\\.\\COM" + std::to_string(i); HANDLE hPort = CreateFile( portName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if (hPort != INVALID_HANDLE_VALUE) { DCB dcb; if (GetCommState(hPort, &dcb)) { std::cout << "串口号: COM" << i << std::endl; std::cout << "波特率: " << dcb.BaudRate << std::endl; std::cout << "数据位: " << dcb.ByteSize << std::endl; std::cout << "奇偶校验: " << dcb.Parity << std::endl; std::cout << std::endl; } CloseHandle(hPort); } } return 0; } ``` 上述代码通过遍历从 COM1 到 COM255 的端口号,打开每个串口并获取其配置信息,并将其输出到控制台。 总结:以上就是使用 Visual C++ 枚举所有串口的方法及示例代码。通过遍历端口号、使用相应的 Win32 API 函数可以实现串口的枚举

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值