Конференция "WinAPI" » Аналог GetProcAddress
 
  • Deniska © (12.12.11 08:27) [0]
    Приветствую!
    Есть функция:

    procedure ListDLLExports(FileName: String);
    type
     TDWordArray = array [0..$FFFFF] of DWORD;
    var
     Name: String;
     i, dirsize: Cardinal;
     imageinfo: LoadedImage;
     pNameRVAs: ^TDWordArray;
     pDummy: PImageSectionHeader;
     pExportDirectory: PImageExportDirectory;
    begin
     if MapAndLoad(PChar(FileName), nil, @imageinfo, True, True) then
     begin
       try
         pExportDirectory := ImageDirectoryEntryToData(imageinfo.MappedAddress,
                                                       False,
                                                       IMAGE_DIRECTORY_ENTRY_EXPORT,
                                                       dirsize);
         if (pExportDirectory <> nil) then
         begin
           pNameRVAs := ImageRvaToVa(imageinfo.FileHeader, imageinfo.MappedAddress,
                                     DWORD(pExportDirectory^.AddressOfNames),
                                     pDummy);
           for i := 0 to pExportDirectory^.NumberOfNames - 1 do
           begin
             Name := PChar(ImageRvaToVa(imageinfo.FileHeader,
                                        imageinfo.MappedAddress,
                                        pNameRVAs^[i], pDummy));

             Show(Name);
           end;
         end;
       finally
         UnMapAndLoad(@imageinfo);
       end;
     end;
    end;


    Показывает список экспортируемых функций у длл.
    Хочу переписать ее в таком виде:
    function ListDLLExports(FileName, ProcName: String): Pointer;
    Чтобы результат ее выполнения был такой же как у GetProcAddress. Подскажите пожалуйста как это сделать :)
  • Deniska © (12.12.11 08:30) [1]
    Основная сложность: Не знаю откуда вытащить адресс функции.
    Предполагаю что из этой структуры:
     PImageExportDirectory = ^TImageExportDirectory;
     _IMAGE_EXPORT_DIRECTORY = packed record
         Characteristics: DWord;
         TimeDateStamp: DWord;
         MajorVersion: Word;
         MinorVersion: Word;
         Name: DWord;
         Base: DWord;
         NumberOfFunctions: DWord;
         NumberOfNames: DWord;
         AddressOfFunctions: ^PDWORD;
         AddressOfNames: ^PDWORD;
         AddressOfNameOrdinals: ^PWord;
     end;


    Подскажите пожалуйста :)
  • Rouse_ © (12.12.11 10:57) [2]
    program Project1;

    {$APPTYPE CONSOLE}

    uses
     Windows,
     SysUtils;

    var
     FuncName: AnsiString;
     pNtHeaders: PImageNtHeaders;
     ExportAddr: TImageDataDirectory = (VirtualAddress: 0; Size: 0);
     ImageBase: DWORD;
     IED: PImageExportDirectory;
     I: Integer;
     FuntionAddr: DWORD;
     NamesCursor: PDWORD;
     OrdinalCursor: PWORD;
     Ordinal: DWORD;

    begin
     ImageBase := GetModuleHandle('NTDLL.DLL');

     if PWORD(ImageBase)^ = IMAGE_DOS_SIGNATURE then
     begin
       // проверка заголовков
       pNtHeaders := Pointer(ImageBase + DWORD(PImageDosHeader(ImageBase)^._lfanew)
         );
       ExportAddr.VirtualAddress := 0;
       ExportAddr.Size := 0;
       if (pNtHeaders^.Signature = IMAGE_NT_SIGNATURE) and
         (pNtHeaders^.FileHeader.Machine = IMAGE_FILE_MACHINE_I386) then
       begin
         // получаем указатель на таблицу экспорта
         ExportAddr := pNtHeaders.OptionalHeader.DataDirectory
           [IMAGE_DIRECTORY_ENTRY_EXPORT];
         if ExportAddr.VirtualAddress <> 0 then
           Inc(ExportAddr.VirtualAddress, ImageBase)
         else
           ExportAddr.Size := 0;
       end;
     end;

     if (ImageBase = 0) or (ExportAddr.VirtualAddress = 0) then
       Exit;
     IED := PImageExportDirectory(ExportAddr.VirtualAddress);
     I := 1;
     NamesCursor := Pointer(ImageBase + DWORD(IED^.AddressOfNames));
     OrdinalCursor := Pointer(ImageBase + DWORD(IED^.AddressOfNameOrdinals));
     while I < Integer(IED^.NumberOfNames) do
     begin
       // получаем имя функции
       FuncName := PAnsiChar(ImageBase + PDWORD(NamesCursor)^);
       // Смотрим номер функции в таблице ординалов
       Ordinal := OrdinalCursor^ + IED^.Base;
       // Через ординал вычисляем реальный адрес функции
       FuntionAddr := ImageBase + DWORD(IED^.AddressOfFunctions);
       FuntionAddr := ImageBase + PDWORD(FuntionAddr + (Ordinal - 1) * 4)^;
       Writeln(FuncName, ' proc addr: 0x', IntToHex(FuntionAddr, 8));
       Inc(I);
       Inc(NamesCursor);
       Inc(OrdinalCursor);
     end;
     Readln;

    end.

  • P (12.12.11 11:41) [3]
    uses ImageHlp, PsAPI;

    {$R *.dfm}

    function _GetKernel32BaseAddress(ProcessHandle: THandle): Integer;
    const
     MM_USER_PROBE_ADDRESS = $7FFF0000;
    var
     Address: THandle;
     Buffer: TMemoryBasicInformation;
     Length: DWORD;
     FileName: array [0 .. MAX_PATH - 1] of WideChar;
     LoadLibraryBaseAddress: Integer;
    begin
     Result := 0;
     Address := 0;
     Length := Sizeof(TMemoryBasicInformation);
     if VirtualQueryEx(ProcessHandle, Pointer(Address), Buffer, Length) = Length then
     begin
       while Address < MM_USER_PROBE_ADDRESS do
       begin
         if VirtualQueryEx(ProcessHandle, Pointer(Address), Buffer, Length) = Length then
         begin
           Inc(Address, Buffer.RegionSize);
           if GetMappedFileNameW(ProcessHandle, Buffer.BaseAddress, @FileName[0], MAX_PATH) > 0 then
           begin
             if LowerCase(ExtractFileName(FileName)) = 'kernel32.dll' then
             begin
               Result := Integer(Buffer.BaseAddress);
               Break;
             end;
           end;
         end;
       end;
     end;
    end;

    function _GetLoadLibraryWAddress: Integer;
    type
     TDWordArray = array [0 .. $FFFFF] of DWORD;
    var
     i: Cardinal;
     ImageInfo: LoadedImage;
     ImageExportDirectory: PImageExportDirectory;
     ImageDirectorySize: ULONG;
     LastRvaSection: PImageSectionHeader;
     RvaAddressOfNames, RvaAddressOfFunctions: ^TDWordArray;
     RvaAddressOfNameOrdinals: ^TWordArray;
     LabraryName: string;
     Ordinal: Word;
    begin
     Result := 0;
     if MapAndLoad('C:\WINDOWS\system32\kernel32.dll', nil, @ImageInfo, True, True) then
     begin
       try
         ImageExportDirectory := ImageDirectoryEntryToData(ImageInfo.MappedAddress, False, IMAGE_DIRECTORY_ENTRY_EXPORT, ImageDirectorySize);
         if (ImageExportDirectory <> nil) then
         begin
           RvaAddressOfNames := ImageRvaToVa(ImageInfo.FileHeader, ImageInfo.MappedAddress, DWORD(ImageExportDirectory^.AddressOfNames), LastRvaSection);
           RvaAddressOfNameOrdinals := ImageRvaToVa(ImageInfo.FileHeader, ImageInfo.MappedAddress, DWORD(ImageExportDirectory^.AddressOfNameOrdinals), LastRvaSection);
           RvaAddressOfFunctions := ImageRvaToVa(ImageInfo.FileHeader, ImageInfo.MappedAddress, DWORD(ImageExportDirectory^.AddressOfFunctions), LastRvaSection);
           for i := 0 to ImageExportDirectory^.NumberOfNames - 1 do
           begin
             LabraryName := PChar(ImageRvaToVa(ImageInfo.FileHeader, ImageInfo.MappedAddress, RvaAddressOfNames^[i], LastRvaSection));
             if LowerCase(LabraryName) = 'loadlibraryw' then
             begin
               // Ordinal := RvaAddressOfNameOrdinals^[i]; //Ordinal
               Result := (RvaAddressOfFunctions^[i]);
               Break;
             end;
           end;
         end;
       finally
         UnMapAndLoad(@ImageInfo);
       end;
     end;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     ProcessHandle: THandle;
     Address: Integer;
    begin
     ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, True, GetCurrentProcessId);
     Address := _GetLoadLibraryWAddress;
     if Address > 0 then
       Caption := IntToHex(_GetKernel32BaseAddress(ProcessHandle) + Address, 0);
     Caption := Caption + ' / ' + IntToHex(Integer(GetModuleHandleW('kernel32.dll')) + Address, 0);
     Caption := Caption + ' / ' + IntToHex(Integer(GetProcAddress(GetModuleHandleW('kernel32.dll'), 'LoadLibraryW')), 0);
     {
       Странно так EAccessViolation
       Caption := IntToHex(_GetKernel32BaseAddress(ProcessHandle) + _GetLoadLibraryWAddress, 0);
     }


     if ProcessHandle <> 0 then
       CloseHandle(ProcessHandle);
    end;

  • Deniska © (12.12.11 15:08) [4]
    Спасибо за помощь, все работает прекрасно! :)
  • Deniska © (13.12.11 14:40) [5]
    Еще один вопрос, по поводу кода от Rouse_
    Как переделать код с учетом:
    Однако полученный адрес м.б. ссылкой на имя функции из другой dll (forwarded экспорт), поэтому нужно еще проверить - если полученный адрес лежит за пределами таблицы экспорта, то это реальный адрес экспортируемой функции, если же внутри, то это указатель на составное имя - например, в kernel32 адрес ф-ии HeapAlloc даст ссылку не на саму ф-ю, а на строку "ntdll.RtlAllocateHeap"
  • Rouse_ © (13.12.11 16:32) [6]

    >  например, в kernel32 адрес ф-ии HeapAlloc даст ссылку не
    > на саму ф-ю, а на строку "ntdll.RtlAllocateHeap"

    Хм, да - не учел я этот момент:

    program Project1;

    {$APPTYPE CONSOLE}

    uses
     Windows,
     SysUtils;

    var
     FuncName: AnsiString;
     pNtHeaders: PImageNtHeaders;
     ExportAddr: TImageDataDirectory = (VirtualAddress: 0; Size: 0);
     ImageBase: DWORD;
     IED: PImageExportDirectory;
     IID: DWORD;
     I: Integer;
     FuntionAddr: DWORD;
     NamesCursor: PDWORD;
     OrdinalCursor: PWORD;
     Ordinal: DWORD;
    begin
     ImageBase := GetModuleHandle('kernel32.DLL');
     if ImageBase < HINSTANCE_ERROR then Exit;

     IID := 0;

     if PWORD(ImageBase)^ = IMAGE_DOS_SIGNATURE then
     begin
       // проверка заголовков
       pNtHeaders := Pointer(ImageBase + DWORD(PImageDosHeader(ImageBase)^._lfanew));
       ExportAddr.VirtualAddress := 0;
       ExportAddr.Size := 0;
       if (pNtHeaders^.Signature = IMAGE_NT_SIGNATURE) and
         (pNtHeaders^.FileHeader.Machine = IMAGE_FILE_MACHINE_I386) then
       begin
         // получаем указатель на таблицу экспорта
         ExportAddr := pNtHeaders.OptionalHeader.DataDirectory
           [IMAGE_DIRECTORY_ENTRY_EXPORT];
         IID :=
           pNtHeaders.OptionalHeader.DataDirectory[
             IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + ImageBase;
         if ExportAddr.VirtualAddress <> 0 then
           Inc(ExportAddr.VirtualAddress, ImageBase);
       end;
     end;

     if ExportAddr.VirtualAddress = 0 then Exit;

     IED := PImageExportDirectory(ExportAddr.VirtualAddress);
     I := 1;
     NamesCursor := Pointer(ImageBase + DWORD(IED^.AddressOfNames));
     OrdinalCursor := Pointer(ImageBase + DWORD(IED^.AddressOfNameOrdinals));
     while I < Integer(IED^.NumberOfNames) do
     begin
       // получаем имя функции
       FuncName := PAnsiChar(ImageBase + PDWORD(NamesCursor)^);
       // Смотрим номер функции в таблице ординалов
       Ordinal := OrdinalCursor^ + IED^.Base;
       // Через ординал вычисляем реальный адрес функции
       FuntionAddr := ImageBase + DWORD(IED^.AddressOfFunctions);
       FuntionAddr := ImageBase + PDWORD(FuntionAddr + (Ordinal - 1) * 4)^;
       if (FuntionAddr > ExportAddr.VirtualAddress) and (FuntionAddr <= IID) then
         Writeln(FuncName, ' forwarded -> ', PAnsiChar(FuntionAddr))
       else
         Writeln(FuncName, ' proc addr: 0x', IntToHex(FuntionAddr, 8));
       Inc(I);
       Inc(NamesCursor);
       Inc(OrdinalCursor);
     end;
     Readln;

    end.

  • Deniska © (14.12.11 02:12) [7]
    Спасибо! :)

    Кстати, вот еще один из вариантов решений, возможно кому то будет полезно:

    function GetAddr(szDll, szFunc: PChar): Pointer;
    var
     s: String;
     NamesCursor: PDWORD;
     OrdinalCursor: PWORD;
     IED: PImageExportDirectory;
     pNtHeaders: PImageNtHeaders;
     ExportAddr: TImageDataDirectory;
     i, j, Ordinal, FuntionAddr, ImageBase: Dword;
    begin
     Result := nil;
     ZeroMemory(@ExportAddr, SizeOf(ExportAddr));
     ImageBase := GetModuleHandle(szDll);
     if PWORD(ImageBase)^ = IMAGE_DOS_SIGNATURE then
     begin
       pNtHeaders := Pointer(ImageBase + DWORD(PImageDosHeader(ImageBase)^._lfanew));
       if (pNtHeaders^.Signature = IMAGE_NT_SIGNATURE) and
          (pNtHeaders^.FileHeader.Machine = IMAGE_FILE_MACHINE_I386) then
       begin
         ExportAddr := pNtHeaders.OptionalHeader.DataDirectory
                       [IMAGE_DIRECTORY_ENTRY_EXPORT];
         if ExportAddr.VirtualAddress <> 0 then
            Inc(ExportAddr.VirtualAddress, ImageBase)
         else ExportAddr.Size := 0;
       end;
     end;
     if (ImageBase = 0) or (ExportAddr.VirtualAddress = 0) then Exit;
     IED := PImageExportDirectory(ExportAddr.VirtualAddress);
     i := 1;
     NamesCursor := Pointer(ImageBase + DWORD(IED^.AddressOfNames));
     OrdinalCursor := Pointer(ImageBase + DWORD(IED^.AddressOfNameOrdinals));
     while i < Dword(IED^.NumberOfNames) do
     begin
       Ordinal := OrdinalCursor^ + IED^.Base;
       FuntionAddr := ImageBase + DWORD(IED^.AddressOfFunctions);
       FuntionAddr := ImageBase + PDWORD(FuntionAddr + (Ordinal - 1) * 4)^;
       if lstrcmpi(szFunc, PAnsiChar(ImageBase + PDWORD(NamesCursor)^)) = 0 then
       begin
         if (FuntionAddr > ExportAddr.VirtualAddress) and
             //&#229;&#241;&#235;&#232; &#224;&#228;&#240;&#229;&#241; &#226;&#237;&#243;&#242;&#240;&#232; &#253;&#234;&#241;&#239;&#238;&#240;&#242;&#224;, &#242;&#238; &#253;&#242;&#238; forwarded
            (FuntionAddr < ExportAddr.VirtualAddress + ExportAddr.Size) then
         begin
           s := PAnsiChar(FuntionAddr); //&#241;&#242;&#240;&#238;&#234;&#224; &#226;&#232;&#228;&#224; ntdll.RtlAllocateHeap
           j := Pos('.', s);
           if j > 0 then
           begin
             s[j] := #0; //&#240;&#224;&#231;&#225;&#232;&#226;&#224;&#229;&#236; &#237;&#224; ntdll &#232; RtlAllocateHeap
             Result := GetAddr(@s[1], @s[j + 1]); //&#226;&#251;&#231;&#251;&#226;&#224;&#229;&#236; &#253;&#242;&#243; &#230;&#229; &#244;&#243;&#237;&#234;&#246;&#232;&#254; &#228;&#235;&#255; &#238;&#239;&#240;&#229;&#228;&#229;&#235;&#229;&#237;&#232;&#255; &#224;&#228;&#240;&#229;&#241;&#224;
           end;
         end
         else Result := Pointer(FuntionAddr);
         Break; //&#240;&#224;&#231; &#243;&#230;&#229; &#237;&#224;&#248;&#235;&#232;, &#242;&#238; &#226;&#251;&#245;&#238;&#228;&#232;&#236; &#232;&#231; &#246;&#232;&#234;&#235;&#224;
       end;
       Inc(i);
       Inc(NamesCursor);
       Inc(OrdinalCursor);
     end;
    end; //GetAddr

 
Конференция "WinAPI" » Аналог GetProcAddress
Есть новые Нет новых   [134431   +6][b:0][p:0.009]