草庐IT

windows - 如何获取 NtQueryInformationProcess 所需的缓冲区大小?

coder 2024-06-18 原文

NtQueryInformationProcess的ReturnLength参数说明如下:

ReturnLength

A pointer to a variable in which the function returns the size of the requested information. If the function was successful, this is the size of the information written to the buffer pointed to by the ProcessInformation parameter, but if the buffer was too small, this is the minimum size of buffer needed to receive the information successfully.

特别感兴趣的部分是:如果缓冲区太小,这是成功接收信息所需的最小缓冲区大小。

我希望函数返回特定信息类所需的缓冲区大小。

我尝试了以下方法:

 // for static linking

function NtQueryInformationProcess(ProcessHandle        : THANDLE;
                               ProcessInformationClass  : DWORD;
                               ProcessInformation       : PPEB;
                               ProcessInformationLength : DWORD;
                               ReturnLength             : PDWORD)
     : NTSTATUS; stdcall; external ntdll;

 // for dynamic linking

 type
   TNtQueryInformationProcess
     = function (ProcessHandle       : THANDLE;
            ProcessInformationClass  : DWORD;
            ProcessInformation       : PPEB;
            ProcessInformationLength : DWORD;
            ReturnLength             : PDWORD) : NTSTATUS; stdcall;

var
  ProcessHandle : THANDLE;

  Peb           : TPEB;
  BufferSize    : DWORD;
  ReturnLength  : DWORD;
  NtResult      : NTSTATUS;
  NtdllHandle   : HMODULE;
  NtQueryInformationProcessPtr : TNtQueryInformationProcess;

begin
 ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS,
                              FALSE,
                              GetCurrentProcessId());

 ZeroMemory(@Peb, sizeof(Peb));
 BufferSize   := sizeof(PROCESS_BASIC_INFORMATION);
 ReturnLength := 0;

 NtResult := NtQueryInformationProcess(ProcessHandle,
                                       ProcessBasicInformation,
                                    @Peb,
                                    BufferSize,
                                   @ReturnLength);

 writeln('NTSTATUS     : ', IntToHex(NtResult, 0));
 writeln('ReturnLength : ', ReturnLength);

 // try calling the function by address

 NtdllHandle := LoadLibrary('ntdll.dll');

 pointer(NtQueryInformationProcessPtr) := GetProcAddress(NtdllHandle,
                                             'NtQueryInformationProcess');

 // reinitialize just to be safe

 ZeroMemory(@Peb, sizeof(Peb));
 BufferSize   := sizeof(PROCESS_BASIC_INFORMATION);
 ReturnLength := 0;

 NtResult := NtQueryInformationProcessPtr(ProcessHandle,
                                          ProcessBasicInformation,
                                       @Peb,
                                       BufferSize,
                                       @ReturnLength);

 writeln('NTSTATUS     : ', IntToHex(NtResult, 0));
 writeln('ReturnLength : ', ReturnLength);

 writeln('program end.');
 readln;
end.

当我将缓冲区的大小设置为 ProcessBasicInformation 的正确大小时,一切都按预期工作,但是,如果我将 BufferSize 设置为零(例如)希望函数在 ReturnLength 变量中返回必要的缓冲区大小,我得到正如预期的那样返回 0xC0000004(大小不匹配)但是,ReturnLength 变量未设置为成功获取 ProcessBasicInformation 所需的大小。

鉴于 ReturnLength 参数的描述,我希望 API 将 ReturnLength 设置为请求的信息类所需的任何大小。

我的问题是:代码中是否存在错误,或者 API 是否没有按照记录工作?还是我误解了 ReturnLength 参数的描述?

感谢您的帮助。

最佳答案

许多 Win32 API 旨在通过使用 nil 指针调用它并为 ReturnLength 指定 0 来告诉您正确的缓冲区大小。 Nt api 的工作方式通常有点不同:

您只需向它传递一个任意大小的缓冲区,它会通过返回 STATUS_INFO_LENGTH_MISMATCH 告诉您是否需要更多。

我还建议使用 Jedi Api Library而不是自己翻译 (Nt Api) 函数/ header 。

编辑:似乎您正在尝试读取 ProcessBasicInformation 类,该类具有固定大小并且不返回指向 PEB 的指针而是返回指向 PROCESS_BASIC_INFORMATION 的指针结构/记录。

这是您尝试执行的操作的示例:

// uses JwaNative

function TDebugThread.ReadPEB: Boolean;
var
  nts: NTSTATUS;
  pbi: PROCESS_BASIC_INFORMATION;
  dwBytes: DWORD;
begin
  Result := False;
  nts := NtQueryInformationProcess(pi.hProcess,
    ProcessBasicInformation, @pbi, SizeOf(pbi), @dwBytes);

  if nts <> STATUS_SUCCESS then
    Exit;

  New(PEB);
  Result := ReadProcessMemory(pi.hProcess, pbi.PebBaseAddress, PEB, SizeOf(PEB^),
    @dwBytes);

end;

下面是一个使用 NtQuerySystemInformation 的示例(完整示例可以在我的 GitHub repository 上找到)。

{ TProcessList }
constructor TProcessList.Create(const AOwnsObjects: Boolean = True);
var
  Current: PSystemProcesses;
  SystemProcesses : PSystemProcesses;
  dwSize: DWORD;
  nts: NTSTATUS;
begin
  inherited Create(AOwnsObjects);

  dwSize := 200000;
  SystemProcesses := AllocMem(dwSize);

  nts := NtQuerySystemInformation(SystemProcessesAndThreadsInformation,
      SystemProcesses, dwSize, @dwSize);

  while nts = STATUS_INFO_LENGTH_MISMATCH do
  begin
    ReAllocMem(SystemProcesses, dwSize);
    nts := NtQuerySystemInformation(SystemProcessesAndThreadsInformation,
      SystemProcesses, dwSize, @dwSize);
  end;

  if nts = STATUS_SUCCESS then
  begin
    Current := SystemProcesses;
    while True do
    begin
      Self.Add(TProcess.Create(Current^));
      if Current^.NextEntryDelta = 0 then
        Break;

      Current := PSYSTEM_PROCESSES(DWORD_PTR(Current) + Current^.NextEntryDelta);
    end;
  end;

  FreeMem(SystemProcesses);
end;

编辑:回答@ScienceAmateur 的评论,以下测试代码始终为 ReturnLength 返回 0:

uses
  Windows,
  System.SysUtils,
  Rtti,
  JwaNative,
  JwaWinType,
  JwaNtSecApi,
  JwaNtStatus;


function NtStatusErrorMessage(const nts: NTSTATUS): String;
begin
  Result := SysErrorMessage(LsaNtStatusToWinError(nts));
end;

var
  nts: NTSTATUS;
  pic: PROCESS_INFORMATION_CLASS;
  Buffer: Pointer;
  pil: DWORD;
  ReturnLength: DWORD;
begin
  for pic := Low(PROCESS_INFORMATION_CLASS) to High(PROCESS_INFORMATION_CLASS) do
  begin
    Buffer := nil;
    pil := 0;
    ReturnLength := 0;
    nts := NtQueryInformationProcess(GetCurrentProcess,
      ProcessBasicInformation, Buffer, pil, @ReturnLength);
    WriteLn(Format('%s: returned 0x%.8x and ReturnLength: %d', [TRttiEnumerationType.GetName(pic), nts, ReturnLength]));
  end;

  WriteLn('Finished.');

  if DebugHook <> 0 then
    ReadLn;

输出:

ProcessBasicInformation: returned 0xC0000004 and ReturnLength: 0
ProcessQuotaLimits: returned 0xC0000004 and ReturnLength: 0
ProcessIoCounters: returned 0xC0000004 and ReturnLength: 0
ProcessVmCounters: returned 0xC0000004 and ReturnLength: 0
ProcessTimes: returned 0xC0000004 and ReturnLength: 0
ProcessBasePriority: returned 0xC0000004 and ReturnLength: 0
ProcessRaisePriority: returned 0xC0000004 and ReturnLength: 0
ProcessDebugPort: returned 0xC0000004 and ReturnLength: 0
ProcessExceptionPort: returned 0xC0000004 and ReturnLength: 0
ProcessAccessToken: returned 0xC0000004 and ReturnLength: 0
ProcessLdtInformation: returned 0xC0000004 and ReturnLength: 0
ProcessLdtSize: returned 0xC0000004 and ReturnLength: 0
ProcessDefaultHardErrorMode: returned 0xC0000004 and ReturnLength: 0
ProcessIoPortHandlers: returned 0xC0000004 and ReturnLength: 0
ProcessPooledUsageAndLimits: returned 0xC0000004 and ReturnLength: 0
ProcessWorkingSetWatch: returned 0xC0000004 and ReturnLength: 0
ProcessUserModeIOPL: returned 0xC0000004 and ReturnLength: 0
ProcessEnableAlignmentFaultFixup: returned 0xC0000004 and ReturnLength: 0
ProcessPriorityClass: returned 0xC0000004 and ReturnLength: 0
ProcessWx86Information: returned 0xC0000004 and ReturnLength: 0
ProcessHandleCount: returned 0xC0000004 and ReturnLength: 0
ProcessAffinityMask: returned 0xC0000004 and ReturnLength: 0
ProcessPriorityBoost: returned 0xC0000004 and ReturnLength: 0
ProcessDeviceMap: returned 0xC0000004 and ReturnLength: 0
ProcessSessionInformation: returned 0xC0000004 and ReturnLength: 0
ProcessForegroundInformation: returned 0xC0000004 and ReturnLength: 0
ProcessWow64Information: returned 0xC0000004 and ReturnLength: 0
ProcessImageFileName: returned 0xC0000004 and ReturnLength: 0
ProcessLUIDDeviceMapsEnabled: returned 0xC0000004 and ReturnLength: 0
ProcessBreakOnTermination: returned 0xC0000004 and ReturnLength: 0
ProcessDebugObjectHandle: returned 0xC0000004 and ReturnLength: 0
ProcessDebugFlags: returned 0xC0000004 and ReturnLength: 0
ProcessHandleTracing: returned 0xC0000004 and ReturnLength: 0
MaxProcessInfoClass: returned 0xC0000004 and ReturnLength: 0

关于windows - 如何获取 NtQueryInformationProcess 所需的缓冲区大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55084802/

有关windows - 如何获取 NtQueryInformationProcess 所需的缓冲区大小?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  6. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  7. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐