Table of Contents for
Practical Malware Analysis

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Practical Malware Analysis by Andrew Honig Published by No Starch Press, 2012
  1. Cover
  2. Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software
  3. Praise for Practical Malware Analysis
  4. Warning
  5. About the Authors
  6. About the Technical Reviewer
  7. About the Contributing Authors
  8. Foreword
  9. Acknowledgments
  10. Individual Thanks
  11. Introduction
  12. What Is Malware Analysis?
  13. Prerequisites
  14. Practical, Hands-On Learning
  15. What’s in the Book?
  16. 0. Malware Analysis Primer
  17. The Goals of Malware Analysis
  18. Malware Analysis Techniques
  19. Types of Malware
  20. General Rules for Malware Analysis
  21. I. Basic Analysis
  22. 1. Basic Static Techniques
  23. Antivirus Scanning: A Useful First Step
  24. Hashing: A Fingerprint for Malware
  25. Finding Strings
  26. Packed and Obfuscated Malware
  27. Portable Executable File Format
  28. Linked Libraries and Functions
  29. Static Analysis in Practice
  30. The PE File Headers and Sections
  31. Conclusion
  32. Labs
  33. 2. Malware Analysis in Virtual Machines
  34. The Structure of a Virtual Machine
  35. Creating Your Malware Analysis Machine
  36. Using Your Malware Analysis Machine
  37. The Risks of Using VMware for Malware Analysis
  38. Record/Replay: Running Your Computer in Reverse
  39. Conclusion
  40. 3. Basic Dynamic Analysis
  41. Sandboxes: The Quick-and-Dirty Approach
  42. Running Malware
  43. Monitoring with Process Monitor
  44. Viewing Processes with Process Explorer
  45. Comparing Registry Snapshots with Regshot
  46. Faking a Network
  47. Packet Sniffing with Wireshark
  48. Using INetSim
  49. Basic Dynamic Tools in Practice
  50. Conclusion
  51. Labs
  52. II. Advanced Static Analysis
  53. 4. A Crash Course in x86 Disassembly
  54. Levels of Abstraction
  55. Reverse-Engineering
  56. The x86 Architecture
  57. Conclusion
  58. 5. IDA Pro
  59. Loading an Executable
  60. The IDA Pro Interface
  61. Using Cross-References
  62. Analyzing Functions
  63. Using Graphing Options
  64. Enhancing Disassembly
  65. Extending IDA with Plug-ins
  66. Conclusion
  67. Labs
  68. 6. Recognizing C Code Constructs in Assembly
  69. Global vs. Local Variables
  70. Disassembling Arithmetic Operations
  71. Recognizing if Statements
  72. Recognizing Loops
  73. Understanding Function Call Conventions
  74. Analyzing switch Statements
  75. Disassembling Arrays
  76. Identifying Structs
  77. Analyzing Linked List Traversal
  78. Conclusion
  79. Labs
  80. 7. Analyzing Malicious Windows Programs
  81. The Windows API
  82. The Windows Registry
  83. Networking APIs
  84. Following Running Malware
  85. Kernel vs. User Mode
  86. The Native API
  87. Conclusion
  88. Labs
  89. III. Advanced Dynamic Analysis
  90. 8. Debugging
  91. Source-Level vs. Assembly-Level Debuggers
  92. Kernel vs. User-Mode Debugging
  93. Using a Debugger
  94. Exceptions
  95. Modifying Execution with a Debugger
  96. Modifying Program Execution in Practice
  97. Conclusion
  98. 9. OllyDbg
  99. Loading Malware
  100. The OllyDbg Interface
  101. Memory Map
  102. Viewing Threads and Stacks
  103. Executing Code
  104. Breakpoints
  105. Loading DLLs
  106. Tracing
  107. Exception Handling
  108. Patching
  109. Analyzing Shellcode
  110. Assistance Features
  111. Plug-ins
  112. Scriptable Debugging
  113. Conclusion
  114. Labs
  115. 10. Kernel Debugging with WinDbg
  116. Drivers and Kernel Code
  117. Setting Up Kernel Debugging
  118. Using WinDbg
  119. Microsoft Symbols
  120. Kernel Debugging in Practice
  121. Rootkits
  122. Loading Drivers
  123. Kernel Issues for Windows Vista, Windows 7, and x64 Versions
  124. Conclusion
  125. Labs
  126. IV. Malware Functionality
  127. 11. Malware Behavior
  128. Downloaders and Launchers
  129. Backdoors
  130. Credential Stealers
  131. Persistence Mechanisms
  132. Privilege Escalation
  133. Covering Its Tracks—User-Mode Rootkits
  134. Conclusion
  135. Labs
  136. 12. Covert Malware Launching
  137. Launchers
  138. Process Injection
  139. Process Replacement
  140. Hook Injection
  141. Detours
  142. APC Injection
  143. Conclusion
  144. Labs
  145. 13. Data Encoding
  146. The Goal of Analyzing Encoding Algorithms
  147. Simple Ciphers
  148. Common Cryptographic Algorithms
  149. Custom Encoding
  150. Decoding
  151. Conclusion
  152. Labs
  153. 14. Malware-Focused Network Signatures
  154. Network Countermeasures
  155. Safely Investigate an Attacker Online
  156. Content-Based Network Countermeasures
  157. Combining Dynamic and Static Analysis Techniques
  158. Understanding the Attacker’s Perspective
  159. Conclusion
  160. Labs
  161. V. Anti-Reverse-Engineering
  162. 15. Anti-Disassembly
  163. Understanding Anti-Disassembly
  164. Defeating Disassembly Algorithms
  165. Anti-Disassembly Techniques
  166. Obscuring Flow Control
  167. Thwarting Stack-Frame Analysis
  168. Conclusion
  169. Labs
  170. 16. Anti-Debugging
  171. Windows Debugger Detection
  172. Identifying Debugger Behavior
  173. Interfering with Debugger Functionality
  174. Debugger Vulnerabilities
  175. Conclusion
  176. Labs
  177. 17. Anti-Virtual Machine Techniques
  178. VMware Artifacts
  179. Vulnerable Instructions
  180. Tweaking Settings
  181. Escaping the Virtual Machine
  182. Conclusion
  183. Labs
  184. 18. Packers and Unpacking
  185. Packer Anatomy
  186. Identifying Packed Programs
  187. Unpacking Options
  188. Automated Unpacking
  189. Manual Unpacking
  190. Tips and Tricks for Common Packers
  191. Analyzing Without Fully Unpacking
  192. Packed DLLs
  193. Conclusion
  194. Labs
  195. VI. Special Topics
  196. 19. Shellcode Analysis
  197. Loading Shellcode for Analysis
  198. Position-Independent Code
  199. Identifying Execution Location
  200. Manual Symbol Resolution
  201. A Full Hello World Example
  202. Shellcode Encodings
  203. NOP Sleds
  204. Finding Shellcode
  205. Conclusion
  206. Labs
  207. 20. C++ Analysis
  208. Object-Oriented Programming
  209. Virtual vs. Nonvirtual Functions
  210. Creating and Destroying Objects
  211. Conclusion
  212. Labs
  213. 21. 64-Bit Malware
  214. Why 64-Bit Malware?
  215. Differences in x64 Architecture
  216. Windows 32-Bit on Windows 64-Bit
  217. 64-Bit Hints at Malware Functionality
  218. Conclusion
  219. Labs
  220. A. Important Windows Functions
  221. B. Tools for Malware Analysis
  222. C. Solutions to Labs
  223. Lab 1-1 Solutions
  224. Lab 1-2 Solutions
  225. Lab 1-3 Solutions
  226. Lab 1-4 Solutions
  227. Lab 3-1 Solutions
  228. Lab 3-2 Solutions
  229. Lab 3-3 Solutions
  230. Lab 3-4 Solutions
  231. Lab 5-1 Solutions
  232. Lab 6-1 Solutions
  233. Lab 6-2 Solutions
  234. Lab 6-3 Solutions
  235. Lab 6-4 Solutions
  236. Lab 7-1 Solutions
  237. Lab 7-2 Solutions
  238. Lab 7-3 Solutions
  239. Lab 9-1 Solutions
  240. Lab 9-2 Solutions
  241. Lab 9-3 Solutions
  242. Lab 10-1 Solutions
  243. Lab 10-2 Solutions
  244. Lab 10-3 Solutions
  245. Lab 11-1 Solutions
  246. Lab 11-2 Solutions
  247. Lab 11-3 Solutions
  248. Lab 12-1 Solutions
  249. Lab 12-2 Solutions
  250. Lab 12-3 Solutions
  251. Lab 12-4 Solutions
  252. Lab 13-1 Solutions
  253. Lab 13-2 Solutions
  254. Lab 13-3 Solutions
  255. Lab 14-1 Solutions
  256. Lab 14-2 Solutions
  257. Lab 14-3 Solutions
  258. Lab 15-1 Solutions
  259. Lab 15-2 Solutions
  260. Lab 15-3 Solutions
  261. Lab 16-1 Solutions
  262. Lab 16-2 Solutions
  263. Lab 16-3 Solutions
  264. Lab 17-1 Solutions
  265. Lab 17-2 Solutions
  266. Lab 17-3 Solutions
  267. Lab 18-1 Solutions
  268. Lab 18-2 Solutions
  269. Lab 18-3 Solutions
  270. Lab 18-4 Solutions
  271. Lab 18-5 Solutions
  272. Lab 19-1 Solutions
  273. Lab 19-2 Solutions
  274. Lab 19-3 Solutions
  275. Lab 20-1 Solutions
  276. Lab 20-2 Solutions
  277. Lab 20-3 Solutions
  278. Lab 21-1 Solutions
  279. Lab 21-2 Solutions
  280. Index
  281. Index
  282. Index
  283. Index
  284. Index
  285. Index
  286. Index
  287. Index
  288. Index
  289. Index
  290. Index
  291. Index
  292. Index
  293. Index
  294. Index
  295. Index
  296. Index
  297. Index
  298. Index
  299. Index
  300. Index
  301. Index
  302. Index
  303. Index
  304. Index
  305. Index
  306. Index
  307. Updates
  308. About the Authors
  309. Copyright

Lab 16-3 Solutions

Short Answers

  1. There aren’t many useful strings in the malware other than import functions and the strings cmd and cmd.exe.

  2. When you run this malware, it appears to do nothing other than terminate.

  3. You must rename the malware to peo.exe for it to run properly.

  4. This malware uses three different anti-debugging timing techniques: rdtsc, GetTickCount, and QueryPerformanceCounter.

  5. If the QueryPerformanceCounter check is successful, the malware modifies the string needed for the program to run properly. If the GetTickCount check is successful, the malware causes an unhandled exception that crashes the program. If the rdtsc check is successful, the malware will attempt to delete itself from disk.

  6. The anti-debugging timing checks are successful because the malware causes and catches an exception that it handles by manipulating the Structured Exception Handling (SEH) mechanism to include its own exception handler in between two calls to the timing checking functions. Exceptions are handled much more slowly in a debugger than outside a debugger.

  7. The malware uses the domain name adg.malwareanalysisbook.com.

Detailed Analysis

As noted in the lab description, this malware is the same as Lab09-02.exe, except with added anti-debugging techniques. A good place to start is by doing Lab 9-2 Solutions or by reviewing your answers to refresh your memory of this malware’s capabilities.

Static analysis of Lab16-03.exe shows it to be similar to Lab09-02.exe, with few strings visible other than cmd.exe. When we load Lab16-03.exe into IDA Pro, we see that much of the same functionality is present in this malware. Example C-150 shows the malware using gethostbyname to resolve a domain and using port 9999, as with Lab 9-2 Solutions.

Example C-150. Same calls from Lab 9-2 Solutions, which resolve a domain name and get a port in network byte order

004015DB         call    ds:gethostbyname
...
0040160D         push    9999                    ; hostshort
00401612         call    ds:htons

Since this malware uses DNS and connects out over port 9999, we set up a dynamic environment using ApateDNS and Netcat. However, when we first run the malware, it doesn’t perform DNS or connect on port 9999. Recall from Lab 9-2 Solutions that the name of the malware needed to be ocl.exe. Let’s see if that is the case here.

Two strings appear to be created on the stack at the start of the malware’s main function: 1qbz2wsx3edc and ocl.exe. We rename the malware to ocl.exe to see if it connects out. It doesn’t, which means the name ocl.exe must be modified before the comparison.

Example C-151 shows the string comparison that checks to see if the launched malware has the correct name.

Example C-151. Using strncmp for the module name comparison

0040150A         mov     ecx, [ebp+Str2] 
00401510         push    ecx                     ; Str2
00401511         lea     edx, [ebp+Str1] 
00401517         push    edx                     ; Str1
00401518         call    _strncmp

At , we see Str2, which will contain the current name of the launched malware. At , we see Str1. Looking back through the code, it seems Str1 is our ocl.exe string, but it is passed to sub_4011E0 before the comparison. Let’s load this malware into OllyDbg and set a breakpoint at the strncmp call at 0x401518.

When we set the breakpoint and click play, we get a division-by-zero exception caught by OllyDbg. You can press SHIFT-F9 to pass the exception to the program or change the options to pass all exceptions to the program.

After we pass the exception to the program, it is handled, and we arrive at the 0x401518 breakpoint. We see that qgr.exe is on the stack to be compared to Lab16-03.exe, so we try to rename the malware to qgr.exe. However, when we try to run it with the name qgr.exe, the malware still doesn’t perform a DNS query or connect out.

The QueryPerformanceCounter Function

We need to review the sub_4011E0 function (where the ocl.exe string was passed) before the strncmp function. Examining sub_4011E0, we see that it calls QueryPerformanceCounter twice, as shown in Example C-152 (in bold).

Example C-152. Anti-debugging timing check using QueryPerformanceCounter

00401219         lea     eax, [ebp+PerformanceCount]
0040121C         push    eax                     ; lpPerformanceCount
0040121D         call    ds:QueryPerformanceCounter
...
0040126A         lea     ecx, [ebp+var_110]
00401270         push    ecx                     ; lpPerformanceCount
00401271         call    ds:QueryPerformanceCounter
00401277         mov     edx, [ebp+var_110]
0040127D         sub     edx, dword ptr [ebp+PerformanceCount] 
00401280         mov     [ebp+var_114], edx
00401286         cmp     [ebp+var_114], 4B0h 
00401290         jle     short loc_40129C
00401292         mov     [ebp+var_118], 2 

The two calls to QueryPerformanceCounter surround code that we will examine shortly, but for now we’ll look at the rest of the function. The malware subtracts the first-time capture (lpPerformanceCount) from the second-time capture (var_110) at . Next, at , the malware compares the result of the time difference to 0x4B0 (1200 in decimal). If the time difference exceeds 1200, var_118 is set to 2; otherwise, it will stay at 1 (its initialized value).

Immediately following this check is the start of a for loop at 0x40129C. The loop (not shown here) manipulates the string passed into the function (arg_0) using var_118; therefore, the QueryPerformanceCounter check influences the string result. The string used in strncmp is different in a debugger versus when run normally. To get the correct string, we’ll make sure that var_118 is set to 1 when this loop is entered. To do this, we set a breakpoint at the strncmp and NOP-out the instruction at . Now we see that the filename must be peo.exe in order for the malware to run properly outside a debugger.

Let’s examine the code surrounded by the two calls to QueryPerformanceCounter. Example C-153 shows the code that starts with a call/pop combination to get the current EIP into the EAX register.

Example C-153. Malware setting its own exception handler and triggering an exception

00401223         call    $+5
00401228         pop     eax
00401229         xor     ecx, ecx
0040122B         mov     edi, eax
0040122D         xor     ebx, ebx
0040122F         add     ebx, 2Ch 
00401232         add     eax, ebx
00401234         push    eax 
00401235         push    large dword ptr fs:0
0040123C         mov     large fs:0, esp 
00401243         div     ecx
00401245         sub     edi, 0D6Ah
0040124B         mov     ecx, 0Ch
00401250         jmp     short loc_401262
00401252         repne stosb
00401254         mov     ecx, [esp+0Ch] 
00401258         add     dword ptr [ecx+0B8h], 2
0040125F         xor     eax, eax
00401261         retn
00401262         pop     large dword ptr fs:0 
00401269         pop     eax

Once the malware gets the current EIP into EAX it adds 0x2C to it at . This causes the EAX register to contain 0x2C + 0x401228 = 0x401254, which references the code starting at . Next, the malware modifies SEH to insert the 0x401254 address into the SEH call chain, as explained in Chapter 15. This manipulation happens from through . When the div ecx instruction executes, it causes a divide-by-zero exception to occur because ECX is set to 0 earlier in the code, and this, in turn, causes the malware exception handler to execute at . The next two instructions process the divide-by-zero exception before returning execution to just after the division by zero. Execution will eventually lead to , where the SEH chain is restored by removing the malware’s exception handler.

The malware goes through all of this trouble to execute code that has a drastic time difference inside a debugger versus outside a debugger. As we explained in Chapter 8, exceptions are handled differently when running in a debugger and take a little bit longer to process. That small time delta is enough for the malware to determine if it is executing in a debugger.

The GetTickCount Function

Next, we set a breakpoint at gethostbyname at 0x4015DB in order to see the domain name used by the malware, and we see that the malware terminates without hitting the breakpoint. Examining the code in the main function, we see two calls to GetTickCount, as shown in Example C-154 (in bold).

Example C-154. Anti-debugging timing check using GetTickCount

00401584         call    ds:GetTickCount
0040158A         mov     [ebp+var_2B4], eax
00401590         call    sub_401000 
00401595         call    ds:GetTickCount
0040159B         mov     [ebp+var_2BC], eax
004015A1         mov     ecx, [ebp+var_2BC]
004015A7         sub     ecx, [ebp+var_2B4]
004015AD         cmp     ecx, 1 
004015B0         jbe     short loc_4015B7 
004015B2         xor     eax, eax
004015B4         mov     [eax], edx 
004015B6         retn

Between the two calls to GetTickCount, the call to sub_401000 at contains the same SEH manipulation code we saw in the QueryPerformanceCounter method we analyzed previously. Next, at , the malware compares the result of the time difference in milliseconds. If the time difference exceeds one millisecond, the code executes the instruction at , which is illegal because EAX is set to 0 in the previous instruction. This causes the malware to crash. To fix this, we just need to make sure that the jump at is taken.

The rdtsc Instruction

Examining the decoding method sub_401300, we see that the code in Lab 16-3 Solutions differs from the decoding method in Lab 9-2 Solutions. In Lab 16-3 Solutions, we find that the rdtsc instruction is used twice, and the familiar SEH manipulation code is in between. The rdtsc instructions are shown in Example C-155 (in bold), and we have omitted the SEH manipulation code from the listing.

Example C-155. Anti-debugging timing check using rdtsc

00401323         rdtsc
00401325         push    eax 
...
0040136D         rdtsc
0040136F         sub     eax, [esp+20h+var_20] 
00401372         mov     [ebp+var_4], eax
00401375         pop     eax
00401376         pop     eax
00401377         cmp     [ebp+var_4], 7A120h 
0040137E         jbe     short loc_401385
00401380         call    sub_4010E0 

The malware pushes the result of the rdtsc instruction onto the stack at , and later executes the rdtsc instruction again, this time subtracting the value it previously pushed onto the stack from the result (EAX) at . IDA Pro has mislabeled the first result as a local variable, var_20. To correct this, right-click var_20 and change the instruction to appear as sub eax, [esp].

Next, the time difference is stored in var_4 and compared to 0x7A120 (500000 in decimal) at . If the time difference exceeds 500000, sub_4010E0 is called at . The sub_4010E0 function attempts to delete the malware from disk, but fails since it is running inside the debugger. Nevertheless, the malware will terminate because of the call to exit at the end of the function.

Summary

Lab 16-3 Solutions uses three different anti-debugging techniques to thwart analysis of the malware inside a debugger: QueryPerformanceCounter, GetTickCount, and rdtsc. The easiest way to beat this malware at its own game is to NOP-out the jumps or force them to be taken by changing them from conditional to nonconditional jumps. Once we figure out how to rename the malware (to peo.exe) in a debugger, we can exit the debugger, rename the file, and effectively use basic dynamic analysis techniques.