Advertisement
cakemaker

dumpster_ordinals.dll

May 28th, 2024 (edited)
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.30 KB | Science | 0 0
  1. //
  2. // dumpster_ordinals.cpp
  3. // https://pastebin.com/C3qcNMbh
  4. //
  5. // Compile via msvc:
  6. // cl /O2 /GS- /Brepro dumpster_ordinals.cpp /link /dll /nocoffgrpinfo /noentry /out:dumpster_ordinals.dll
  7. //
  8. // Self-test via rundll32:
  9. // rundll32.exe %__CD__%\dumpster_ordinals.dll,test
  10. //
  11.  
  12. #define _NO_CRT_STDIO_INLINE
  13.  
  14. #include <stdio.h>
  15. #include <Windows.h>
  16.  
  17.  
  18. #pragma comment(lib, "ntdllp")      // you might need wdk for this
  19. #pragma comment(lib, "user32")
  20. #pragma comment(lib, "kernel32")
  21.  
  22. #pragma execution_character_set("utf-8")
  23.  
  24.  
  25. // round 1
  26. #pragma comment(linker, "/export:A=advapi32.dll.#1212,@1")      // with dll extension (and we enforce our ordinal)
  27. #pragma comment(linker, "/export:B=advapi32.#+4294968508!")     // overflows uint32 into 1212
  28. // "advapi32.#▲ ♫1212*1337", linker directive quoted due to " "; RtlCharToInteger skips leading chars with ords <= 0x20
  29. #pragma comment(linker, "\"/export:C=advapi32.#\x1E \x0E" "1212*1337\"")
  30. #pragma comment(linker, "/export:D=advapi32.#-0x44FFFFFB44")    // overflows and then gets negated
  31.  
  32. // round 2
  33. #pragma comment(linker, "/export:E=advapi32.dll::$DATA.#1212")              // use ads streams (here unnamed default)
  34. #pragma comment(linker, "/export:F=C:\\windows\\system32\\advapi32.#1212")  // full path
  35. #pragma comment(linker, "/export:G=\\windows\\system32\\advapi32.#1212")    // ok only when current drive is C:
  36. #pragma comment(linker, "/export:H=C:advapi32.#1212")                       // 👎 doesn't work even if cwd is %system32%
  37.  
  38. // round 2 with editing own export (only coz msvc linker doesn't allow to build such file statically)
  39. #pragma comment(linker, "/export:J=dumpster_ordinals.#")           // 👎 means ordinal is 0; but 0 ordinal doesn't work
  40. #pragma comment(linker, "/export:K=dumpster_ordinals.#0x13370001") // not an overflow(!): ok when ordinalBase 0x13370001
  41.  
  42. // for rundll32.exe test
  43. #pragma comment(linker, "/export:test")
  44. #pragma comment(linker, "/alternatename:test=_test@16") // needed for x32 only
  45.  
  46.  
  47. extern "C"
  48. IMAGE_DOS_HEADER __ImageBase;    // linker-defined
  49.  
  50.  
  51. static void test_round2()
  52. {
  53.     HMODULE ownImage = (HMODULE)&__ImageBase;
  54.  
  55.     char funcName[2]{"E"};
  56.     void* funcs[6];
  57.     for (int i = 0; i < _countof(funcs); ++i, ++funcName[0])
  58.         funcs[i] = GetProcAddress(ownImage, funcName);
  59.  
  60.     // prepare to edit our own export table, to change ordinal base first to 0, and then to 0x13370001;
  61.     // it doesn't have to be edited dynamically, it's just msvc linker doesn't allow us to build it statically
  62.     auto* peHeader = (const IMAGE_NT_HEADERS*)(PBYTE(ownImage) + __ImageBase.e_lfanew);
  63.     UINT exportRva = peHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  64.     auto* exports = (IMAGE_EXPORT_DIRECTORY*)(PBYTE(ownImage) + exportRva);
  65.     ULONG dummyOldProtect;
  66.     VirtualProtect(exports, sizeof(*exports), PAGE_READWRITE, &dummyOldProtect);
  67.     UINT origOrdinalBase = exports->Base;
  68.  
  69.     void* funcsX[2];
  70.     exports->Base = 0;          // 'J' still won't resolve, but only because LdrpGetProcedureAddress bans ordinal 0
  71.     funcsX[0] = GetProcAddress(ownImage, "J");
  72.     exports->Base = 0x13370001; // 'K' should resolve now
  73.     funcsX[1] = GetProcAddress(ownImage, "K");
  74.     // note if module has OrdinalBase larger than 0xFFFF in its export table, you won't be able to resolve any of its
  75.     // funcs by ordinals via GetProcAddress; however, you can use native ntdll!LdrGetProcedureAddressForCaller for that
  76.     exports->Base = origOrdinalBase;
  77.  
  78.     wchar_t buf[0x740];
  79.     swprintf_s(buf, _countof(buf),
  80. LR"(Secret round2 discovered!
  81.  
  82.  
  83. %p  "E" > advapi32.dll::$DATA.#1212
  84. %p  "F"
  85.     > C:\windows\system32\advapi32.#1212
  86.  
  87. %p  "G"
  88.     > \windows\system32\advapi32.#1212
  89. should work iff "C:" is current drive
  90.  
  91. %p  "H" > C:advapi32.#1212
  92. does NOT work even if %%system32%% is cwd
  93.  
  94. %p  "J" > dumpster_ordinals.#
  95. %p  "J" > dumpster_ordinals.#
  96. ^ OrdinalBase is 0 - still does NOT work
  97.  
  98. %p  "K" > dumpster_ordinals.#0x13370001
  99. %p  "K" > dumpster_ordinals.#0x13370001
  100. ^ OrdinalBase is 0x13370001 - should work okay)",
  101.         funcs[0], funcs[1], funcs[2], funcs[3],
  102.         funcs[4], funcsX[0],
  103.         funcs[5], funcsX[1]);
  104.  
  105.     MessageBoxW({}, buf, L"dumpster ordinals", MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);
  106. }
  107.  
  108.  
  109. extern "C"
  110. void __stdcall test(HWND, HINSTANCE, LPSTR, int)
  111. {
  112.     void* funcs[4];
  113.     char funcName[2]{"A"};
  114.     unsigned exportsResolved = 0;
  115.     for (int i = 0; i < _countof(funcs); exportsResolved += !!funcs[i], ++i, ++funcName[0])
  116.         funcs[i] = GetProcAddress((HMODULE)&__ImageBase, funcName);
  117.    
  118.     // may only retrieve image base like that once we've resolved forwarded exports
  119.     HMODULE advapi = GetModuleHandleA("advapi32");
  120.     void* testFuncs[3]{};
  121.     if (advapi)
  122.     {
  123.         testFuncs[0] = GetProcAddress(advapi, "CryptGenRandom");
  124.         testFuncs[1] = GetProcAddress(advapi, (LPCSTR)1212);
  125.         testFuncs[2] = GetProcAddress(advapi, (LPCSTR)1213);
  126.     }
  127.  
  128.     wchar_t buf[0x400];
  129.     swprintf_s(buf, _countof(buf),
  130. LR"(%p  advapi32.dll
  131. %p  dumpster_ordinals.dll
  132.  
  133. ------------------------------------------------
  134. Sanity test; exports resolved via
  135. GetProcAddress(advapi32):
  136.  
  137. %p  "CryptGenRandom"
  138. %p  #1212
  139. %p  #1213
  140. ------------------------------------------------
  141.  
  142.  
  143. ------------------------------------------------
  144. Actual test; exports resolved via
  145. GetProcAddress(dumpster_ordinals):
  146.  
  147. %p  "A" > advapi32.dll.#1212
  148. %p  "B" > advapi32.#+4294968508!
  149. %p  "C" > advapi32.#▲ ♫1212*1337
  150. %p  "D" > advapi32.#-0x44FFFFFB44
  151. ------------------------------------------------
  152.  
  153.  
  154. RESULT: %u/4 weird exports resolved.)",
  155.         advapi, &__ImageBase,
  156.         testFuncs[0], testFuncs[1], testFuncs[2],
  157.         funcs[0], funcs[1], funcs[2], funcs[3], exportsResolved);
  158.  
  159.     // Note we cheat a bit with visual representation of variant C - we use higher Unicode chars. That doesn't affect
  160.     // our export table, sequence "\x1E\x20\x0E" there still consists of just 3 bytes.         !▲ ♫!  << Unicode
  161.     // This comment line contains actual lower ansi chars just to test your environment.       ! !  << Ansi
  162.     int rez = MessageBoxW({}, buf, L"dumpster ordinals",
  163.         MB_CANCELTRYCONTINUE|MB_DEFBUTTON2|MB_ICONINFORMATION|MB_SETFOREGROUND);
  164.     if (rez == IDTRYAGAIN)
  165.         test_round2();
  166. }
  167.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement