Hi,
Malware is often really boring to reverse because in high percentage they implements basical well known mechanisms of infection and self protection.
But sometimes there are really intersting malware that implements innovative techniques, this is the case of a trojan borned into 2006 that implemented DeleteFiber() as AntiโDebug Trick in a really easy and smart way.
To understand how it works, let’s see whar DeleteFiber is, directly from MSDN:
Deletes an existing fiber.
Syntax
VOID WINAPI DeleteFiber(
__inย LPVOID lpFiber
);
lpFiber is the address of the fiber to be deleted.
Important to say that the DeleteFiber function deletes all data associated with the fiber.
This data includes the stack, a subset of the registers, and the fiber data.
Now let’s see a basical use of DeleteFiber():
#define _WIN32_WINNT 0x0400
#include <windows.h>
int main(void)
{
char fiber[1024] = {0};
DeleteFiber(fiber);
return EXIT_SUCCESS;
}
After showing the basical use of DeleteFiber let’s see how can be implemented as Anti-Debug Trick,
I insert here direcly the code:
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <stdio.h>
int main(void)
{
char fib[1024] = {0};
DeleteFiber(fib);
if(GetLastError() == 0x00000057)
MessageBoxA(NULL,”This process is NOT debugged”,”Info”,MB_OK);
else
MessageBoxA(NULL,”This process IS debugged”,”Info”,MB_OK);
return EXIT_SUCCESS;
}
As you can understant we can resume this trick into two cases:
- If the process is NOT debugged DeleteFiber give us an Error Code of 0x00000057 that corresponds to ERROR_INVALID_PARAMETER
- If the process IS debugged the error code is differs from 0x00000057
What to say it’s really easy to implement and really effective for all kind of debuggers, with a
bit of junk code that confuses ideas the conditional check could be placed really distant from the
DeleteFiber() itself.
Inside DeleteFiber()
Now we will see how DeleteFiber internally works to understand why this should be used as
Anti-Debug trick.
This is the Dead List:
00401000 PUSH DF.00403370
00401005 CALL DWORD PTR DS:[<&KERNEL32.DeleteFiber>; kernel32.DeleteFiber
inside DeleteFiber()
7C825A9F > MOV EDI,EDI ; DF.00403778
7C825AA1 PUSH EBP
7C825AA2 MOV EBP,ESP
7C825AA4 PUSH ECX
7C825AA5 PUSH ESI
7C825AA6 MOV EAX,DWORD PTR FS:[18] ;_TEB Struct
7C825AAC MOV ECX,DWORD PTR DS:[EAX+10] ;pointer to _TIB.FiberData field
7C825AAF MOV ESI,DWORD PTR SS:[EBP+8] ;lpFiber
7C825AB2 CMP ECX,ESI
7C825AB4 JE kernel32.7C826596 ;ExitThread if( FiberData == lpfiber)
7C825ABA AND DWORD PTR SS:[EBP-4],0 ;Clears this Stack location
7C825ABE PUSH 8000 ;MEM_RELEASE
7C825AC3 LEA EAX,DWORD PTR SS:[EBP-4]
7C825AC6 PUSH EAX
7C825AC7 LEA EAX,DWORD PTR DS:[ESI+10]
7C825ACA PUSH EAX
7C825ACB PUSH -1
7C825ACD CALL DWORD PTR DS:[<&ntdll.NtFreeVirtual> ntdll.ZwFreeVirtualMemory
7C825AD3 MOV EAX,DWORD PTR FS:[18] ;_TEB Struct
7C825AD9 MOV EAX,DWORD PTR DS:[EAX+30] ;points to _PEB Struct
7C825ADC PUSH ESI ;lpFiber
7C825ADD PUSH 0 ;0x00000000
7C825ADF PUSH DWORD PTR DS:[EAX+18] ;PEB.ProcessHeap
7C825AE2 CALL DWORD PTR DS:[<&ntdll.RtlFreeHeap>] ; ntdll.RtlFreeHeap
7C825AE8 POP ESI
7C825AE9 LEAVE
7C825AEA RETN 4
In the first part of DeleteFiber is retrived the _TEB structure and specifically a member of
_TIB structure located at 10h
0:003> dt nt!_TEB -b
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x000 ExceptionList : Ptr32
…
+0x00c SubSystemTib : Ptr32
+0x010 FiberData : Ptr32
and next if FiberData is equal to our Fiber’s Address it means that Fiber is suicinding itself
and system calls ExitThread(), next we can notice a NtFreeVirtualMemory call with the following
parameters:
NtFreeVirtualMemory(NtCurrentProcess(), &pStackAllocBase,&nSize,MEM_RELEASE);
The system deallocates the used stack and finally calls RtlFreeHeap in this manner:
RtlFreeHeap(GetProcessHeap(), 0, lpFiber);
This last call clarifies totally the presence of ERROR_INVALID_PARAMETER because has we have seen
DeleteFiber is directly correlated with Heap, and Heap Memory presents a set of Flags that
characterize the Heap itself.
These Flags differs in case the process IS debugged or NOT, so we can suppose that these flags
are created when the exe itself is executed, in other words at Process Creation Time. Under
Windows NT processes are created through PspUserThreadStartup and inside it we can found
LdrInitializeThunk, that as Russinovich sais The LdrInitializeThunk routine initializes the
loader, heap manager, NLS tables, thread-local storage (TLS) array, and critical section
structures. By going more deep we can see that there is a specific function that fill the PEB
Struct of the new process MmCreatePeb(), PEB is important because between his various fields
are stored Heap Flags of our process. I’m talking about NtGlobalFlag, for a debugged process
these flags are:
#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010
#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020
#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040
Now if a process has these flags enabled ( HeapDebug ) RtlFreeHeap will fail the Heap freeing and
this error will be propagated to DeleteFiber() that will exit with an ERROR_INVALID_PARAMETER.
Anti Anti-Debug
Due to the fact that the Heap Validation is accomplished at Processs Creation Time, one
countermeasure against Anti-Debug will be to attach the debugger after that the process is created.
If you are using WinDbg could be used the HeapDebug option ( -hd )
Between the function involved in process creation we have also LdrQueryImageFileExecutionOptions
that mantains trace of IFEO ( Image File Execution Options structure) this struct is located into
Registry under the path
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\]
The various possible values are:
Debugger
DisableHeapLookaside
ShutdownFlags
MinimumStackCommitInBytes
ExecuteOptions
GlobalFlag
DebugProcessHeapOnly
ApplicationGoo
RpcThreadPoolThrottle
GlobalFlag can be used to modify NtGlobalFlag, so if you set this key entry to NULL, Heap of the
debugged program will looks as an undebugged one, read this as an Anti-Anti Debug Trick :).
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\
Target.exe]
"GlobalFlag"=""