Da Li’L World of DLL Exports and Entry Points, Part 4

Looong time ago I wrote a couple of posts about DLLs and their exports. I decided to return to this series as I have some new notes jotted down about the subject…

The extraordinary way we can run Rundll32 with ordinals gave me an idea to check if commonly exported functions are following some sort of… export order. That is, if we look at e.g. COM DLLs, I tried to check if we always see the same export ordinal mapping of DllCanUnloadNow, DllGetClassObject, DllRegisterServer, etc. .

It turns out that this is usually the case:

 237607 DllCanUnloadNow	1
  19736 DllCanUnloadNow	2
   8665 DllCanUnloadNow	3
   2763 DllCanUnloadNow	5
   2411 DllCanUnloadNow	4

 234844 DllGetClassObject	2
  16700 DllGetClassObject	3
   9188 DllGetClassObject	4
   5669 DllGetClassObject	1
   3402 DllGetClassObject	6

 167356 DllRegisterServer	3
  67396 DllRegisterServer	4
   6308 DllRegisterServer	5
   3427 DllRegisterServer	7
   2026 DllRegisterServer	2

 164710 DllUnregisterServer	4
  66457 DllUnregisterServer	5
   6327 DllUnregisterServer	6
   3304 DllUnregisterServer	8
   1909 DllUnregisterServer	7

  30159 DllMain	3
  24334 DllMain	1
   5503 DllMain	20
   5299 DllMain	2
   2387 DllMain	4

  29805 DllInstall	3
   3014 DllInstall	4
    239 DllInstall	18
    188 DllInstall	5
    169 DllInstall	30

These are pretty consistent:

  • DllCanUnloadNow 1
  • DllGetClassObject 2
  • DllRegisterServer 3
  • DllUnregisterServer 4

As such, one could use them instead of actual API names. Not a biggie, but could confuse some naive detection rules…

Hiding process creation and cmd line with a long com…

How long is the command line buffer?

Depends on a program…

How much of command line do Sysmon, 4688 events log?

A finite amount.

‘Depends’ minus ‘finite’ == opportunity.

Re-visiting my old Sysmon demo where I’ve shown how to hide long command lines I thought that it would be interesting to check a different idea:

  • Write a program A that launches program B
  • Program A passes a very long command line to program B
  • Program B retrieves the command line and prints out last 5 characters only

The idea was to check if we can use the end of that long buffer as a covert channel for two processes to exchange some data (lame IPC)…

After testing it with 4688 and Sysmon enabled I spotted two things:

  • 4688 completely missed the process B creation
  • Sysmon log truncated the last bits of the command line (these 5 characters!!!) with ellipsis.

The pic below shows how 4688 log looks like:

  • We can see the invocation of the program A (first event 4688), followed by conhost.exe and then Program B is not logged at all.
  • Then we see program termination – Program A, Program B, and conhost.exe.

Sysmon logged a long command line, but the last bits are truncated and replaced by the ellipsis:

This is the invocation of ProgramB that I used (via CreateProcess):

 buffer dw 'p','r','o','g','r','a','m','B',' '
 dw 32698 dup(0FABEh)
 dw 'h','e','l','l','o'
 dw 0

and this is what ProgramB shows: