title: Exported DLL functions not ordered lexically?
body: <p>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. </p>
  
  <p>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 <code>Export Name Pointer Table</code>:</p>
  
  <blockquote>
    <p>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.</p>
  </blockquote>
  
  <p>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.</p>
  
  <p>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:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Anyone spot the issue here? Despite the documentation claiming that the export table is ordered lexically, LZRead is listed before LeaveCriticalSection.</p>
  
  <p>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?</p>
  
  <p><strong>Function used to dump exports:</strong></p>
  
  <pre><code>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-&gt;e_lfanew);
      IMAGE_DATA_DIRECTORY expDir = pNtHd-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
      if (expDir.Size)
      {
          IMAGE_EXPORT_DIRECTORY *pExpDir = (IMAGE_EXPORT_DIRECTORY*)(pBase + expDir.VirtualAddress);
          WORD *pOrds = (WORD*)(pBase + pExpDir-&gt;AddressOfNameOrdinals);
          DWORD *pNames = (DWORD*)(pBase + pExpDir-&gt;AddressOfNames);
  
          for(unsigned long i = 0; i &lt; pExpDir-&gt;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);
  }
  </code></pre>
  
  <p>EDIT: I'm an idiot. Of course 'Z' is before 'o', It's 3am and my brain isn't functioning. Very sorry.</p>
  
  <p>EDIT EDIT: Okay, I'm not totally insane. Half of the problem was that apparently C#'s string.CompareTo extension doesn't compare lexically.</p>
  
  <p>For example</p>
  
  <pre><code>"LoadLibraryW".CompareTo("LZRead");
  </code></pre>
  
  <p>Returns "-1". This was the source of my confusion.</p>