您的位置:首页 > 编程语言 > Delphi

ZwQuerySystemInformation 安全使用心得 Delphi 版

2013-07-24 14:27 351 查看
作为 DELPHI 版本,需要引用 jwaNative, JwaWinType ,他们是 JEDI API 的一部分。JEDI 官网有下载。

先给出 2 个辅助函数 和 一些结构体。

type

PRecord = ^TRecord;
TRecord = record
end;

PSystemInformationList = ^TSystemInformationList;
TSystemInformationList = record
Count: ULONG;
List: array [0 .. 0] of TRecord;
end;

PSYSTEM_HANDLE_Informations = ^TSYSTEM_HANDLE_Informations;
_SYSTEM_HANDLE_Informations = record
Count: ULONG;
SH: array [0 .. 0] of _SYSTEM_HANDLE_INFORMATION;
end;

TSYSTEM_HANDLE_Informations = _SYSTEM_HANDLE_Informations;
SYSTEM_HANDLE_Informations = _SYSTEM_HANDLE_Informations;

PNM_INFO = ^TNM_INFO;

_NM_INFO = record
hFile: THandle;
Info: _FILE_NAME_Information;
Name: array [0 .. MAX_PATH - 1] of WideChar;
end;

TNM_INFO = _NM_INFO;
NM_INFO = _NM_INFO;

Function GetSystemInformationClassSize(Const ATableType: SYSTEM_INFORMATION_CLASS; Const Count: ULONG): ULONG;
begin
Result := 0;
case ATableType of
SystemBasicInformation:
Result := $002C;
SystemProcessorInformation:
Result := $0000C;
SystemPerformanceInformation:
Result := $0138;
// SystemTimeInformation: Result := $0020;
// SystemPathInformation: Result := $0;
// SystemProcessInformation: Result := $00C8 + Count;
// SystemCallInformation: Result := $0018 + (Count * $0004);
SystemConfigurationInformation:
Result := $0018;
// SystemProcessorCounters: Result := $0030 + Count;//per cpu
SystemGlobalFlag:
Result := $0004; // (fails if size != 4)
// SystemCallTimeInformation: Result := $0;
SystemModuleInformation:
Result := $0004 + (Count * Sizeof(SYSTEM_MODULE_INFORMATION)); //(n * 0x011C)
SystemLockInformation:
Result := $0004 + (Count * Sizeof(SYSTEM_LOCK_INFORMATION)); //(n * 0x0024)
// SystemStackTraceInformation: Result := $0;
// SystemPagedPoolInformation: Result := $0;
// SystemNonPagedPoolInformation: Result := $0;
SystemHandleInformation:
Result := $0004 + (Count * Sizeof(SYSTEM_HANDLE_INFORMATION)); //(n * 0x0010)
// SystemObjectTypeInformation: Result := $0038+ + (Count * $0030);// +)
SystemPageFileInformation:
Result := $0018 + (Count * Sizeof(SYSTEM_PAGEFILE_INFORMATION));
// SystemVdmInstemulInformation: Result := $0088;
// SystemVdmBopInformation: Result := $0;
SystemCacheInformation:
Result := $0024;
SystemPoolTagInformation:
Result := $0004 + (Count * Sizeof(SYSTEM_POOL_TAG_INFORMATION)); // (n * 0x001C)
// SystemInterruptInformation: Result := $0000 + Count;//, or 0x0018 per cpu
SystemDpcInformation:
Result := $0014;
// SystemFullMemoryInformation: Result := $0;
// SystemLoadDriver: Result := $0018;//, set mode only
// SystemUnloadDriver: Result := $0004;//, set mode only
// SystemTimeAdjustmentInformation: Result := $000C;//, 0x0008 writeable
// SystemSummaryMemoryInformation: Result := $0;
// SystemNextEventIdInformation: Result := $0;
// SystemEventIdsInformation: Result := $0;
SystemCrashDumpInformation:
Result := $0004;
SystemExceptionInformation:
Result := $0010;
SystemCrashDumpStateInformation:
Result := $0004;
// SystemDebuggerInformation: Result := $0002;
SystemContextSwitchInformation:
Result := $0030;
SystemRegistryQuotaInformation:
Result := $000C;
// SystemAddDriver: Result := $0008;//, set mode only
// SystemPrioritySeparationInformatio: Result := $0004;//, set mode only
// SystemPlugPlayBusInformation: Result := $0;
// SystemDockInformation: Result := $0;
// SystemPowerInfo: Result := $0060;// (XP only!)
// SystemProcessorSpeedInformation: Result := $000C;// (XP only!)
SystemTimeZoneInformation:
Result := $00AC;
SystemLookasideInformation:
Result := Count * $0020;
SystemSetTimeSlipEvent:
Result := $0;
SystemCreateSession:
Result := $0;
SystemDeleteSession:
Result := $0;
SystemInvalidInfoClass1:
Result := $0;
SystemRangeStartInformation:
Result := $0004; // (fails if size != 4)
SystemVerifierInformation:
Result := $0;
SystemAddVerifier:
Result := $0;
SystemSessionProcessesInformation:
Result := $0;
end;
end;

Function GetSystemInformationClassHasCount(Const ATableType: SYSTEM_INFORMATION_CLASS): BOOL;
begin
Result := False;
case ATableType of
// SystemProcessInformation,
// SystemCallInformation,
// SystemProcessorCounters,
SystemModuleInformation,
SystemLockInformation,
SystemHandleInformation,
// SystemObjectTypeInformation,
//SystemPageFileInformation, //好像这个还不确定。
// SystemInterruptInformation,
SystemPoolTagInformation:
Result := True;
end;
//可以 和 GetSystemInformationClassSize 配合使用。
end;


  

上面的 NM_INFO 和本文无关。

大家 可以 方便的使用 GetSystemInformationTable 来 获取所需的系统信息数据。

Function GetSystemInformationTable(hHeap: THandle; Const ATableType: SYSTEM_INFORMATION_CLASS; var buffSize: ULONG): PVOID;
var
OldPrivilegeAttributes: ULONG;
hFile, hQuery: THandle;
Status: NTSTATUS;
cbBuffer: Cardinal;
AVOID: PVOID;
MinBufSize,
ReturnLength: ULONG;
PReturnLength: PULONG;
begin
buffSize := 0;
Result := nil;
if not EnableDebugPrivilege(GetCurrentProcess, True, OldPrivilegeAttributes) then
Exit;
try
ReturnLength := 0;
cbBuffer := 0;
AVOID := nil;
PReturnLength := Addr(ReturnLength);
Status := ZwQuerySystemInformation(ATableType, AVOID, 0, PReturnLength);
if (ReturnLength > 0) then // ReturnLength 一个结构的大小。
begin
cbBuffer := ReturnLength;
MinBufSize := ReturnLength;
AVOID := HeapAlloc(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, cbBuffer);
if not Assigned(AVOID) then
Exit;
try
ZeroMemory(AVOID, cbBuffer);
Status := ZwQuerySystemInformation(ATableType, AVOID, cbBuffer, PReturnLength);
if NTSTATUS_SUCCESS(Status) then
begin
Result := AVOID;
buffSize := cbBuffer;
end
else if (Status = STATUS_INFO_LENGTH_MISMATCH) and GetSystemInformationClassHasCount(ATableType) then
begin
//调试中,下一秒,也许就不够用了。不调试,大概也需要多申请些空间
//cbBuffer := GetSystemInformationClassSize(ATableType, PSystemInformationList(AVOID).Count + 100);
cbBuffer := Sizeof(PSystemInformationList(AVOID).Count) +
(MinBufSize - Sizeof(PSystemInformationList(AVOID).Count)) * (PSystemInformationList(AVOID).Count + 100);
HeapFree(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, AVOID);
AVOID := HeapAlloc(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, cbBuffer);
if not Assigned(AVOID) then
Exit;
try
ZeroMemory(AVOID, cbBuffer);
Status := ZwQuerySystemInformation(ATableType, AVOID, cbBuffer, PReturnLength);
if NTSTATUS_SUCCESS(Status) then
begin
Result := AVOID;
buffSize := cbBuffer;
end
else
begin
HeapFree(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, AVOID);
end;
finally
end;
end
else
begin
HeapFree(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, AVOID);
cbBuffer := $10000;
repeat
AVOID := HeapAlloc(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, cbBuffer);
if not Assigned(AVOID) then
Exit;
ZeroMemory(AVOID, cbBuffer);
Status := ZwQuerySystemInformation(ATableType, AVOID, cbBuffer, PReturnLength);
if (Status = STATUS_INFO_LENGTH_MISMATCH) then
begin
HeapFree(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, AVOID);
cbBuffer := cbBuffer * 2;
end;
if cbBuffer > $1000000 then
begin
Exit;
end;
until (Status <> STATUS_INFO_LENGTH_MISMATCH);
if NTSTATUS_SUCCESS(Status) then
begin
Result := AVOID;
buffSize := cbBuffer;
end
else
begin
HeapFree(hHeap, 0 or HEAP_GENERATE_EXCEPTIONS, AVOID);
end;
end;
finally
end;
end
else
begin
Result := nil;
buffSize := 0;
end;
finally
SetDebugPrivilege(GetCurrentProcess, OldPrivilegeAttributes, OldPrivilegeAttributes);
end;
end;


第一次 ZwQuerySystemInformation,主要是为了返回 ReturnLength,这个是 最小数据大小,一般对于单个的数据,就直接用这个值。但是对于多个的数据,这个值就是 每一个数据项的大小加上 4 。

第二次调用 ZwQuerySystemInformation,返回了一个数据区,如果多个的数据,肯定会 Status = STATUS_INFO_LENGTH_MISMATCH,所以需要第三次调用。大小有 2 种办法获取(具体看代码)。

如果不确定是不是 多个数据,但是又出现空间不够用的情况,就需要用网络上大家常见的循环增大空间的办法了。

另外 hHeap := GetProcessHeap; 可以得到 hHeap ,而且空间的申请,不一定非要用这个,也可以用 GetMem 等。

最后补上 权限提升函数。

Function SetDebugPrivilege(Const hProcess: THandle; Const PrivilegeAttributes: ULONG;
var OldPrivilegeAttributes: ULONG): Boolean;
var
hToken: THandle;
tp: TOKEN_PRIVILEGES;
NewPrivilegeAttributes: ULONG;
ReturnLength: ULONG;
hProcessToken: THandle;
begin
hToken := NULL_Handle;
Result := False;
OldPrivilegeAttributes := SE_PRIVILEGE_ENABLED_BY_DEFAULT;
NewPrivilegeAttributes := PrivilegeAttributes;
hProcessToken := hProcess;
if hProcessToken = NULL_Handle then
begin
hProcessToken := GetCurrentProcess;
end;
if (OpenProcessToken(hProcessToken, TOKEN_ADJUST_PRIVILEGES, hToken)) // 获得进程访问令牌的句柄
then
begin
try
tp.PrivilegeCount := 1;
LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid); // 查询进程的权限,获取一个权限对应的LUID值
OldPrivilegeAttributes := tp.Privileges[0].Attributes;
tp.Privileges[0].Attributes := NewPrivilegeAttributes;
Result := AdjustTokenPrivileges(hToken, False, tp, sizeof(tp), nil, ReturnLength); // 判断令牌权限,对这个访问令牌进行修改
finally
CloseHandle(hToken);
end;
end;
end;

// 提升当前进程具有权限
Function EnableDebugPrivilege(Const hProcess: THandle; Const Enable: Boolean;
var OldPrivilegeAttributes: ULONG): Boolean;
var
hToken: THandle;
tp: TOKEN_PRIVILEGES;
ReturnLength: ULONG;
hProcessToken: THandle;
begin
hToken := NULL_Handle;
Result := False;
OldPrivilegeAttributes := SE_PRIVILEGE_ENABLED_BY_DEFAULT;
hProcessToken := hProcess;
if hProcessToken = NULL_Handle then
begin
hProcessToken := GetCurrentProcess;
end;
if (OpenProcessToken(hProcessToken, TOKEN_ADJUST_PRIVILEGES, hToken)) // 获得进程访问令牌的句柄
then
begin
try
tp.PrivilegeCount := 1;
LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid); // 查询进程的权限,获取一个权限对应的LUID值
OldPrivilegeAttributes := tp.Privileges[0].Attributes;
if Enable then
begin
tp.Privileges[0].Attributes := tp.Privileges[0].Attributes or SE_PRIVILEGE_ENABLED;
// tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
end
else
begin
tp.Privileges[0].Attributes := tp.Privileges[0].Attributes and (not SE_PRIVILEGE_ENABLED);
// tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED_BY_DEFAULT;
// tp.Privileges[0].Attributes := 0;
end;
Result := AdjustTokenPrivileges(hToken, False, tp, sizeof(tp), nil, ReturnLength); // 判断令牌权限,对这个访问令牌进行修改
finally
CloseHandle(hToken);
end;
end;
end;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: