Q&A

  • ZwQuerySystemInformation 함수로 리턴값을 받았는데, 첫항목만 세팅된것 같습니다.
비문서화된 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-->
4  COMMENTS
  • Profile
    최용일 2009.07.03 15:47
    DuplicateHandle함수 사용이 문제가 있는것 같은데요...
    첫번째에 들어가는 hProcess는 소스의 프로세스 핸들(hSourceProcessHandle)인데... 그 어디에도 값이 설정된곳이 없네요...
  • Profile
    송 시중 2009.07.03 17:08
    배열에 첫 아이템에만 값이 들어가는 문제는 비스타64에선 안되는것으로 확인됐습니다.
    윈도XP와 윈도7베타 64비트에서 테스트는 정상적으로 작동되네요.
    (비스타64는 안된면서 윈도7 64비트에선 왜 정상인건지.. -_-;;)
    여지껏 비스타64쓰면서 운영체제의 의한 문제는 못 느꼈었는데,
    비문서화 함수라 그런지 문제가 생기네요.
    프로세스 익스플러러는 비스타64에서도 정상적으로 표시해주는걸 보면, 다른 함수나 다른 방식을 찾아봐야할것 같습니다.
    (사실 프로세스 익스플러러도 32비트용과 64비트용 실행파일을 따로 만들어서 실행하더군요)

    DuplicateHandle함수 인자는 제가 C코드를 배끼다보니 그렇게 된것 같습니다. ^^;
    첫 인자는 self.Handle만 줘도 무난하겠지요?
  • Profile
    최용일 2009.07.03 20:34
    폼의 핸들이 아니라 프로세스 핸들이 들어가야죠... arrSBI에서 받은 프로세스 ID로 OpenProcess를 이용하셔서 핸들을 얻어오세요.
  • Profile
    송 시중 2009.07.04 16:10
    알려주신 방법으로 원하던바를 이루었습니다.
    감사합니다. ^^