delphi R3下 跨进程获取DLL信息 NtQueryInformationProcess

unit APIUnit;
{
 GetProcessModuleHandle API Unit

 Ring3调用NtQueryInformationProcess实现跨进程获取DLL句柄

}
interface
USES
  Winapi.Windows,System.SysUtils;
type
  USHORT = Word;
  UNICODE_STRING = packed Record
  Length : USHORT;
  MaximumLength: USHORT;
  Buffer : PWideString;
  end;
  RTL_USER_PROCESS_PARAMETERS = packed record
  Reserved1 : array[0..15] of Byte;
  Reserved2 : array[0..9] of Pointer;
  ImagePathName: UNICODE_STRING;
  CommandLine : UNICODE_STRING;
  end;
  PRTL_USER_PROCESS_PARAMETERS = ^RTL_USER_PROCESS_PARAMETERS;

  _PEB_LDR_DATA = record
    Length: ULONG;
    Initialized: BOOLEAN;
    SsHandle: pointer;//PVOID;
    InLoadOrderModuleList: LIST_ENTRY;
    InMemoryOrderModuleList: LIST_ENTRY;
    InInitializationOrderModuleList: LIST_ENTRY;
  end {_PEB_LDR_DATA};
  PEB_LDR_DATA = _PEB_LDR_DATA;
  PPEB_LDR_DATA = ^_PEB_LDR_DATA;

  _LDR_MODULE = record
    InLoadOrderModuleList: LIST_ENTRY;
    InMemoryOrderModuleList: LIST_ENTRY;
    InInitializationOrderModuleList: LIST_ENTRY;
    BaseAddress: pointer;
    EntryPoint:  pointer;
    SizeOfImage: ULONG;
    FullDllName: UNICODE_STRING;
    BaseDllName: UNICODE_STRING;
    Flags: ULONG;
    LoadCount: SmallInt;
    TlsIndex: SmallInt;
    HashTableEntry: LIST_ENTRY;
    TimeDateStamp: ULONG;
  end {_LDR_MODULE};
  LDR_MODULE = _LDR_MODULE;
  PLDR_MODULE = ^_LDR_MODULE;

  _PEB_FREE_BLOCK = record
    Next:Pointer;
    Size:ULONG;
  end;
  PPEB_FREE_BLOCK = ^_PEB_FREE_BLOCK;

  PEB = packed record
    InheritedAddressSpace:Boolean;// 00h
    ReadImageFileExecOptions:Boolean; // 01h
    BeingDebugged:Boolean; //02H
    Spare:Boolean;
    Mutant:THandle;
    ImageBaseAddress:Pointer;
    LoaderData:Pointer;  //0C
    ProcessParameters:Pointer;
    SubSystemData:Pointer;
    ProcessHeap:Pointer;
    FastPebLock:Pointer;
    FastPebLockRoutine:PPointer;
    FastPebUnlockRoutine:PPointer;
    EnvironmentUpdateCount:ULONG;
    KernelCallbackTable:^Pointer;
    EventLogSection:Pointer;
    EventLog:Pointer;
    FreeList:PPEB_FREE_BLOCK;
    TlsExpansionCounter:ULONG;
    TlsBitmap:Pointer;
    TlsBitmapBits:array [0..$2] of ULONG;
    ReadOnlySharedMemoryBase:Pointer;
    ReadOnlySharedMemoryHeap:Pointer;
    ReadOnlyStaticServerData:^Pointer;
    AnsiCodePageData:Pointer;
    OemCodePageData:Pointer;
    UnicodeCaseTableData:Pointer;
    NumberOfProcessors:ULONG;
    NtGlobalFlag:ULONG;
    Spare2:array [0..$4] of Byte;
    CriticalSectionTimeout:LARGE_INTEGER;
    HeapSegmentReserve:ULONG;
    HeapSegmentCommit:ULONG;
    HeapDeCommitTotalFreeThreshold:ULONG;
    HeapDeCommitFreeBlockThreshold:Ulong;
    NumberOfHeaps:ULONG;
    MaximumNumberOfHeaps:ULONG;
    ProcessHeaps:PPointer;
    GdiSharedHandleTable:Pointer;
    ProcessStarterHelper:Pointer;
    GdiDCAttributeList:Pointer;
    LoaderLock:Pointer;
    OSMajorVersion:ULONG;
    OSMinorVersion:ULONG;
    OSBuildNumber:ULONG;
    OSPlatformId:ULONG;
    ImageSubSystem:ULONG;
    ImageSubSystemMajorVersion:ULONG;
    ImageSubSystemMinorVersion:ULONG;
    GdiHandleBuffer:array [0..$22] of ULONG;
    PostProcessInitRoutine:ULONG;
    TlsExpansionBitmap:ULONG;
    TlsExpansionBitmapBits: array [0..$80] of Byte;
    SessionId:ULONG;
  end;
  PPEB = ^PEB;

  PROCESS_BASIC_INFORMATION = packed record
  ExitStatus : DWORD;
  PebBaseAddress: PPEB;
  AffinityMask : DWORD;
  BasePriority : DWORD;
  uUniqueProcessId: ULong;
  uInheritedFromUniqueProcessId: ULong;
  end;
  TProcessBasicInformation = PROCESS_BASIC_INFORMATION;
 

function NtQueryInformationProcess(
          ProcessHandle: THandle; {进程句柄}
          ProcessInformationClass: Byte; {信息类型}
          ProcessInformation: Pointer;   {缓冲指针}
          ProcessInformationLength: ULONG; {以字节为单位的缓冲大小}
          ReturnLength: PULONG  {写入缓冲的字节数}
          ): DWORD; stdcall; external 'ntdll.dll';
function GetProcessModuleHandle(dwProcessID:DWORD;DllName:PChar):DWORD;
implementation
  function EnablePrivilege(hToken: Cardinal; PrivName: string; bEnable: Boolean):Boolean;
  var
    TP: TOKEN_PRIVILEGES;
    Dummy: Cardinal;
  begin
    try
      TP.PrivilegeCount := 1;
      LookupPrivilegeValue(nil, pchar(PrivName), TP.Privileges[0].Luid);
      if bEnable then
        TP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
      else TP.Privileges[0].Attributes := 0;
      AdjustTokenPrivileges(hToken, False, TP, SizeOf(TP), nil, Dummy);
    except
    end;
    Result :=True;
  end;
  function EnableDebugPrivilege: Boolean;
  var
    hToken: THandle;
  begin
    Result := False;
    try
      OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken);
      EnablePrivilege(hToken, 'SeDebugPrivilege', True);
      CloseHandle(hToken);
      Result :=True;
    except
    end;
  end;
  function GetProcessModuleHandle(dwProcessID:DWORD;DllName:PChar):DWORD;
  var
    hProcess:DWORD;
    PBI:TProcessBasicInformation;
    r,ret:DWORD;
    readByte: SIZE_T;
    PEBType:PPEB;
    PLD :PPEB_LDR_DATA;
    PME :PLDR_MODULE;
    PEBDLLName:PChar;
  const
    Size:DWORD = 255;
  begin
     Result := 0;
     GetMem(PEBType,SizeOf(PEB));
     ZeroMemory(PEBType,SizeOf(PEB));
     GetMem(PLD,SizeOf(PEB_LDR_DATA));
     ZeroMemory(PLD,SizeOf(PEB_LDR_DATA));
     GetMem(PME,SizeOf(LDR_MODULE));
     ZeroMemory(PME,SizeOf(LDR_MODULE));
     GetMem(PEBDLLName,Size);
     try
        //提升进程权限
        if not EnableDebugPrivilege then
        begin
          OutputDebugStringW('Do not have Debug privilege');   //无法提升调试权限
        end;
        //如果PID为0则获取自身的伪句柄,如果不是则获取指定PID的句柄
        if dwProcessID <> 0 then
          //打开进程,需要PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限
          hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE,dwProcessID)
        else
        hProcess := GetCurrentProcess;
        //调用NtQueryInformationProcess获取结构信息
        ret := NtQueryInformationProcess(hProcess,0,@PBI,SizeOf(PBI),@r);
        //正常情况下ret是0,如果不是则认为错误
        if ret = 0 then
        begin
          //获取PEB结构
          ReadProcessMemory(hProcess,PBI.PebBaseAddress,PEBType,SizeOf(PEB),readByte);
          //获取PLD结构
          ReadProcessMemory(hProcess,PEBType.LoaderData,PLD,SizeOf(PEB_LDR_DATA),readByte);
          //获取第一个PME
          ReadProcessMemory(hProcess,PLD.InLoadOrderModuleList.Flink,PME,SizeOf(LDR_MODULE),readByte);
          //循环
          while True do
          begin
             //清零缓冲区
             ZeroMemory(PEBDLLName,Size);
             //读取buff到内存中,获取当前结构的DLL名
             if not ReadProcessMemory(hProcess,PME.BaseDllName.Buffer,PEBDLLName,PME.BaseDllName.Length,readByte) then Break;
             //对比DLL名称,不区分大小写
             if LowerCase(AnsiString(PEBDLLName)) = LowerCase(AnsiString(DllName)) then
             begin
               //调试信息
               OutputDebugStringW(PEBDLLName);
               //返回DLL的句柄
               Result := dword(pme.BaseAddress);
               //退出循环
               Break;
             end;
             //调试信息
             OutputDebugStringW(PEBDLLName);
             //如果下一个结构为开始的结构,则认为链表已经枚举完了
             if PME.InLoadOrderModuleList.Flink = PLD.InLoadOrderModuleList.Flink then Break;
             //读取下一个结构
             if not ReadProcessMemory(hProcess,PME.InLoadOrderModuleList.Flink,PME,SizeOf(LDR_MODULE),readByte) then Break;
          end;
        end
        else
        begin
          //返回错误信息
          OutputDebugStringW('Error!NtQueryInformationProcess Error!');
        end;
     finally
        //释放使用的内存
        FreeMem(PEBDLLName,Size);
        FreeMem(PME,SizeOf(LDR_MODULE));
        FreeMem(PLD,SizeOf(PEB_LDR_DATA));
        FreeMem(PEBType,SizeOf(PEB));
     end;
  end;
end.