Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exported DLL functions not ordered lexically?

Well, today I ran into an oddity. I wrote my own version of GetProcAddress a while ago to get function addresses from remote processes. I obviously spent quite a lot of time reading up on the PE architecture to figure out the best way to approach this.

From the PECOFF v8 specification (which, as I take it is the most up-to-date official specification), there is the following notation about the Export Name Pointer Table:

The export name pointer table is an array of addresses (RVAs) into the export name table. The pointers are 32 bits each and are relative to the image base. The pointers are ordered lexically to allow binary searches.

So I took this into account when writing my version of GetProcAddress. Obviously there would be a nice efficiency improvement in walking the export table in say...KERNEL32.dll (1300+ exported functions) using a binary search over a linear search.

This worked for a while until today when I ran into a weird issue. It appears that some of the exported functions in Kernel32 aren't actually ordered lexically and this was throwing off my binary search. The following is an excerpt from a Exported Dll dump using the function I'll post below:

Ordinal: 810    Name: K32QueryWorkingSetEx
Ordinal: 811    Name: LCIDToLocaleName
Ordinal: 812    Name: LCMapStringA
Ordinal: 813    Name: LCMapStringEx
Ordinal: 814    Name: LCMapStringW
Ordinal: 815    Name: LZClose
Ordinal: 816    Name: LZCloseFile
Ordinal: 817    Name: LZCopy
Ordinal: 818    Name: LZCreateFileW
Ordinal: 819    Name: LZDone
Ordinal: 820    Name: LZInit
Ordinal: 821    Name: LZOpenFileA
Ordinal: 822    Name: LZOpenFileW
Ordinal: 823    Name: LZRead
Ordinal: 824    Name: LZSeek
Ordinal: 825    Name: LZStart
Ordinal: 826    Name: LeaveCriticalSection
Ordinal: 827    Name: LeaveCriticalSectionWhenCallbackReturns
Ordinal: 828    Name: LoadAppInitDlls
Ordinal: 829    Name: LoadLibraryA
Ordinal: 830    Name: LoadLibraryExA

Anyone spot the issue here? Despite the documentation claiming that the export table is ordered lexically, LZRead is listed before LeaveCriticalSection.

I've always taken lexical ordering to be synonymous with alphabetical ordering when dealing with strings, am I wrong here or is there some weird issue with Kernel32's export table?

Function used to dump exports:

void DumpExports(PBYTE pBase)
{
    freopen("B:\\PeDump.txt", "wb", stdout);
    IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pBase;
    IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)(pBase + pDosHd->e_lfanew);
    IMAGE_DATA_DIRECTORY expDir = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    if (expDir.Size)
    {
        IMAGE_EXPORT_DIRECTORY *pExpDir = (IMAGE_EXPORT_DIRECTORY*)(pBase + expDir.VirtualAddress);
        WORD *pOrds = (WORD*)(pBase + pExpDir->AddressOfNameOrdinals);
        DWORD *pNames = (DWORD*)(pBase + pExpDir->AddressOfNames);

        for(unsigned long i = 0; i < pExpDir->NumberOfNames; i++, pOrds++, pNames++)
            printf("Ordinal: %d\tName: %s\n", *pOrds, (char*)(pBase + *pNames));
    }
    else
    {
        printf("No functions are exported from this image.\n");
    }
    fflush(stdout);
    freopen("CON", "w", stdout);
}

EDIT: I'm an idiot. Of course 'Z' is before 'o', It's 3am and my brain isn't functioning. Very sorry.

EDIT EDIT: Okay, I'm not totally insane. Half of the problem was that apparently C#'s string.CompareTo extension doesn't compare lexically.

For example

"LoadLibraryW".CompareTo("LZRead");

Returns "-1". This was the source of my confusion.

like image 452
Jason Larke Avatar asked Feb 20 '23 03:02

Jason Larke


1 Answers

LZRead is lexicographically before LeaveCriticalSection using ascii. Don't use case insensitivity and it looks like it will work.


An interesting observation about the documentation.

The pointers are 32 bits each ... are ordered lexically to allow binary searches.

It is hard to understand why one would do a binary search for a pointer (rather than a symbol name) but that is what is says.

like image 57
wallyk Avatar answered Feb 22 '23 17:02

wallyk