Exetools

Exetools (https://forum.exetools.com/index.php)
-   General Discussion (https://forum.exetools.com/forumdisplay.php?f=2)
-   -   Get APi from the address (https://forum.exetools.com/showthread.php?t=13319)

ahmadmansoor 02-25-2011 08:52

Get APi from the address
 
we always do this to get the API addresss

GetAPIAddress = GetProcAddress(GetModuleHandle("Kernel.dll),FunctionName)

to get the Address of the API .
but what the programmatic way to get the API of the address .
like if we have this :
Quote:

2FEB1344 >7611FC28 (��v kernel32.LockFile
if I have 2FEB1344 how I could know for which API it relative too !!

( I need the reverse way of GetProcAddress )
Thanks in adv

Nacho_dj 02-25-2011 14:55

Since it is a handle in memory and it is linked to the imagebase of its module loaded by the system, you need:
- Getting all processes loaded in memory, thus retrieving their imagebase and size, their module name, and so on...
- Determining which process the handle belongs to, getting in this way the module that is exporting it.
- Go analyzing export table of that module to find the handle (in RVA), and then get the function name, if this exists in the functions names table. Ordinal can always be retrieved.
- If there is forwarding, you should try to find which is the module that is the origin of forward, to get the function name inside it.

Cheers

Nacho_dj

ahmadmansoor 02-25-2011 19:35

Thanks Nacho_dj ....
This idea have come to my mind . but I note that it could make this process take a lot of time ..
I have check "Import REConstructor" and "CHimpREC"
and I have note that "Import REConstructor" didn't take the time which "CHimpREC" take it .
it is more faster .
so is there fast way to get this or it will depended on the algorithm of the code it self !!
Thanks for replay

Nacho_dj 02-25-2011 20:19

Yeah, it depends strongly of the algo used and the way of accessing files.

I have checked that, for instance, some tools load in memory the content of an entire file, whilst other just load the section of the file needed, so it will get much faster because of managing less memory space.

If you need more detailed data I could post it here...

Cheers

Nacho_dj

ahmadmansoor 02-25-2011 20:44

Quote:

If you need more detailed data I could post it here...
yes pls .....
many thanks

Nacho_dj 02-26-2011 03:36

How to retrieve every function name in a loaded application (executable or dll) - Part I

I have used Delphi code to implement this, so pseudocode will be near to Delphi...

1. Create an instance of tagMODULEENTRY32:

tagMODULEENTRY32.dwSize := SizeOf(MODULEENTRY32);

2. Get process information inside the sanapshot:
hSnapShot := CreateToolHelp32SnapShot(TH32CS_SNAPMODULE,lpProcessInformation.dwProcessId);

3. Retrieve first module loaded in your process:
Module32First(hSnapShot,tagMODULEENTRY32)

If the function succeeds, you have got some module information, like this:
tagMODULEENTRY32.modBaseAddr
tagMODULEENTRY32.modBaseSize

Store it in an struct inside an array, and then, start a loop to get the others processes info:
Module32Next(hSnapShot,tagMODULEENTRY32)
If the function succeeds, you have got several module information, like this:
tagMODULEENTRY32.modBaseAddr
tagMODULEENTRY32.modBaseSize

The loop ends when the previous function doesn't succeed.

4. For everyone of the modules previously stored in your array, get the export table. This will be used later.
You just need to read PE header, and get the export table rva & size from data directories.

Get the IMAGE_EXPORT_DIRECTORY structure and store it in an array for every process loaded.

5. Get the import table addresses minimum and maximum bounds. There could be several methods to do it. I prefer reading the entire code section and get all references to imported functions by analyzing every opcode like this table shows:
Code:

FF35 | PUSH [virtual address]
A1  | MOV EAX,[virtual address]
8B0D | MOV ECX,[virtual address]
8B15 | MOV EDX,[virtual address]
8B1D | MOV EBX,[virtual address]
8B25 | MOV ESP,[virtual address]
8B2D | MOV EBP,[virtual address]
8B35 | MOV ESI,[virtual address]
8B3D | MOV EDI,[virtual address]
FF15 | CALL [virtual address]
FF25 | JMP [virtual address]

For everyone of the addresses, validate that it is inside memory of your main process, then get the handle, and then try to find its function name or ordinal, as follows. If you succeed, it belongs to IAT. Get with a clever algo this:
Mimimum IAT address RVA
Maximum IAT address RVA

For every iteration, you only need to validate that a handle is valid if the RVA of the handle is out of minimum and maximum RVA previosly computed.


To find a valid handle for imported function, first check in a loop that it belongs to any of the processes loaded:

Code:

for i := 0 to Length(TableProcess) - 1 do
        if (hndFunc > TableProcess[i].modBaseAddr) AND
          (hndFunc < (TableProcess[i].modBaseAddr + TableProcess[i].modBaseSize)) then
begin
  GetFunctionNameAndOrdinal(...)
end;

To be continued... ;)

Nacho_dj

ahmadmansoor 02-26-2011 04:32

Thanks Nacho_dj ,,, very nice explanation .
I will wait the continue .

D-Jester 02-26-2011 09:18

This might be useful

http://www.masm32.com/board/index.php?topic=5996.0

Fyyre 02-26-2011 09:34

You want custom GetProcAddress?

Code:

PVOID FastGetProcAddress(PCHAR DllBase, PCHAR RoutineName)
{
        USHORT OrdinalNumber;
        PULONG NameTableBase;
        PUSHORT NameOrdinalTableBase;
        PULONG Addr;
        ULONG High;
        ULONG Low;
        ULONG Middle;
        LONG Result;
        ULONG ExportSize;
        PVOID FunctionAddress;
        PIMAGE_EXPORT_DIRECTORY ExportDirectory;


        ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
                RtlImageDirectoryEntryToData(DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
        NameTableBase = (PULONG)(DllBase + (ULONG)ExportDirectory->AddressOfNames);
        NameOrdinalTableBase = (PUSHORT)(DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);
        Low = 0;
        High = ExportDirectory->NumberOfNames - 1;
        while (High >= Low)
        {
                Middle = (Low + High) >> 1;
                Result = strcmp(RoutineName,
                                                (PCHAR)(DllBase + NameTableBase[Middle]));
                if (Result < 0)
                {
                        High = Middle - 1;
                }
                else if (Result > 0)
                {
                        Low = Middle + 1;
                }
                else
                {
                        break;
                };
        };
        if (High < Low)
        {
                return NULL;
        };
        OrdinalNumber = NameOrdinalTableBase[Middle];
        if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions)
        {
                return NULL;
        };
        Addr = (PULONG)(DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
        FunctionAddress = (PVOID)(DllBase + Addr[OrdinalNumber]);
        return FunctionAddress;
};

Quote:

Originally Posted by ahmadmansoor (Post 71697)
we always do this to get the API addresss

GetAPIAddress = GetProcAddress(GetModuleHandle("Kernel.dll),FunctionName)

to get the Address of the API .
but what the programmatic way to get the API of the address .
like if we have this :


if I have 2FEB1344 how I could know for which API it relative too !!

( I need the reverse way of GetProcAddress )
Thanks in adv


ahmadmansoor 02-27-2011 20:53

Thanks D-Jester and Fyyre ...
but what i mean that I have the address memory , and I want to know which API related to this address memory .
that what I mean .
@ Fyyre : thanks for nice code ... easy and can be useful .
in ur code it need this too ;)
Quote:

PVOID NTAPI RtlImageDirectoryEntryToData ( PVOID BaseAddress,
BOOLEAN MappedAsImage,
USHORT Directory,
PULONG Size
) ;

dila 02-28-2011 03:31

It sounds like he wants reverse GetProcAddress. Like the sort of code "analysis" you find next to CALL instructions in OllyDbg.

I've been looking at doing this for adding details to beaengine output and it goes like this:
  • Subtract the CALL RVA back to the image base.
  • Then subtract it back to the import library FirstThunk base address (remember there are two IAT arrays for each module, the file one and the one that is fixed up at runtime). Divide by the sizeof each element (DWORD) to make it into a 0...N index into the IAT array.
  • Use that index to get the import name out of the library names array.
  • Then the code builds an OllyDbg style "Library.Func" or "Library.#Ordinal" string for asm comment.

Code:

QString importFromRva( const PeFile *peFile, uint64_t addr )
{
    if ( addr )
    {
        addr -= peFile->imageBase();
        addr = addr;

        for ( uint32_t lib = 0; lib < peFile->importLibraryCount(); ++lib )
        {
            PeFile::ImportLibrary library;
            if ( !peFile->importLibrary(&library,lib) )
            {
                continue;
            }

            uint32_t offset = addr - library.;

            offset /= sizeof(DWORD);

            if ( offset < peFile->importAddressCount(&library) )
            {
                PeFile::ImportAddress address;
                if ( peFile->importAddress(&address,&library,offset) )
                {
                    if ( address.name )
                    {
                        return QString(library.name).toUpper() + QString(".") + QString(address.name);
                    }
                    else // by ordinal
                    {
                        return QString(library.name).toUpper() + QString(".#") + QString::number(address.ordinal,16);
                    }
                }
            }
        }

    }

    return QString();
}


dila 02-28-2011 03:49

1 Attachment(s)
see attached: proof of concept screenshot ;)

ahmadmansoor 02-28-2011 08:33

Thanks dila .... I will try it .
and I will back with result .
Thanks in adv ..

BoB 02-28-2011 14:38

Ah but Dila, that only works if the Imports.OrigFirstThunk array is valid ;)

Code:

//-----------------------------------------------------------------------//
// Get Api Name from address ..  (Reverse GetProcAddress)

Function  GetProcAddressName(Const ApiAddress : DWord) : String;
Var
  I,
  Base,                        // Module base address ..
  Rva : DWord;                  // Rva of Api ..
  FA,                          // Pointer to Functions Array ..
  NA  : PDWord;                // Pointer to Names Array ..
  Exp : PImageExportDirectory;  // Export Table ..
  Dos : PImageDosHeader;        // Dos Header ..
  Nt  : PImageNtHeaders;        // Nt Headers ..
Begin
  Result := 'Error';

  // Calc module base address from API address ..
  Base := ApiAddress;
  Repeat
    NT := Nil;
    Dec(Base);
    Base := Base And $FFFFF000;  // Align to page size ..
    If (Not IsBadReadPtr(Pointer(Base), 4)) Then Begin
      Dos := Pointer(Base);
      If (Dos^.Magic = IMAGE_DOS_SIGNATURE) Then Nt := Pointer(Base + Dos^.OffsetPE);
    End;
  Until (Not IsBadReadPtr(NT, 4)) And (NT^.Signature = IMAGE_NT_SIGNATURE);

  // Search for the Rva in the Function Array of the export table ..
  Exp := Pointer(Base + NT^.OptionalHeader.DataDirectory[0].Rva);
  Rva := ApiAddress - Base;
  FA  := Pointer(Base + Exp^.RvaOfFunctions);
  NA  := Pointer(Base + Exp^.RvaOfNames);
  For I := 0 To Exp^.NumberOfFunctions-1 Do Begin
    If (Rva = FA^) Then Begin
      // Return name or ordinal string ..
      Result := PAnsiChar(Base + Exp^.Name) + '!';
      If (I < Exp^.NumberOfNames) Then Result := Result + PAnsiChar(Base + NA^)
      Else Result := Result + '#' + IntToStr(Exp^.Base + I);
      Break;
    End;
    Inc(FA);
    Inc(NA);
  End;
End;

Simple usage like this:
Code:

  Api := DWord(GetProcAddress(KernelBase, 'HeapCreate'));
  MessageBox(0, PChar(GetProcAddressName(Api)), Nil, MB_OK);

Would show:
Code:

KERNEL32.dll!HeapCreate
Ahmadmansoor: If you want it rewriting in Asm or anything let me know.

Excuse any weird code, it's 6:30 am and I need to sleep :)
BoB

V0ldemAr 02-28-2011 22:02

1 Attachment(s)
My implementation in CPP, Use VirtualQuery to get module base and check if it's really module then parse export table and get api name or ordinal. PS: Code is old and may contain bugs was fastly coded few years ago :)


All times are GMT +8. The time now is 15:09.

Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2026, vBulletin Solutions, Inc.
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX