BASIC STATIC TECHNIQUES
We begin our exploration of malware analysis with
static analysis, which is usually the first step in studying
malware. Static analysis describes the process of analyzing the code or structure of a program to determine its
function. The program itself is not run at this time. In
contrast, when performing dynamic analysis, the analyst
actually runs the program, as you’ll learn in Chapter 3.
This chapter discusses multiple ways to extract useful information from
executables. In this chapter, we’ll discuss the following techniques:
Using antivirus tools to confirm maliciousness
Using hashes to identify malware
Gleaning information from a file’s strings, functions, and headers
Each technique can provide different information, and the ones you use
depend on your goals. Typically, you’ll use several techniques to gather as
much information as possible.
10 Chapter 1
Antivirus Scanning: A Useful First Step
When first analyzing prospective malware, a good first step is to run it
through multiple antivirus programs, which may already have identified it.
But antivirus tools are certainly not perfect. They rely mainly on a database
of identifiable pieces of known suspicious code (file signatures), as well as
behavioral and pattern-matching analysis (heuristics) to identify suspect
files. One problem is that malware writers can easily modify their code,
thereby changing their program’s signature and evading virus scanners.
Also, rare malware often goes undetected by antivirus software because it’s
simply not in the database. Finally, heuristics, while often successful in
identifying unknown malicious code, can be bypassed by new and unique
malware.
Because the various antivirus programs use different signatures and
heuristics, it’s useful to run several different antivirus programs against the
same piece of suspected malware. Websites such as VirusTotal (http://www
.virustotal.com/) allow you to upload a file for scanning by multiple antivirus
engines. VirusTotal generates a report that provides the total number of
engines that marked the file as malicious, the malware name, and, if available, additional information about the malware.
Hashing: A Fingerprint for Malware
Hashing is a common method used to uniquely identify malware. The malicious software is run through a hashing program that produces a unique
hash that identifies that malware (a sort of fingerprint). The Message-Digest
Algorithm 5 (MD5) hash function is the one most commonly used for
malware analysis, though the Secure Hash Algorithm 1 (SHA-1) is also
popular.
For example, using the freely available md5deep program to calculate the
hash of the Solitaire program that comes with Windows would generate the
following output:
C:>md5deep c:\WINDOWS\system32\sol.exe
373e7a863a1a345c60edb9e20ec32311 c:\WINDOWS\system32\sol.exe
The hash is 373e7a863a1a345c60edb9e20ec32311.
The GUI-based WinMD5 calculator, shown in Figure 1-1, can calculate
and display hashes for several files at a time.
Once you have a unique hash for a piece of malware, you can use it as
follows:
Use the hash as a label.
Share that hash with other analysts to help them to identify malware.
Search for that hash online to see if the file has already been identified.
Basic Static Techniques 11
Figure 1-1: Output of WinMD5
Finding Strings
A string in a program is a sequence of characters such as “the.” A program
contains strings if it prints a message, connects to a URL, or copies a file to a
specific location.
Searching through the strings can be a simple way to get hints about
the functionality of a program. For example, if the program accesses a URL,
then you will see the URL accessed stored as a string in the program. You can
use the Strings program (http://bit.ly/ic4plL), to search an executable for
strings, which are typically stored in either ASCII or Unicode format.
NOTE Microsoft uses the term wide character string to describe its implementation of Unicode strings, which varies slightly from the Unicode standards. Throughout this book,
when we refer to Unicode, we are referring to the Microsoft implementation.
Both ASCII and Unicode formats store characters in sequences that end
with a NULL terminator to indicate that the string is complete. ASCII strings
use 1 byte per character, and Unicode uses 2 bytes per character.
Figure 1-2 shows the string BAD stored as ASCII. The ASCII string is stored
as the bytes 0x42, 0x41, 0x44, and 0x00, where 0x42 is the ASCII representation of a capital letter B, 0x41 represents the letter A, and so on. The 0x00 at
the end is the NULL terminator.
Figure 1-2: ASCII representation of the string BAD
Figure 1-3 shows the string BAD stored as Unicode. The Unicode string is
stored as the bytes 0x42, 0x00, 0x41, and so on. A capital B is represented by
the bytes 0x42 and 0x00, and the NULL terminator is two 0x00 bytes in a row.
BAD NULL Terminator
ASCII
42 41 44 00
12 Chapter 1
Figure 1-3: Unicode representation of the string BAD
When Strings searches an executable for ASCII and Unicode strings, it
ignores context and formatting, so that it can analyze any file type and detect
strings across an entire file (though this also means that it may identify bytes
of characters as strings when they are not). Strings searches for a three-letter
or greater sequence of ASCII and Unicode characters, followed by a string
termination character.
Sometimes the strings detected by the Strings program are not actual
strings. For example, if Strings finds the sequence of bytes 0x56, 0x50, 0x33,
0x00, it will interpret that as the string VP3. But those bytes may not actually
represent that string; they could be a memory address, CPU instructions, or
data used by the program. Strings leaves it up to the user to filter out the
invalid strings.
Fortunately, most invalid strings are obvious, because they do not represent legitimate text. For example, the following excerpt shows the result of
running Strings against the file bp6.ex_:
C:>strings bp6.ex_
VP3
VW3
t$@
D$4
99.124.22.1
e-@
GetLayout
GDI32.DLL
SetLayout
M}C
Mail system DLL is invalid.!Send Mail failed to send message.
In this example, the bold strings can be ignored. Typically, if a string is
short and doesn’t correspond to words, it’s probably meaningless.
On the other hand, the strings GetLayout at and SetLayout at are Windows functions used by the Windows graphics library. We can easily identify
these as meaningful strings because Windows function names normally begin
with a capital letter and subsequent words also begin with a capital letter.
GDI32.DLL at is meaningful because it’s the name of a common Windows
dynamic link library (DLL) used by graphics programs. (DLL files contain executable code that is shared among multiple applications.)
As you might imagine, the number 99.124.22.1 at is an IP address—
most likely one that the malware will use in some fashion.
Finally, at , Mail system DLL is invalid.!Send Mail failed to send message.
is an error message. Often, the most useful information obtained by running Strings is found in error messages. This particular message reveals two
BAD NULL Terminator
Unicode
42 00 41 00 44 00 00 00
Basic Static Techniques 13
things: The subject malware sends messages (probably through email), and it
depends on a mail system DLL. This information suggests that we might want
to check email logs for suspicious traffic, and that another DLL (Mail system
DLL) might be associated with this particular malware. Note that the missing
DLL itself is not necessarily malicious; malware often uses legitimate libraries
and DLLs to further its goals.
Packed and Obfuscated Malware
Malware writers often use packing or obfuscation to make their files more
difficult to detect or analyze. Obfuscated programs are ones whose execution
the malware author has attempted to hide. Packed programs are a subset of
obfuscated programs in which the malicious program is compressed and cannot be analyzed. Both techniques will severely limit your attempts to statically
analyze the malware.
Legitimate programs almost always include many strings. Malware that is
packed or obfuscated contains very few strings. If upon searching a program
with Strings, you find that it has only a few strings, it is probably either obfuscated or packed, suggesting that it may be malicious. You’ll likely need to
throw more than static analysis at it in order to investigate further.
NOTE Packed and obfuscated code will often include at least the functions LoadLibrary and
GetProcAddress, which are used to load and gain access to additional functions.
Packing Files
When the packed program is run, a small wrapper program also runs to
decompress the packed file and then run the unpacked file, as shown in Figure 1-4. When a packed program is analyzed statically, only the small wrapper
program can be dissected. (Chapter 18 discusses packing and unpacking in
more detail.)
Figure 1-4: The file on the left is the original executable, with all strings,
imports, and other information visible. On the right is a packed executable. All of the packed file’s strings, imports, and other information are
compressed and invisible to most static analysis tools.
Wrapper Program
Original Executable
(Strings and other
information visible)
Packed Executable
(Strings and other
information not
visible)
Start
Start
14 Chapter 1
Detecting Packers with PEiD
One way to detect packed files is with the PEiD program. You can use PEiD
to detect the type of packer or compiler employed to build an application,
which makes analyzing the packed file much easier. Figure 1-5 shows information about the orig_af2.ex_ file as reported by PEiD.
Figure 1-5: The PEiD program
NOTE Development and support for PEiD has been discontinued since April 2011, but it’s
still the best tool available for packer and compiler detection. In many cases, it will also
identify which packer was used to pack the file.
As you can see, PEiD has identified the file as being packed with UPX
version 0.89.6-1.02 or 1.05-2.90. (Just ignore the other information shown
here for now. We’ll examine this program in more detail in Chapter 18.)
When a program is packed, you must unpack it in order to be able to
perform any analysis. The unpacking process is often complex and is covered
in detail in Chapter 18, but the UPX packing program is so popular and easy
to use for unpacking that it deserves special mention here. For example, to
unpack malware packed with UPX, you would simply download UPX (http://
upx.sourceforge.net/) and run it like so, using the packed program as input:
upx -d PackedProgram.exe
NOTE Many PEiD plug-ins will run the malware executable without warning! (See Chapter 2
to learn how to set up a safe environment for running malware.) Also, like all programs, especially those used for malware analysis, PEiD can be subject to vulnerabilities. For example, PEiD version 0.92 contained a buffer overflow that allowed an
attacker to execute arbitrary code. This would have allowed a clever malware writer to
write a program to exploit the malware analyst’s machine. Be sure to use the latest version of PEiD.
Portable Executable File Format
So far, we have discussed tools that scan executables without regard to their
format. However, the format of a file can reveal a lot about the program’s
functionality.
Basic Static Techniques 15
The Portable Executable (PE) file format is used by Windows executables, object code, and DLLs. The PE file format is a data structure that
contains the information necessary for the Windows OS loader to manage
the wrapped executable code. Nearly every file with executable code that is
loaded by Windows is in the PE file format, though some legacy file formats
do appear on rare occasion in malware.
PE files begin with a header that includes information about the code,
the type of application, required library functions, and space requirements.
The information in the PE header is of great value to the malware analyst.
Linked Libraries and Functions
One of the most useful pieces of information that we can gather about an
executable is the list of functions that it imports. Imports are functions used
by one program that are actually stored in a different program, such as code
libraries that contain functionality common to many programs. Code libraries can be connected to the main executable by linking.
Programmers link imports to their programs so that they don’t need to
re-implement certain functionality in multiple programs. Code libraries can
be linked statically, at runtime, or dynamically. Knowing how the library code
is linked is critical to our understanding of malware because the information
we can find in the PE file header depends on how the library code has been
linked. We’ll discuss several tools for viewing an executable’s imported functions in this section.
Static, Runtime, and Dynamic Linking
Static linking is the least commonly used method of linking libraries, although
it is common in UNIX and Linux programs. When a library is statically linked
to an executable, all code from that library is copied into the executable, which
makes the executable grow in size. When analyzing code, it’s difficult to differentiate between statically linked code and the executable’s own code, because
nothing in the PE file header indicates that the file contains linked code.
While unpopular in friendly programs, runtime linking is commonly used
in malware, especially when it’s packed or obfuscated. Executables that use
runtime linking connect to libraries only when that function is needed, not
at program start, as with dynamically linked programs.
Several Microsoft Windows functions allow programmers to import
linked functions not listed in a program’s file header. Of these, the two most
commonly used are LoadLibrary and GetProcAddress. LdrGetProcAddress and
LdrLoadDll are also used. LoadLibrary and GetProcAddress allow a program to
access any function in any library on the system, which means that when
these functions are used, you can’t tell statically which functions are being
linked to by the suspect program.
16 Chapter 1
Of all linking methods, dynamic linking is the most common and the most
interesting for malware analysts. When libraries are dynamically linked, the
host OS searches for the necessary libraries when the program is loaded.
When the program calls the linked library function, that function executes
within the library.
The PE file header stores information about every library that will be
loaded and every function that will be used by the program. The libraries
used and functions called are often the most important parts of a program,
and identifying them is particularly important, because it allows us to guess
at what the program does. For example, if a program imports the function
URLDownloadToFile, you might guess that it connects to the Internet to download some content that it then stores in a local file.
Exploring Dynamically Linked Functions with Dependency Walker
The Dependency Walker program (http://www.dependencywalker.com/), distributed with some versions of Microsoft Visual Studio and other Microsoft development packages, lists only dynamically linked functions in an executable.
Figure 1-6 shows the Dependency Walker’s analysis of SERVICES.EX_ .
The far left pane at shows the program as well as the DLLs being
imported, namely KERNEL32.DLL and WS2_32.DLL.
Figure 1-6: The Dependency Walker program
Clicking KERNEL32.DLL shows its imported functions in the upper-right
pane at . We see several functions, but the most interesting is CreateProcessA,
which tells us that the program will probably create another process, and suggests that when running the program, we should watch for the launch of
additional programs.
The middle right pane at lists all functions in KERNEL32.DLL that can
be imported—information that is not particularly useful to us. Notice the column in panes and labeled Ordinal. Executables can import functions
!
" #
$
%
&
Basic Static Techniques 17
by ordinal instead of name. When importing a function by ordinal, the name
of the function never appears in the original executable, and it can be harder
for an analyst to figure out which function is being used. When malware
imports a function by ordinal, you can find out which function is being
imported by looking up the ordinal value in the pane at .
The bottom two panes ( and ) list additional information about
the versions of DLLs that would be loaded if you ran the program and any
reported errors, respectively.
A program’s DLLs can tell you a lot about its functionality. For example,
Table 1-1 lists common DLLs and what they tell you about an application.
Table 1-1: Common DLLs
DLL Description
Kernel32.dll This is a very common DLL that contains core functionality, such as access
and manipulation of memory, files, and hardware.
Advapi32.dll This DLL provides access to advanced core Windows components such
as the Service Manager and Registry.
User32.dll This DLL contains all the user-interface components, such as buttons, scroll
bars, and components for controlling and responding to user actions.
Gdi32.dll This DLL contains functions for displaying and manipulating graphics.
Ntdll.dll This DLL is the interface to the Windows kernel. Executables generally do
not import this file directly, although it is always imported indirectly by
Kernel32.dll. If an executable imports this file, it means that the author
intended to use functionality not normally available to Windows programs. Some tasks, such as hiding functionality or manipulating processes, will use this interface.
WSock32.dll and
Ws2_32.dll
These are networking DLLs. A program that accesses either of these most
likely connects to a network or performs network-related tasks.
Wininet.dll This DLL contains higher-level networking functions that implement
protocols such as FTP, HTTP, and NTP.
FUNCTION NAMING CONVENTIONS
When evaluating unfamiliar Windows functions, a few naming conventions are
worth noting because they come up often and might confuse you if you don’t recognize them. For example, you will often encounter function names with an Ex suffix,
such as CreateWindowEx. When Microsoft updates a function and the new function is
incompatible with the old one, Microsoft continues to support the old function. The
new function is given the same name as the old function, with an added Ex suffix.
Functions that have been significantly updated twice have two Ex suffixes in their
names.
Many functions that take strings as parameters include an A or a W at the end of
their names, such as CreateDirectoryW. This letter does not appear in the documentation for the function; it simply indicates that the function accepts a string parameter
and that there are two different versions of the function: one for ASCII strings and
one for wide character strings. Remember to drop the trailing A or W when searching
for the function in the Microsoft documentation.
18 Chapter 1
Imported Functions
The PE file header also includes information about specific functions used
by an executable. The names of these Windows functions can give you a good
idea about what the executable does. Microsoft does an excellent job of
documenting the Windows API through the Microsoft Developer Network
(MSDN) library. (You’ll also find a list of functions commonly used by malware in Appendix A.)
Exported Functions
Like imports, DLLs and EXEs export functions to interact with other programs and code. Typically, a DLL implements one or more functions and
exports them for use by an executable that can then import and use them.
The PE file contains information about which functions a file exports.
Because DLLs are specifically implemented to provide functionality used by
EXEs, exported functions are most common in DLLs. EXEs are not designed
to provide functionality for other EXEs, and exported functions are rare.
If you discover exports in an executable, they often will provide useful
information.
In many cases, software authors name their exported functions in a
way that provides useful information. One common convention is to use the
name used in the Microsoft documentation. For example, in order to run a
program as a service, you must first define a ServiceMain function. The presence of an exported function called ServiceMain tells you that the malware
runs as part of a service.
Unfortunately, while the Microsoft documentation calls this function
ServiceMain, and it’s common for programmers to do the same, the function
can have any name. Therefore, the names of exported functions are actually
of limited use against sophisticated malware. If malware uses exports, it will
often either omit names entirely or use unclear or misleading names.
You can view export information using the Dependency Walker program
discussed in “Exploring Dynamically Linked Functions with Dependency
Walker” on page 16. For a list of exported functions, click the name of the
file you want to examine. Referring back to Figure 1-6, window shows all of
a file’s exported functions.
Static Analysis in Practice
Now that you understand the basics of static analysis, let’s examine some real
malware. We’ll look at a potential keylogger and then a packed program.
PotentialKeylogger.exe: An Unpacked Executable
Table 1-2 shows an abridged list of functions imported by PotentialKeylogger.exe,
as collected using Dependency Walker. Because we see so many imports, we
can immediately conclude that this file is not packed.
Basic Static Techniques 19
Like most average-sized programs, this executable contains a large number of imported functions. Unfortunately, only a small minority of those
functions are particularly interesting for malware analysis. Throughout this
book, we will cover the imports for malicious software, focusing on the most
interesting functions from a malware analysis standpoint.
When you are not sure what a function does, you will need to look it up.
To help guide your analysis, Appendix A lists many of the functions of greatest interest to malware analysts. If a function is not listed in Appendix A,
search for it on MSDN online.
As a new analyst, you will spend time looking up many functions that
aren’t very interesting, but you’ll quickly start to learn which functions could
be important and which ones are not. For the purposes of this example, we
will show you a large number of imports that are uninteresting, so you can
Table 1-2: An Abridged List of DLLs and Functions Imported from PotentialKeylogger.exe
Kernel32.dll User32.dll User32.dll (continued)
CreateDirectoryW BeginDeferWindowPos ShowWindow
CreateFileW CallNextHookEx ToUnicodeEx
CreateThread CreateDialogParamW TrackPopupMenu
DeleteFileW CreateWindowExW TrackPopupMenuEx
ExitProcess DefWindowProcW TranslateMessage
FindClose DialogBoxParamW UnhookWindowsHookEx
FindFirstFileW EndDialog UnregisterClassW
FindNextFileW GetMessageW UnregisterHotKey
GetCommandLineW GetSystemMetrics
GetCurrentProcess GetWindowLongW GDI32.dll
GetCurrentThread GetWindowRect GetStockObject
GetFileSize GetWindowTextW SetBkMode
GetModuleHandleW InvalidateRect SetTextColor
GetProcessHeap IsDlgButtonChecked
GetShortPathNameW IsWindowEnabled Shell32.dll
HeapAlloc LoadCursorW CommandLineToArgvW
HeapFree LoadIconW SHChangeNotify
IsDebuggerPresent LoadMenuW SHGetFolderPathW
MapViewOfFile MapVirtualKeyW ShellExecuteExW
OpenProcess MapWindowPoints ShellExecuteW
ReadFile MessageBoxW
SetFilePointer RegisterClassExW Advapi32.dll
WriteFile RegisterHotKey RegCloseKey
SendMessageA RegDeleteValueW
SetClipboardData RegOpenCurrentUser
SetDlgItemTextW RegOpenKeyExW
SetWindowTextW RegQueryValueExW
SetWindowsHookExW RegSetValueExW
20 Chapter 1
become familiar with looking at a lot of data and focusing on some key nuggets of information.
Normally, we wouldn’t know that this malware is a potential keylogger,
and we would need to look for functions that provide the clues. We will be
focusing on only the functions that provide hints to the functionality of the
program.
The imports from Kernel32.dll in Table 1-2 tell us that this software can
open and manipulate processes (such as OpenProcess, GetCurrentProcess, and
GetProcessHeap) and files (such as ReadFile, CreateFile, and WriteFile). The
functions FindFirstFile and FindNextFile are particularly interesting ones that
we can use to search through directories.
The imports from User32.dll are even more interesting. The large number of GUI manipulation functions (such as RegisterClassEx, SetWindowText,
and ShowWindow) indicates a high likelihood that this program has a GUI
(though the GUI is not necessarily displayed to the user).
The function SetWindowsHookEx is commonly used in spyware and is the
most popular way that keyloggers receive keyboard inputs. This function has
some legitimate uses, but if you suspect malware and you see this function,
you are probably looking at keylogging functionality.
The function RegisterHotKey is also interesting. It registers a hotkey (such
as CTRL-SHIFT-P) so that whenever the user presses that hotkey combination,
the application is notified. No matter which application is currently active, a
hotkey will bring the user to this application.
The imports from GDI32.dll are graphics-related and simply confirm that
the program probably has a GUI. The imports from Shell32.dll tell us that this
program can launch other programs—a feature common to both malware
and legitimate programs.
The imports from Advapi32.dll tell us that this program uses the registry,
which in turn tells us that we should search for strings that look like registry
keys. Registry strings look a lot like directories. In this case, we found the
string Software\Microsoft\Windows\CurrentVersion\Run, which is a registry key
(commonly used by malware) that controls which programs are automatically run when Windows starts up.
This executable also has several exports: LowLevelKeyboardProc and
LowLevelMouseProc. Microsoft’s documentation says, “The LowLevelKeyboardProc
hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function.” In other words, this function
is used with SetWindowsHookEx to specify which function will be called when a
specified event occurs—in this case, the low-level keyboard event. The documentation for SetWindowsHookEx further explains that this function will be
called when certain low-level keyboard events occur.
The Microsoft documentation uses the name LowLevelKeyboardProc, and
the programmer in this case did as well. We were able to get valuable information because the programmer didn’t obscure the name of an export.
Using the information gleaned from a static analysis of these imports
and exports, we can draw some significant conclusions or formulate some
hypotheses about this malware. For one, it seems likely that this is a local
keylogger that uses SetWindowsHookEx to record keystrokes. We can also
Basic Static Techniques 21
surmise that it has a GUI that is displayed only to a specific user, and that the
hotkey registered with RegisterHotKey specifies the hotkey that the malicious
user enters to see the keylogger GUI and access recorded keystrokes. We can
further speculate from the registry function and the existence of Software
Microsoft\Windows\CurrentVersion\Run that this program sets itself to load at
system startup.
PackedProgram.exe: A Dead End
Table 1-3 shows a complete list of the functions imported by a second piece
of unknown malware. The brevity of this list tells us that this program is
packed or obfuscated, which is further confirmed by the fact that this program
has no readable strings. A Windows compiler would not create a program
that imports such a small number of functions; even a Hello, World program
would have more.
The fact that this program is packed is a valuable piece of information,
but its packed nature also prevents us from learning anything more about
the program using basic static analysis. We’ll need to try more advanced analysis techniques such as dynamic analysis (covered in Chapter 3) or unpacking (covered in Chapter 18).
The PE File Headers and Sections
PE file headers can provide considerably more information than just imports.
The PE file format contains a header followed by a series of sections. The
header contains metadata about the file itself. Following the header are the
actual sections of the file, each of which contains useful information. As we
progress through the book, we will continue to discuss strategies for viewing
the information in each of these sections. The following are the most common and interesting sections in a PE file:
.text The .text section contains the instructions that the CPU executes. All other sections store data and supporting information. Generally, this is the only section that can execute, and it should be the only
section that includes code.
.rdata The .rdata section typically contains the import and export information, which is the same information available from both Dependency
Table 1-3: DLLs and Functions Imported from PackedProgram.exe
Kernel32.dll User32.dll
GetModuleHandleA MessageBoxA
LoadLibraryA
GetProcAddress
ExitProcess
VirtualAlloc
VirtualFree
22 Chapter 1
Walker and PEview. This section can also store other read-only data used
by the program. Sometimes a file will contain an .idata and .edata section,
which store the import and export information (see Table 1-4).
.data The .data section contains the program’s global data, which is
accessible from anywhere in the program. Local data is not stored in
this section, or anywhere else in the PE file. (We address this topic in
Chapter 6.)
.rsrc The .rsrc section includes the resources used by the executable
that are not considered part of the executable, such as icons, images,
menus, and strings. Strings can be stored either in the .rsrc section or
in the main program, but they are often stored in the .rsrc section for
multilanguage support.
Section names are often consistent across a compiler, but can vary across
different compilers. For example, Visual Studio uses .text for executable
code, but Borland Delphi uses CODE. Windows doesn’t care about the actual
name since it uses other information in the PE header to determine how a
section is used. Furthermore, the section names are sometimes obfuscated to
make analysis more difficult. Luckily, the default names are used most of the
time. Table 1-4 lists the most common you’ll encounter.
Examining PE Files with PEview
The PE file format stores interesting information within its header. We can use
the PEview tool to browse through the information, as shown in Figure 1-7.
In the figure, the left pane at displays the main parts of a PE header.
The IMAGE_FILE_HEADER entry is highlighted because it is currently selected.
The first two parts of the PE header—the IMAGE_DOS_HEADER and MS-DOS
Stub Program—are historical and offer no information of particular interest
to us.
The next section of the PE header, IMAGE_NT_HEADERS, shows the NT headers. The signature is always the same and can be ignored.
The IMAGE_FILE_HEADER entry, highlighted and displayed in the right panel
at , contains basic information about the file. The Time Date Stamp
Table 1-4: Sections of a PE File for a Windows Executable
Executable Description
.text Contains the executable code
.rdata Holds read-only data that is globally accessible within the program
.data Stores global data accessed throughout the program
.idata Sometimes present and stores the import function information; if this section is
not present, the import function information is stored in the .rdata section
.edata Sometimes present and stores the export function information; if this section is not
present, the export function information is stored in the .rdata section
.pdata Present only in 64-bit executables and stores exception-handling information
.rsrc Stores resources needed by the executable
.reloc Contains information for relocation of library files
Basic Static Techniques 23
description at tells us when this executable was compiled, which can be very
useful in malware analysis and incident response. For example, an old compile time suggests that this is an older attack, and antivirus programs might
contain signatures for the malware. A new compile time suggests the reverse.
Figure 1-7: Viewing the IMAGE_FILE_HEADER in the PEview program
That said, the compile time is a bit problematic. All Delphi programs use
a compile time of June 19, 1992. If you see that compile time, you’re probably looking at a Delphi program, and you won’t really know when it was compiled. In addition, a competent malware writer can easily fake the compile
time. If you see a compile time that makes no sense, it probably was faked.
The IMAGE_OPTIONAL_HEADER section includes several important pieces of
information. The Subsystem description indicates whether this is a console
or GUI program. Console programs have the value IMAGE_SUBSYSTEM_WINDOWS_CUI
and run inside a command window. GUI programs have the value IMAGE_
SUBSYSTEM_WINDOWS_GUI and run within the Windows system. Less common subsystems such as Native or Xbox also are used.
The most interesting information comes from the section headers, which
are in IMAGE_SECTION_HEADER, as shown in Figure 1-8. These headers are used to
describe each section of a PE file. The compiler generally creates and names
the sections of an executable, and the user has little control over these names.
As a result, the sections are usually consistent from executable to executable
(see Table 1-4), and any deviations may be suspicious.
For example, in Figure 1-8, Virtual Size at tells us how much space is
allocated for a section during the loading process. The Size of Raw Data at
shows how big the section is on disk. These two values should usually be
equal, because data should take up just as much space on the disk as it does
in memory. Small differences are normal, and are due to differences between
alignment in memory and on disk.
The section sizes can be useful in detecting packed executables. For
example, if the Virtual Size is much larger than the Size of Raw Data, you
know that the section takes up more space in memory than it does on disk.
This is often indicative of packed code, particularly if the .text section is
larger in memory than on disk.
!
"
24 Chapter 1
Figure 1-8: Viewing the IMAGE_SECTION_HEADER .text section in the PEview program
Table 1-5 shows the sections from PotentialKeylogger.exe. As you can see,
the .text, .rdata, and .rsrc sections each has a Virtual Size and Size of Raw
Data value of about the same size. The .data section may seem suspicious
because it has a much larger virtual size than raw data size, but this is normal
for the .data section in Windows programs. But note that this information
alone does not tell us that the program is not malicious; it simply shows that it
is likely not packed and that the PE file header was generated by a compiler.
Table 1-6 shows the sections from PackedProgram.exe. The sections in this
file have a number of anomalies: The sections named Dijfpds, .sdfuok, and
Kijijl are unusual, and the .text, .data, and .rdata sections are suspicious.
The .text section has a Size of Raw Data value of 0, meaning that it takes up
no space on disk, and its Virtual Size value is A000, which means that space
will be allocated for the .text segment. This tells us that a packer will unpack
the executable code to the allocated .text section.
Table 1-5: Section Information for PotentialKeylogger.exe
Section Virtual size Size of raw data
.text 7AF5 7C00
.data 17A0 0200
.rdata 1AF5 1C00
.rsrc 72B8 7400
Table 1-6: Section Information for PackedProgram.exe
Name Virtual size Size of raw data
.text A000 0000
.data 3000 0000
.rdata 4000 0000
.rsrc 19000 3400
!
"
Basic Static Techniques 25
Viewing the Resource Section with Resource Hacker
Now that we’re finished looking at the header for the PE file, we can look at
some of the sections. The only section we can examine without additional
knowledge from later chapters is the resource section. You can use the free
Resource Hacker tool found at http://www.angusj.com/ to browse the .rsrc
section. When you click through the items in Resource Hacker, you’ll see the
strings, icons, and menus. The menus displayed are identical to what the program uses. Figure 1-9 shows the Resource Hacker display for the Windows
Calculator program, calc.exe.
Figure 1-9: The Resource Hacker tool display for calc.exe
The panel on the left shows all resources included in this executable.
Each root folder shown in the left pane at stores a different type of
resource. The informative sections for malware analysis include:
The Icon section lists images shown when the executable is in a file listing.
The Menu section stores all menus that appear in various windows, such
as the File, Edit, and View menus. This section contains the names of all
the menus, as well as the text shown for each. The names should give you
a good idea of their functionality.
The Dialog section contains the program’s dialog menus. The dialog at
shows what the user will see when running calc.exe. If we knew nothing
else about calc.exe, we could identify it as a calculator program simply by
looking at this dialog menu.
The String Table section stores strings.
The Version Info section contains a version number and often the company name and a copyright statement.
Dijfpds 20000 0000
.sdfuok 34000 3313F
Kijijl 1000 0200
Table 1-6: Section Information for PackedProgram.exe (continued)
Name Virtual size Size of raw data
! "
26 Chapter 1
The .rsrc section shown in Figure 1-9 is typical of Windows applications
and can include whatever a programmer requires.
NOTE Malware, and occasionally legitimate software, often store an embedded program or
driver here and, before the program runs, they extract the embedded executable or driver.
Resource Hacker lets you extract these files for individual analysis.
Using Other PE File Tools
Many other tools are available for browsing a PE header. Two of the most
useful tools are PEBrowse Professional and PE Explorer.
PEBrowse Professional (http://www.smidgeonsoft.prohosting.com/pebrowsepro-file-viewer.html) is similar to PEview. It allows you to look at the bytes from
each section and shows the parsed data. PEBrowse Professional does the better job of presenting information from the resource (.rsrc) section.
PE Explorer (http://www.heaventools.com/) has a rich GUI that allows you
to navigate through the various parts of the PE file. You can edit certain parts
of the PE file, and its included resource editor is great for browsing and editing the file’s resources. The tool’s main drawback is that it is not free.
PE Header Summary
The PE header contains useful information for the malware analyst, and we
will continue to examine it in subsequent chapters. Table 1-7 reviews the key
information that can be obtained from a PE header.
Conclusion
Using a suite of relatively simple tools, we can perform static analysis on malware to gain a certain amount of insight into its function. But static analysis is
typically only the first step, and further analysis is usually necessary. The next
step is setting up a safe environment so you can run the malware and perform basic dynamic analysis, as you’ll see in the next two chapters.