비문서화된 API인 ZwQuerySystemInformation을 이용해서 시스템 정보를 보여주는 프로그램을 하나 만들려고 합니다.
( Project JEDI ( http://jedi-apilib.sourceforge.net/ )에서 받은곳에 정의되어 있던것입니다. )
혹시나해서 기존에 정의된 SYSTEM_HANDLE_INFO record를 복사해서 packed record형으로 MY_SYSTEM_HANDLE_INFO를 만들어봤지만 여전하네요....
제가 겪고 있는 문제는 ZwQuerySystemInformation 함수를 사용하면
리턴값은 (숫자) + (구조체) + (구조체) + ... 형태로 리턴이 되야 하는데,
제가 해보면 리턴되는 수는 24000개가 넘게 나오지만
SYSTEM_HANDLE_INFO 정보는 오직 첫번째만 세팅되고 있습니다.
정확한것은 아니지만 첫번째 Record에 들어가는 값을 보면
아무래도 첫번째는 정확히 세팅되는것 같구요.
다른것들은 99% 0값을 가지고 있고, 나머지 가끔 보이는것도 비정상적인 값으로 보입니다.
(브레이크 포인트걸고 배열에 마우스 가져다 대 봤습니다. ^^;;;)
당최 왜 이러는지 모르겠네요.
어떻게 손봐야 제대로 정보가 꽉찬 리턴값을 받을 수 있을까요?
아래에는 테스트용으로 만든, 딱 정보만 가져와서 찍는거긴하지만.. Unit1.pas를 다 올려봅니다...
Memo와 Button만 하나씩 있습니다.
<!--CodeS-->
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, jwaVista, jwaWindows, StdCtrls;
type
_MY_SYSTEM_HANDLE_INFORMATION = packed record // Information Class 16
ProcessId: ULONG;
ObjectTypeNumber: UCHAR;
Flags: UCHAR; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
Handle: USHORT;
Object_: PVOID;
GrantedAccess: ACCESS_MASK;
end;
MY_SYSTEM_HANDLE_INFORMATION = _MY_SYSTEM_HANDLE_INFORMATION;
PMY_SYSTEM_HANDLE_INFORMATION = ^SYSTEM_HANDLE_INFORMATION;
TMY_SystemHandleInformation = MY_SYSTEM_HANDLE_INFORMATION;
PMY_SystemHandleInformation = ^TMY_SystemHandleInformation;
type
TMy_SBI = packed record
recordCount : ULONG;
arrSBI : array[0..50000] of MY_SYSTEM_HANDLE_INFORMATION;
end;
PMy_SBI = ^TMy_SBI;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
function Unicode_String_To_String( us : UNICODE_STRING):String;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
CONST_ADD_QUERY_SIZE = 200;
procedure TForm1.Button1Click(Sender: TObject);
var
hProcess : THandle;
i, QueryCount : integer;
pInfo : PMy_SBI;
hObject : THandle;
obi : OBJECT_BASIC_INFORMATION;
pOti : POBJECT_TYPE_INFORMATION;
pOni : POBJECT_NAME_INFORMATION;
nTypeName, nObjectName, n : ULONG;
begin
QueryCount := 50000 * sizeOf(MY_SYSTEM_HANDLE_INFORMATION) + sizeOf(ULONG);
GetMem( pInfo, QueryCount);
if ZwQuerySystemInformation( SystemHandleInformation, pInfo, QueryCount, nil) = STATUS_INFO_LENGTH_MISMATCH then // <--- 이부분이 끝난 후, 아래쪽 IF문의 pInfo.arrSBI에 마우스를 가져다 대어보면 첫 항목만 세팅된듯 합니다.
begin
FreeMem(pInfo);
showmessage('배열공간부족');
end;
Memo1.Lines.Add( '시스템 핸들 수 : ' + inttostr(pInfo.recordCount));
for i := 0 to (pInfo.recordCount-1) do
begin
if (DuplicateHandle(hProcess, pInfo.arrSBI[i].Handle, GetCurrentProcess(), @hObject, 0, False, DUPLICATE_SAME_ACCESS) = True) then
begin
ZwQueryObject(hObject, ObjectBasicInformation, @obi, sizeof(obi), @n);
nTypeName := obi.TypeInformationLength + 2;
GetMem(pOti, nTypeName);
ZwQueryObject(hObject, ObjectTypeInformation, pOti, nTypeName, @nTypeName);
if obi.NameInformationLength = 0 then
begin
nObjectName := MAX_PATH * sizeof(WCHAR);
end else
begin
nObjectName := obi.NameInformationLength;
end;
GetMem(pOni, nObjectName);
if ZwQueryObject(hObject, ObjectNameInformation, pOni, nObjectName, @nObjectName) <> 0 then
begin
Memo1.Lines.Add( Format('%5x %4x %4x %2x %s', [pInfo.arrSBI[i].ProcessId, pInfo.arrSBI[i].ObjectTypeNumber, pInfo.arrSBI[i].Flags, pInfo.arrSBI[i].Handle, Unicode_String_To_String(pOni.Name)]));
end;
FreeMem(pOti);
FreeMem(pOni);
end;
end;
end;
function TForm1.Unicode_String_To_String( us : UNICODE_STRING):String;
var
i : integer;
begin
result := '';
for i := 1 to (us.Length) do
begin
if Ord(us.Buffer[i-1]) = 0 then
begin
exit;
end else begin
result := result + us.Buffer[i-1];
end;
end;
end;
end.
<!--CodeE-->
첫번째에 들어가는 hProcess는 소스의 프로세스 핸들(hSourceProcessHandle)인데... 그 어디에도 값이 설정된곳이 없네요...