Introduction

Defender is an advanced crackme that was written by the Eldad Eilam for the purpose of reverse engineering. It contains several advanced protection mechanisms that a reverse engineer needs to break. The Defender executable is Windows NT compatible and can be run on various versions of Windows, but we’ll be using Windows XP in our case. First we must download the Defender from http://crackmes.de/users/eldad_eilam/defender.exe/ as we can see on the picture below:

After the download, we can unzip the Defender.zip file and run the Defender.exe file. Since the Defender is a console application, we must run it from cmd.exe. Upon doing that, the Defender’s usage instructions will be displayed. We can see it in the picture below:

We can see that Defender takes two input arguments. The first argument is the full name of a person, while the second argument is a 16-digit hexadecimal number. Let’s try running the program with some arguments to see what happens. On the picture below we can see the instance of running Defender with my name “Dejan Lukan” and a 16-bit hexadecimal number 11111AAAAAFFFFFF.

The result of the above program execution is that the Defender displayed the message about a bad key, which tells us that the key 11111AAAAAFFFFFF doesn’t correspond with the name “Dejan Lukan”.

Upon opening the executable in Ida, we can immediately see the following overview navigator:

This gives us the initial overview of the memory used by the application. Different colors are used for different parts of the memory, depending on the data and code being loaded in that part of the memory. If we go to Options – Colors – Navigation band, we can see the legend of the colors used in the overview navigator:

The items in the list are correspond to the colors presented below, where the “Regular function” is presented in dark blue color. This is also of particular importance for us, since this is the code that constitutes the executable code, which we have to reverse engineer. Also the code in brown presents instructions. The grey color presents the data used by the application; this is the part of the executable that we don’t have to reverse engineer, since it only contains data. Well, if the code is using some data structures, then we of course need to be aware of the data structure members.

The Exported symbols used by the Defender program are presented in the picture below, where we can see that only the program’s start point is listed. This is usually the case with programs, where we can only call their start methods to begin executing the program.


The Imported symbols list the functions that the program uses from other loaded modules. In this case, only the IsDebuggerPresent function from the kernel32.dll library is listed. This means that the program is probably using some anti-debugging tricks to detect whether we’re trying to debug the program and, if yes, it will prematurely ending the execution.

Let’s also look at the Names window that presents all the names found in the executable program. A name is an alias for a virtual address, so we can easily remember it, rather than remembering the virtual address itself. The names window contains all referenced locations and variable names that we read data from or write data to. The names window presenting all the names in the executable program can be seen in the picture below:

We already know about the start and IsDebuggerPresent names from the Imports and Exports views, but some other names are also contained in the Names window.

The Suspicious Imports

So far we’ve seen what the Defender tool can do and we’ve taken a look at its Imports/Exports and Names views, but the weird thing is that there is only one function in the imports table, the IsDebuggerPresent function. This is highly unlikely, because the program can do all sorts of things. And another reason for being suspicious is that the program contains quite a few functions, so it seems that it doesn’t contain a lot of code, just a few instructions; but this is not possible, because the program must grab the input name and key, calculate something based on those input values and return the answer about the key being valid or invalid, and this much functionality can’t be implemented with a few functions that contain rather few instructions. And the IsDebuggerPresent function is also suspicious. Maybe the program is checking whether it’s being debugged and terminating the program it if is; otherwise it’s deobfuscating itself in some way and then executing the deobfuscated code. How can we check that? The first thing we can check is figuring out the permissions the program has over the loaded segments.

To display the program’s segments, we can click on the View – Open subviews – Segments, which will present us with the picture that we see below:

We can immediately see that something is fishy. First, the program doesn’t have the .text section that is usually present in the executables. Instead it has two sections that are named .h3mf85n and .h477w81, where only the .h3mf85n section is classified as a CODE section; all other sections are DATA sections. The other thing that’s interesting is that the .h3mf85n section has read/write/execute (RWX) permissions, which is normally not the case. The code section has write permissions only in cases where the program must change itself in some way.

The first thing that we can do when trying to figure out if the program has been packed is to use the PE Identifier named PEiD. In the picture below we have started the PEiD tool and loaded the Defender.exe executable:

We can see that PEiD didn’t find anything, which means that the program is either not packed or it’s packed with an unknown packer that PEiD cannot recognize. We can also get additional information with the PEiD tool regarding the executable by pressing on the ‘>’ button next to the “Subsystem” above; additional information can be seen in the picture below:

Want to learn more?? The InfoSec Institute Reverse Engineering course teaches you everything from reverse engineering malware to discovering vulnerabilities in binaries. These skills are required in order to properly secure an organization from today's ever evolving threats. In this 5 day hands-on course, you will gain the necessary binary analysis skills to discover the true nature of any Windows binary. You will learn how to recognize the high level language constructs (such as branching statements, looping functions and network socket code) critical to performing a thorough and professional reverse engineering analysis of a binary. Some features of this course include:

  • CREA Certification
  • 5 days of Intensive Hands-On Labs
  • Hostile Code & Malware analysis, including: Worms, Viruses, Trojans, Rootkits and Bots
  • Binary obfuscation schemes, used by: Hackers, Trojan writers and copy protection algorithms
  • Learn the methodologies, tools, and manual reversing techniques used real world situations in our reversing lab.

Understanding the Executable

The next thing that we can do is figure out what the executable does. We’ve seen that there isn’t much code, so we can quickly skim though it. First, let’s go to the start of the program executable (by double clicking on the start Export entry). At that point, the basic graph of the program will is shown in the picture below:

We can see that the program isn’t complicated, but we still have to read it though to understand the logic behind it. First thing that we can do is test whether the IsDebuggerPresent function call is actually used to terminate the program or to do some other action based on whether we’re running the program under debugger or not. We’ve already seen that there isn’t any function call that can display the “Sorry bad key” message to the console when we run the program. If we run the program we can see that the console window is presented and something is displayed in it, so the program isn’t terminating. Let’s take a look at the last box on the picture above in more detail; it is there where the IsDebuggerPresent function is called. We can see the code on the picture below:

At the address 0x004042E6, we’re calling a function IsDebuggerPresent that returns a Boolean value, which is true if we’re running a program under debugger or false if we’re running the program normally. If we set the breakpoint at address 0x004042EC, so we can observe the value that is returned by the IsDebuggerPresent function call, and run the program, we can see that the breakpoint is never hit, so the program must be terminated before that. The function call IsDebuggerPresent is thus never called and even if it was, the result of that function is meaningless because of the following “xor eax, eax” instruction that zeros any value returned from that function. We can quickly figure out that it’s the call to the function loc_402082 at address 0x004042E1 that’s terminating the program. We’ve just discovered that the function IsDebuggerPresent is never called and is not being used, so there’s one thing less to worry about.

Let’s start with a program’s entry point and check what the code does right from the beginning when it is run. The first piece of assembly code that is executed can be seen below:

We can see that the function starts with creating the stack frame by pushing the EBP to the stack and moving the stack pointer to the frame pointer. Then it stores the values in the registers ecx twice, esi and edi. After that it calls the sub_402EA8 function. The code of that function is presented below:

The sub_402EA8 function loads the pointer to PEB into the register eax and then stores that pointer to the top of the stack. The variable var_4 holds the value -4, so the expression [eps+4+var_4] can be evaluated as [esp], which means to store the value in eax to the top of the stack. After that it reads the value from the top of the stack into register eax; this step is not needed, since the same value is already in the register eax, but it’s done nevertheless. If we now load the program into WinDbg we’ll be able to print the data structures that we see above.

Let’s run the “dt _TEB” command to display the contents of the TEB data structure. We’re interested in the 0×30 offset data member, because we’re storing that in the eax register above.

		0:000> dt _TEB
	ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void

		+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
	   +0x034 LastErrorValue   : Uint4B
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread  : Ptr32 Void
   +0x040 Win32ThreadInfo  : Ptr32 Void
   +0x044 User32Reserved   : [26] Uint4B
   +0x0ac UserReserved     : [5] Uint4B
   +0x0c0 WOW32Reserved    : Ptr32 Void
   +0x0c4 CurrentLocale    : Uint4B
   +0x0c8 FpSoftwareStatusRegister : Uint4B
   +0x0cc SystemReserved1  : [54] Ptr32 Void
   +0x1a4 ExceptionCode    : Int4B
   +0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
   +0x1bc SpareBytes1      : [24] UChar
   +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
   +0x6b4 RealClientId     : _CLIENT_ID
   +0x6bc GdiCachedProcessHandle : Ptr32 Void
   +0x6c0 GdiClientPID     : Uint4B
   +0x6c4 GdiClientTID     : Uint4B
   +0x6c8 GdiThreadLocalInfo : Ptr32 Void
   +0x6cc Win32ClientInfo  : [62] Uint4B
   +0x7c4 glDispatchTable  : [233] Ptr32 Void
   +0xb68 glReserved1      : [29] Uint4B
   +0xbdc glReserved2      : Ptr32 Void
   +0xbe0 glSectionInfo    : Ptr32 Void
   +0xbe4 glSection        : Ptr32 Void
   +0xbe8 glTable          : Ptr32 Void
   +0xbec glCurrentRC      : Ptr32 Void
   +0xbf0 glContext        : Ptr32 Void
   +0xbf4 LastStatusValue  : Uint4B
   +0xbf8 StaticUnicodeString : _UNICODE_STRING
   +0xc00 StaticUnicodeBuffer : [261] Uint2B
   +0xe0c DeallocationStack : Ptr32 Void
   +0xe10 TlsSlots         : [64] Ptr32 Void
   +0xf10 TlsLinks         : _LIST_ENTRY
   +0xf18 Vdm              : Ptr32 Void
   +0xf1c ReservedForNtRpc : Ptr32 Void
   +0xf20 DbgSsReserved    : [2] Ptr32 Void
   +0xf28 HardErrorsAreDisabled : Uint4B
   +0xf2c Instrumentation  : [16] Ptr32 Void
   +0xf6c WinSockData      : Ptr32 Void
   +0xf70 GdiBatchCount    : Uint4B
   +0xf74 InDbgPrint       : UChar
   +0xf75 FreeStackOnTermination : UChar
   +0xf76 HasFiberData     : UChar
   +0xf77 IdealProcessor   : UChar
   +0xf78 Spare3           : Uint4B
   +0xf7c ReservedForPerf  : Ptr32 Void
   +0xf80 ReservedForOle   : Ptr32 Void
   +0xf84 WaitingOnLoaderLock : Uint4B
   +0xf88 Wx86Thread       : _Wx86ThreadState
   +0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
   +0xf98 ImpersonationLocale : Uint4B
   +0xf9c IsImpersonating  : Uint4B
   +0xfa0 NlsCache         : Ptr32 Void
   +0xfa4 pShimData        : Ptr32 Void
   +0xfa8 HeapVirtualAffinity : Uint4B
   +0xfac CurrentTransactionHandle : Ptr32 Void
   +0xfb0 ActiveFrame      : Ptr32 _TEB_ACTIVE_FRAME
   +0xfb4 SafeThunkCall    : UChar
   +0xfb5 BooleanSpare     : [3] UChar

We’ve just displayed the TEB data structure, which is important because we’re accessing its 0×30 offset data member, which is PEB data structure: “0×030 ProcessEnvironmentBlock : Ptr32 _PEB”.

Then we’re accessing the 0xC offset data member from the PEB data structure. Let’s print the PEB data structure, so we can take a look at which member is located at the 0xC offset. The PEB data structure is presented below:

		0:000> dt _PEB
	ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 SpareBool        : UChar
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void

		  +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
	   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : Ptr32 Void
   +0x018 ProcessHeap      : Ptr32 Void
   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
   +0x020 FastPebLockRoutine : Ptr32 Void
   +0x024 FastPebUnlockRoutine : Ptr32 Void
   +0x028 EnvironmentUpdateCount : Uint4B
   +0x02c KernelCallbackTable : Ptr32 Void
   +0x030 SystemReserved   : [1] Uint4B
   +0x034 AtlThunkSListPtr32 : Uint4B
   +0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK
   +0x03c TlsExpansionCounter : Uint4B
   +0x040 TlsBitmap        : Ptr32 Void
   +0x044 TlsBitmapBits    : [2] Uint4B
   +0x04c ReadOnlySharedMemoryBase : Ptr32 Void
   +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
   +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
   +0x058 AnsiCodePageData : Ptr32 Void
   +0x05c OemCodePageData  : Ptr32 Void
   +0x060 UnicodeCaseTableData : Ptr32 Void
   +0x064 NumberOfProcessors : Uint4B
   +0x068 NtGlobalFlag     : Uint4B
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER
   +0x078 HeapSegmentReserve : Uint4B
   +0x07c HeapSegmentCommit : Uint4B
   +0x080 HeapDeCommitTotalFreeThreshold : Uint4B
   +0x084 HeapDeCommitFreeBlockThreshold : Uint4B
   +0x088 NumberOfHeaps    : Uint4B
   +0x08c MaximumNumberOfHeaps : Uint4B
   +0x090 ProcessHeaps     : Ptr32 Ptr32 Void
   +0x094 GdiSharedHandleTable : Ptr32 Void
   +0x098 ProcessStarterHelper : Ptr32 Void
   +0x09c GdiDCAttributeList : Uint4B
   +0x0a0 LoaderLock       : Ptr32 Void
   +0x0a4 OSMajorVersion   : Uint4B
   +0x0a8 OSMinorVersion   : Uint4B
   +0x0ac OSBuildNumber    : Uint2B
   +0x0ae OSCSDVersion     : Uint2B
   +0x0b0 OSPlatformId     : Uint4B
   +0x0b4 ImageSubsystem   : Uint4B
   +0x0b8 ImageSubsystemMajorVersion : Uint4B
   +0x0bc ImageSubsystemMinorVersion : Uint4B
   +0x0c0 ImageProcessAffinityMask : Uint4B
   +0x0c4 GdiHandleBuffer  : [34] Uint4B
   +0x14c PostProcessInitRoutine : Ptr32     void
   +0x150 TlsExpansionBitmap : Ptr32 Void
   +0x154 TlsExpansionBitmapBits : [32] Uint4B
   +0x1d4 SessionId        : Uint4B
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
   +0x1e8 pShimData        : Ptr32 Void
   +0x1ec AppCompatInfo    : Ptr32 Void
   +0x1f0 CSDVersion       : _UNICODE_STRING
   +0x1f8 ActivationContextData : Ptr32 Void
   +0x1fc ProcessAssemblyStorageMap : Ptr32 Void
   +0x200 SystemDefaultActivationContextData : Ptr32 Void
   +0x204 SystemAssemblyStorageMap : Ptr32 Void
   +0x208 MinimumStackCommit : Uint4B

We can see that the data member we’re after is the Ldr data member: “0x00c Ldr : Ptr32 _PEB_LDR_DATA”. After that, the function is accessing the member at offset 0xC in the Ldr data structure. Let’s display the contents of the PEB_LDR_DATA data structure:

		0:000> dt _PEB_LDR_DATA
	ntdll!_PEB_LDR_DATA
   +0x000 Length           : Uint4B
   +0x004 Initialized      : UChar
   +0x008 SsHandle         : Ptr32 Void

		+0x00c InLoadOrderModuleList : _LIST_ENTRY
	   +0x014 InMemoryOrderModuleList : _LIST_ENTRY
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY
   +0x024 EntryInProgress  : Ptr32 Void

We’re interested in the data member that is located at the 0xC offset, which is the InLoadOrderModuleList data member. This data structure is used to access the loaded executable modules into the current process. We can see that there are different module lists InLoadOrderModuleList, InMemoryOrderModuleList, InInitializationOrderModuleList, which present the same loaded modules in different order.

If we want to continue printing the _LIST_ENTRY data members, we need to get the address of the _PEB_LDR_DATA data structure. We can get that with the command presented below:

		0:000> dt _PEB @$peb
	ntdll!_PEB
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0x1 ''
   +0x003 SpareBool        : 0 ''
   +0x004 Mutant           : 0xffffffff Void
   +0x008 ImageBaseAddress : 0x00400000 Void
   +0x00c Ldr              : 0x00251ea0 _PEB_LDR_DATA

So the address of our data structure is 0x00251ea0. Next we can display the address of the InLoadOrderModuleList data structure:

		0:000> dt nt!_PEB_LDR_DATA 0x00251ea0
	ntdll!_PEB_LDR_DATA
   +0x000 Length           : 0x28
   +0x004 Initialized      : 0x1 ''
   +0x008 SsHandle         : (null)
   +0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x251ee0 - 0x252250 ]
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x251ee8 - 0x252258 ]
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x251f58 - 0x2521a0 ]
   +0x024 EntryInProgress  : (null)

We’ve just figured out that the function reads from the address 0x251ee0. Let’s dump the memory that’s located there with the use of dd command:

		0:000> dd 0x251ee0
	00251ee0  00251f48 00251eac 00251f50 00251eb4

We can see that the function is taking the address 00251f48 from the 00251ee0 and reading the bytes at its 0×18 offset location. Let’s also dump the memory at that address:

		0:000> dd 00251f48
	00251f48  00252010 00251ee0 00252018 00251ee8
00251f58  00252020 00251ebc 7c900000 7c9120f8

Now we’ve figured out that the function is after address 7c900000, which is exactly the ntdll.dll base address, as we can see on the output below:

Want to learn more?? The InfoSec Institute Reverse Engineering course teaches you everything from reverse engineering malware to discovering vulnerabilities in binaries. These skills are required in order to properly secure an organization from today's ever evolving threats. In this 5 day hands-on course, you will gain the necessary binary analysis skills to discover the true nature of any Windows binary. You will learn how to recognize the high level language constructs (such as branching statements, looping functions and network socket code) critical to performing a thorough and professional reverse engineering analysis of a binary. Some features of this course include:

  • CREA Certification
  • 5 days of Intensive Hands-On Labs
  • Hostile Code & Malware analysis, including: Worms, Viruses, Trojans, Rootkits and Bots
  • Binary obfuscation schemes, used by: Hackers, Trojan writers and copy protection algorithms
  • Learn the methodologies, tools, and manual reversing techniques used real world situations in our reversing lab.
		0:000> !dlls
	This is Pre-Win8 without the loader DAG.

0x00251f48: C:WINDOWSsystem32ntdll.dll
      Base   0x7c900000  EntryPoint  0x7c9120f8  Size        0x000b2000
      Flags  0x80084004  LoadCount   0x0000ffff  TlsIndex    0x00000000
             LDRP_IMAGE_DLL
             LDRP_ENTRY_PROCESSED
             LDRP_PROCESS_ATTACH_CALLED

Conclusion

We’ve printed the basic information about the Defender program and discovered that it’s obfuscated. We’ve also discovered that the function sub_402EA8 is after the base address of the ntdll.dll module that has been loaded into memory; the function returns the 0x7c900000 address in register eax.