Enter Sandbox – part 3: If you see Native code is creative

June 10, 2015 in Batch Analysis, Clustering, Malware Analysis, Sandboxing

Native functions are a very tempting target for monitoring as they are the core of the basic, atomic operations used by the OS. Observing them can give us a lot of juicy information about what is going on on the system + chances for evasions are low since most of the complex, high-level functions typically end up calling these OS ‘primitives’ anyway. Hooking/monitoring can be done both on kernel level (system-wide) and in user mode (process-wide); more exotic hooks can go deeper and monitor sysenter/syscall via Model Specific Registers (MSR), patch dispatcher functions e.g. KiFastCallEntry etc. – anything that participates in the transition between kernel and user mode can be monitored/patched/intercepted. There is also an extra layer for wow64 link between 32- and 64-bit layers inside 32-bit processes on 64-bit OS.

As I mentioned in the first part I am not a big fan of native functions hooking. More specifically, I do think it’s worth hooking these functions, but it is not necessary to always do so and there is also no need necessarily to output their logs into report all the time. The thing is that they are extremely noisy and they really lack of context. For the record, must emphasize here again that I am mainly focusing on manual analysis – the commercial sandbox should definitely look at everything and better be oversensitive and show more than ignore some important stuff.

If we look back at the list of APIs that I presented in part 1 and which are resolved using GetProcAddress you will notice that all of them are actually non-native APIs. They are just regular windows APIs.

There is a simple reason for it.

Most of malware is written in high-level languages and they leverage frameworks using predefined, well-structured and easy to use libraries. The functions malware writers rely on are imported statically and since they often use a copy&pasted code the result is that similar stuff is populated in gazillions of malicious projects written in Delphi, VB, AutoIT, .NET, etc. etc. While some of the malware families do leverage native functions it is not that common. It is important to say that native functions are not that difficult to use – they are just not that convenient – who would like to bother with data alignments, undocumented structures, or using NtCreateFile if there is an easy way – f.ex. fopen, CreateFile, etc.

For a reverser, seeing native functions being used by malware is typically a good news i.e. it means an interesting work; that means that someone on the other side of the fence at least made an effort to be creative and most likely wrote the code either in asm, or in C. Copy & paste exists of course too (and also ported to very high-level languages), but I’d argue that on a much smaller scale and mainly used by wrappers.

The code of malware families that leverage native functions is interesting not only for their functionality or technical craftsmanship, but also for the simple reason that being the creation of their intelligent authors it is probably the most personal code you will see in the software world (as juxtaposed by copy&paste efforts that is present all over the place f.ex. inside POS malware, but also in regular software which nowadays heavily relies on copy&paste from Stack Overflow). I could summarize this paragraph by saying that creative malware writers typically use native functions, and from a different angle – if you are looking for an interesting malware – look for the one that is using the native functions.

The post wouldn’t be complete if we didn’t list some of the most popular ntdll functions that are resolved during run-time (i.e. via GetProcAddress):

LdrFindEntryForAddress
NtUnmapViewOfSection
NtQuerySystemInformation
ZwQueryInformationThread
RtlInitUnicodeString
ZwUnmapViewOfSection
RtlNtStatusToDosError
NtMapViewOfSection
NtOpenSection
NtQueryInformationProcess
RtlAllocateHeap
RtlDecompressBuffer
RtlFreeHeap
RtlEnterCriticalSection
RtlLeaveCriticalSection
RtlGetLastWin32Error
RtlReAllocateHeap
RtlDeleteCriticalSection
LdrLoadDll
CsrGetProcessId
LdrGetDllHandle
RtlSetLastWin32Error
NtSetInformationProcess
RtlAddVectoredExceptionHandler
RtlImageNtHeader
LdrGetProcedureAddress
NtCreateThread
RtlAdjustPrivilege
RtlUnwind
LdrFindEntryForAddress
NtSetInformationThread
memset
VerSetConditionMask
NtUnmapViewOfSection
RtlRemoveVectoredExceptionHandler
memcpy
ZwClose
ZwQueryInformationProcess
NtCreateUserProcess
NtAllocateVirtualMemory
RtlUserThreadStart
ZwOpenProcess
NtWriteVirtualMemory
ZwQuerySystemInformation
NtClose
NtReadVirtualMemory
RtlImageDirectoryEntryToData
NtDelayExecution
swprintf
RtlSizeHeap

Share this :)

Comments are closed.