Re-usigned binaries: Java’s nio.dll as a proxy for Windows API

This is a very silly idea, but it intends to be more a food for a thought than anything else. I mentioned before that signed binaries can be used to do almost anything. All we have to do is to find them and… instrument them.

The below is an example of such binary, courtesy of Java.

Browsing through function names exported by Java libraries I came across a very interesting pattern. One of the libraries nio.dll includes a very interesting set of function names, e.g.:

  • _Java_sun_nio_fs_WindowsNativeDispatcher_BackupRead0@44
  • _Java_sun_nio_fs_WindowsNativeDispatcher_BackupSeek@32
  • _Java_sun_nio_fs_WindowsNativeDispatcher_CloseHandle@16
  • _Java_sun_nio_fs_WindowsNativeDispatcher_CopyFileEx0@36
  • _Java_sun_nio_fs_WindowsNativeDispatcher_CreateDirectory0@24
  • _Java_sun_nio_fs_WindowsNativeDispatcher_CreateFile0@40
  • _Java_sun_nio_fs_WindowsNativeDispatcher_CreateHardLink0@24
  • _Java_sun_nio_fs_WindowsNativeDispatcher_DeleteFile0@16
  • _Java_sun_nio_fs_WindowsNativeDispatcher_DuplicateTokenEx@20
  • _Java_sun_nio_fs_WindowsNativeDispatcher_FindClose@16
  • _Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0@20
  • _Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1@24
  • _Java_sun_nio_ch_Net_socket0@20
  • _Java_sun_nio_ch_Net_listen@16
  • _Java_sun_nio_ch_Net_connect0@24
  • etc. (170+ functions total)

Curious, I inspected code of some functions, and quickly discovered that these are just wrappers for your regular Windows API. And since they are we can use them to do Windows API stuff for us.

I quickly coded a simple example that uses:

  • _Java_sun_nio_fs_WindowsNativeDispatcher_CreateFile0

to create a test.txt file. The prototype for the function was slightly different than the CreateFile one, but it’s easy to map them with IDA:

a0=0
a1=0
LPCWSTR lpFileName
a4=0
DWORD dwDesiredAccess
DWORD dwShareMode
LPSECURITY_ATTRIBUTES lpSecurityAttributes
a8=0
DWORD dwCreationDisposition
DWORD dwFlagsAndAttributes
HANDLE hTemplateFile --> ignored

It’s a basic stuff, but since it works, it’s easy to imagine proxying most of available operations via these functions.

One may ask – what would be a purpose of such silly maneuver ?

When you call CreateFile from your code it is from within the image of a .exe file (after it is launched). In other words – it’s a direct call from the program. If a PE file this program was loaded from is unsigned it is going to hit a radar of any security solution that keeps an eye on these things. Many of them progressed from simple API monitors to be more context-aware. They may attempt to interpret a flow of events (sequence of API calls + their context), and remove parts of the reports that may be superfluous. All they have to do is look at the stack, retrieve the return address of the API call and see within boundaries of which code it was called from.

In one of my older posts I described it in more detail and insisted that removing trace of unimportant, in-between calls from the logs in sandbox reports is an important step that improves the readability of the code flow. This doesn’t work all the time, and this post is just one of many examples that may help to fool such ‘readability-oriented report wrappers’.

Since APIs called from an unsigned program may get a much higher risk score than the very same API called from within a trusted code we can try to change the odds.

We can think of libraries like nio.dll as of an API proxy. Proxying calls via a signed library may change the detection odds.

Last, but not least – with code proxy comes great responsibility. As such, the test program is dependent on a couple of Java DLLs (because nio.dll depends on them):

  • java.dll
  • jvm.dll
  • net.dll
  • nio.dll
  • verify.dll

While unintended, such loaded signed DLLs may actually add more credibility to the process. Programs that load signed libraries only cannot be bad, right?

Playing with Delay-Loaded DLLs…

Delay-Loaded DLLs is PE file feature that is almost obsolete today. Programmers who wanted to benefit from this mechanism in the past would write a program that would use many Windows API same as usual. During the linking process though they would enforce some restrictions: forcing some DLLs and their imports to be resolved some time later after the actual program start. This was meant to speed up the loading of the program and use less memory. In practice, it’s just a convenient mechanism that resolves APIs dynamically ‘just-in-time’ so that programmers can use API calls transparently & don’t need to write their own wrappers (or use LoadLibrary/GetProcAddress directly).

We can take the advantage of this mechanism to implement a simple beacon by adding a DLL name to delayed import table, and then using hex editor (or a quick script) to replace the name of this DLL with a UNC path in a same way as the PDB example:

Once program is executed, and the function that is resolved dynamically is encountered, the program’s library function will attempt to load that particular DLL (i.e. in our case it will try to resolve the UNC path and as such will ping the destination address). The DLL could be of course present on that remote site, or the the dynamic loader could be executed within an exception handler wrapper so that the program can continue…

Interestingly, Dependency Walker shows the UNC path when the program is told to view the imports used by the test exe file. It doesn’t stop it though from trying to load the delayed DLL from that UNC path. And because of that, the actual ‘call home’ ping can be made w/o execution of the main sample!

This is again should act as a warning against testing samples on systems that are online. Even static analysis could sometimes be harmful, especially if you use tools that blindly trust the input, or even worse, utilize LoadLibrary to load the DLLs that programs are linked to.