Windows PE Malware Analysis Part I

10 minute read

Introduction

In this article I will be examining a Windows executable malware specimen. Based on a couple reports from automated malware sandboxes, the specimen drops multiple files to disk and calls out to multiple domains and IP addresses.

The purpose of this article is to give readers a look into malware reverse engineering using static analysis, behavioral analysis, and code analysis. This is Part 1 of several more articles to come.

The specimen in question is a Windows PE (Portable Executable) named setup.exe. You can find it’s hashes below.

MD5: d1b2c8ddca2f8dd02e2c132153055084

SHA-1: 21c011ac7406eef048c175f5887e4eb885c050d6

SHA256: 506c2f513d64242fcb20ccff8c26c0ed1755fe9120b984c29ba224b311d635c3

I pulled this malware from Any.Run which contains nearly 75,000 malware samples at the time of this article. This particular specimen was uploaded on October 29th, 2021; however, the earliest upload was on October 21st, 2021.

image

VirusTotal shows 47 out of 68 vendors have flagged this as malware and the last analysis ran was October 28th, 2021. You can see some of the features that VirusTotal identified such as detect-debug-environment, direct-cpu-clock-access and long-sleeps.

image

VirusTotal also displays that the creation time of this malware was October 18th, 2021.

image

Over the course of this series, rather than simply relying on automated sandbox analysis, let’s take a deeper look at what this malware does and try to identify some characteristics such as:

  • Obfuscation

  • Anti-reverse engineering

  • Command and Control

  • Encryption

…and more.

Environment

I will be using two virtual machines to complete my analysis. The first is a REMnux linux virtual machine and the other is the Windows based FlareVM by FireEye.

REMnux is an Ubuntu linux machine that is pre-loaded with tons of malware analysis tools. It can also be installed through a script on any compatible version of Ubuntu.

FlareVM comes as a PowerShell script that utilizes the Chocolatey package manager for Windows to download all the necessary tools for malware analysis, incident response and penetration testing. This will require your own Windows virtual machine for installation.

Static Analysis

Usually, I like to begin with static analysis because it gives me a preliminary look at what to expect from the specimen. It is the easiest step of the reverse engineering process in my opinion since it requires very little setup.

Static analysis includes using tools like file, strings, pedump and disassemblers like IDA Pro by Hex-Rays or Ghidra by the NSA. For this step, I will be using the REMnux VM.

File command

First, I will run the file command to determine the architecture and confirm that the file is a Windows PE.

image

The results show that it is indeed a Windows PE, and it is of the x86 Intel architecture or a 32 bit program.

NOTE: Most malware is 32 bit to ensure it can run on both 32 and 64 bit systems.

PEdump

Next, I will run pedump to get a breakdown of the specimen’s headers, imports, sections and more. Below is the output with some truncated lines.


=== MZ Header ===

                     signature:                     "MZ"
           bytes_in_last_block:        144          0x90
                blocks_in_file:          3             3
                    num_relocs:          0             0
             header_paragraphs:          4             4
          min_extra_paragraphs:          0             0
          max_extra_paragraphs:      65535        0xffff
                            ss:          0             0
                            sp:        184          0xb8
                      checksum:          0             0
                            ip:          0             0
                            cs:          0             0
            reloc_table_offset:         64          0x40
                overlay_number:          0             0
                     reserved0:          0             0
                        oem_id:          0             0
                      oem_info:          0             0
                     reserved2:          0             0
                     reserved3:          0             0
                     reserved4:          0             0
                     reserved5:          0             0
                     reserved6:          0             0
                        lfanew:        272         0x110

=== DOS STUB ===

00000000: 0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000010: 69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000020: 74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000030: 6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|

=== RICH Header ===

   ID   VER         COUNT  DESCRIPTION
  103  6b14            10  
  105  6b14           146  
  104  6b14            18  
  104  6f0b            17  
  103  6f0b            22  
  105  6f0b            44  
  101  6b14             3  
    1     0            93  [---] Unmarked objects
  109  6fc6             3  
   ff  6fc6             1  [RES] VS2019 v16.5.5 build 28614
   97     0             1  
  102  6fc6             1  [LNK] VS2019 v16.5.5 build 28614

=== PE Header ===

                     signature:             "PE\x00\x00"

# IMAGE_FILE_HEADER:
                       Machine:        332         0x14c  x86
              NumberOfSections:          5             5
                 TimeDateStamp:    "2021-10-18 09:26:14"
          PointerToSymbolTable:          0             0
               NumberOfSymbols:          0             0
          SizeOfOptionalHeader:        224          0xe0
               Characteristics:        258         0x102  EXECUTABLE_IMAGE, 32BIT_MACHINE

# IMAGE_OPTIONAL_HEADER32:
                         Magic:        267         0x10b  32-bit executable
                 LinkerVersion:                    14.25
                    SizeOfCode:      89600       0x15e00
         SizeOfInitializedData:     326144       0x4fa00
       SizeOfUninitializedData:          0             0
           AddressOfEntryPoint:      39488        0x9a40
                    BaseOfCode:       4096        0x1000
                    BaseOfData:      94208       0x17000
                     ImageBase:    4194304      0x400000
              SectionAlignment:       4096        0x1000
                 FileAlignment:        512         0x200
        OperatingSystemVersion:                      6.0
                  ImageVersion:                      0.0
              SubsystemVersion:                      6.0
                     Reserved1:          0             0
                   SizeOfImage:     425984       0x68000
                 SizeOfHeaders:       1024         0x400
                      CheckSum:          0             0
                     Subsystem:          2             2  WINDOWS_GUI
            DllCharacteristics:      49472        0xc140  DYNAMIC_BASE, NX_COMPAT, 0x4000
                                                          TERMINAL_SERVER_AWARE
            SizeOfStackReserve:    1048576      0x100000
             SizeOfStackCommit:       4096        0x1000
             SizeOfHeapReserve:    1048576      0x100000
              SizeOfHeapCommit:       4096        0x1000
                   LoaderFlags:          0             0
           NumberOfRvaAndSizes:         16          0x10

=== DATA DIRECTORY ===

  EXPORT        rva:0x       0   size:0x        0
  IMPORT        rva:0x   1d3d8   size:0x       28
  RESOURCE      rva:0x   20000   size:0x    45db8
  EXCEPTION     rva:0x       0   size:0x        0
  SECURITY      rva:0x       0   size:0x        0
  BASERELOC     rva:0x   66000   size:0x     1430
  DEBUG         rva:0x   1c390   size:0x       1c
  ARCHITECTURE  rva:0x       0   size:0x        0
  GLOBALPTR     rva:0x       0   size:0x        0
  TLS           rva:0x       0   size:0x        0
  LOAD_CONFIG   rva:0x   1c3b0   size:0x       40
  Bound_IAT     rva:0x       0   size:0x        0
  IAT           rva:0x   17000   size:0x      12c
  Delay_IAT     rva:0x       0   size:0x        0
  CLR_Header    rva:0x       0   size:0x        0
                rva:0x       0   size:0x        0

=== SECTIONS ===

  NAME          RVA      VSZ   RAW_SZ  RAW_PTR  nREL  REL_PTR nLINE LINE_PTR     FLAGS
  .text        1000    15d02    15e00      400     0        0     0        0  60000020  R-X CODE
  .rdata      17000     6a72     6c00    16200     0        0     0        0  40000040  R-- IDATA
  .data       1e000     1854      a00    1ce00     0        0     0        0  c0000040  RW- IDATA
  .rsrc       20000    45db8    45e00    1d800     0        0     0        0  40000040  R-- IDATA
  .reloc      66000     1430     1600    63600     0        0     0        0  42000040  R-- IDATA DISCARDABLE

=== RESOURCES ===

FILE_OFFSET    CP  LANG     SIZE  TYPE          NAME
    0x37430     0 0x2000   180224  DLL           #124
    0x1dd50     0 0x2000     4465  ICON          #1
    0x1eec8     0 0x2000    67624  ICON          #2
    0x2f6f0     0 0x2000    16936  ICON          #3
    0x33918     0 0x2000     9640  ICON          #4
    0x35ec0     0 0x2000     4264  ICON          #5
    0x36f68     0 0x2000     1128  ICON          #6
    0x373d0     0 0x2000       90  GROUP_ICON    #101
    0x1da70     0 0x2000      732  VERSION       #1
    0x63430     0 0x409      392  MANIFEST      #1

=== IMPORTS ===

MODULE_NAME      HINT   ORD  FUNCTION_NAME
KERNEL32.dll      475        ReadFile
KERNEL32.dll      630        lstrcatA
KERNEL32.dll      278        GetModuleHandleA
KERNEL32.dll      50a        SetCurrentDirectoryA
KERNEL32.dll      279        GetModuleHandleExA
KERNEL32.dll       c6        CreateFileA
KERNEL32.dll      639        lstrcpyA
KERNEL32.dll       89        CloseHandle
KERNEL32.dll      24e        GetFileSize
KERNEL32.dll      264        GetLastError
KERNEL32.dll      2b1        GetProcAddress
KERNEL32.dll      34c        HeapFree
KERNEL32.dll      616        WriteFile
KERNEL32.dll      63f        lstrlenA
KERNEL32.dll      63c        lstrcpynA
KERNEL32.dll      615        WriteConsoleW
KERNEL32.dll      44f        QueryPerformanceCounter
KERNEL32.dll      534        SetLastError
KERNEL32.dll      362        InitializeCriticalSectionAndSpinCount
KERNEL32.dll      5a2        TlsAlloc
KERNEL32.dll      5a4        TlsGetValue
KERNEL32.dll      5a5        TlsSetValue
KERNEL32.dll      5a3        TlsFree
KERNEL32.dll      2ec        GetSystemTimeAsFileTime
KERNEL32.dll      27b        GetModuleHandleW
KERNEL32.dll      5b1        UnhandledExceptionFilter
KERNEL32.dll      571        SetUnhandledExceptionFilter
KERNEL32.dll      21a        GetCurrentProcess
KERNEL32.dll      590        TerminateProcess
KERNEL32.dll      389        IsProcessorFeaturePresent
KERNEL32.dll      382        IsDebuggerPresent
KERNEL32.dll      2d3        GetStartupInfoW
KERNEL32.dll      21b        GetCurrentProcessId
KERNEL32.dll      21f        GetCurrentThreadId
KERNEL32.dll      366        InitializeSListHead
KERNEL32.dll      4d5        RtlUnwind
KERNEL32.dll      464        RaiseException
KERNEL32.dll      130        EncodePointer
KERNEL32.dll      134        EnterCriticalSection
KERNEL32.dll      3c1        LeaveCriticalSection
KERNEL32.dll      113        DeleteCriticalSection
KERNEL32.dll      1ae        FreeLibrary
KERNEL32.dll      3c7        LoadLibraryExW
KERNEL32.dll      161        ExitProcess
KERNEL32.dll      27a        GetModuleHandleExW
KERNEL32.dll      277        GetModuleFileNameW
KERNEL32.dll      2d5        GetStdHandle
KERNEL32.dll      525        SetFilePointerEx
KERNEL32.dll      251        GetFileType
KERNEL32.dll      348        HeapAlloc
KERNEL32.dll      3b5        LCMapStringW
KERNEL32.dll      178        FindClose
KERNEL32.dll      17e        FindFirstFileExW
KERNEL32.dll      18f        FindNextFileW
KERNEL32.dll      38f        IsValidCodePage
KERNEL32.dll      1b5        GetACP
KERNEL32.dll      29a        GetOEMCP
KERNEL32.dll      1c4        GetCPInfo
KERNEL32.dll      1d9        GetCommandLineA
KERNEL32.dll      1da        GetCommandLineW
KERNEL32.dll      3f3        MultiByteToWideChar
KERNEL32.dll      602        WideCharToMultiByte
KERNEL32.dll      23a        GetEnvironmentStringsW
KERNEL32.dll      1ad        FreeEnvironmentStringsW
KERNEL32.dll      2b7        GetProcessHeap
KERNEL32.dll      54e        SetStdHandle
KERNEL32.dll      2da        GetStringTypeW
KERNEL32.dll      1ff        GetConsoleMode
KERNEL32.dll      1a2        FlushFileBuffers
KERNEL32.dll      203        GetConsoleOutputCP
KERNEL32.dll      351        HeapSize
KERNEL32.dll      34f        HeapReAlloc
KERNEL32.dll       ce        CreateFileW
KERNEL32.dll      10c        DecodePointer

=== VERSION INFO ===

# VS_FIXEDFILEINFO:
  FileVersion         :  10001.1.15.1
  ProductVersion      :  10001.1.15.1
  StrucVersion        :  0x10000
  FileFlagsMask       :  0x3f
  FileFlags           :  4
  FileOS              :  0x50000
  FileType            :  1
  FileSubtype         :  0

# StringTable 0c0a04b0:
  CompanyName         :  "TrySearch"
  FileDescription     :  "TrySearch"
  FileVersion         :  "10001.1.15.1"
  InternalName        :  "TrySearch.exe"
  LegalCopyright      :  "Copyright (C) 2021 TrySearch"
  OriginalFilename    :  "TrySearch.exe"
  ProductName         :  "TrySearch"
  ProductVersion      :  "10001.1.15.1"

  VarFileInfo         :  [ 0xc0a, 0x4b0 ]

=== Packer / Compiler ===

  MS Visual C++ v8.0

Looking at the SECTIONS portion of the binary, we see that each section appears to be intact or normal looking, meaning there are no signs that this malware is packed. Typically, if malware is packed or compressed, the section names will be renamed to something different. For example, UPX, a common software packer, renames the headers to UPX0, UPX1, UPX2, etc.

image

If the malware were packed with UPX, it would look something like below…

image

The RESOURCES portion of the binary typically holds things like images and icons. In this binary, we see that there appears to be a DLL (Dynamic Link Library) at offset 0x37430. This is highly suspicious and typical of dropper malware.

image

The IMPORTS section of the output shows all the dynamically loaded Windows APIs or function calls that this binary uses. At first glance, it looks as if it only uses functions from kernel32.dll. There may be other function calls used that are statically linked. We can verify this later using another tool.

image

If we scroll down a bit on the imports list, we notice that this binary uses the API IsDebuggerPresent. This can be indicative of an anti-reverse engineering technique used by malware authors to prevent the specimen from being debugged. We can confirm this through disassembly and code analysis later.

image

There are a lot of file manipulation APIs such as ReadFile, CreateFileA, and WriteFile which are potential indicators of dropper malware as well.

The last observation made from the pedump output is the PACKER / COMPILER subsection indicating that the specimen was compiled with MS Visual C++ v8.0. This version of MS Visual C++ came out in 2005 which makes it old.

image

If the malware were packed with UPX, this section would look something like below…

image

Strings

Running the strings command on the binary will output just over 4500 lines. We can confirm this with the command string Setup.bin | wc -l which will pipe the strings output into the wc (word count) command and filter based on the line count alone.

image

While it may be helpful to scroll through all the string output, having a targeted approach can help identify some more potential features of this malware.

For example, we can pipe our strings output into grep and filter out everything but our desired string. Below I have grepped for the string .dll to locate other potential DLLs in use.

image

The string ole32.dll seems interesting as this DLL is used for embedding hyperlinks and documents in programs. Other interesting DLL strings are user32.dll, gdi32.dll and gdiplus.dll which contain graphics and windowing APIs.

One hypothesis is that this malware masquerades as a legitimate program providing some form of a GUI (graphical user interface). We will be able to validate this during behavioral analysis.

Grepping for the string This program yields two DOS stubs which is not typical for a Windows PE. This could mean that there is another executable embedded in the original PE file that will be extracted and dropped to the filesystem upon execution. This also strengthens our hypothesis of the DLL found in the .rsrc section.

image

If we grep for the string http to find potential Command and Control nodes, we find a few URLs. One URL that stands out is https://github.com/ControlzEx/ControlzEx which is a GitHub repository for Controlz. Based on the README, it appears to be a .NET framework supporting UI (user interface) features.

image

If we look back at the strings output for DLLs, we notice that there is a ControlzEx.dll listed as well.

Some other strings we could search for would be domain names, anything related to encryption, and anything related to downloading.

PEsec

We can use the tool pesec to check the security features of this PE. This would be more useful for exploit development, but I like to check and see if ASLR (Address Space Layout Randomization) is enabled so I am better prepared when performing code analysis alongside a disassembler. If ASLR is enabled, I will rebase the binary’s address in IDA Pro to match that of the running process. Based on the output of pescan, ASLR is enabled. We will save this info for later.

image

Part I Conclusion

In this article, we began our analysis with some initial recon of automated sandbox reports and then moved on to our own static analysis by identifying various header fields, sections, and imports. We discovered that the specimen is not packed, potentially uses various GUI DLLs, potentially tries to perform anti-debugging, and appears to contain a DLL in its .rsrc section which is highly suspicious. This is not an exhaustive approach to static analysis but it’s a good start and introduction.

This concludes Part 1 of this series. Stayed tuned for Part II where we will disassemble the binary and perform analysis using IDA Pro.