back to write-ups
PMA March 21, 2025

PMA Lab 15-2: Anti-Disassembly

Analyze the Malware found in file Lab15-02.exe. Correct all anti-disassembly countermeasures before analyzing the binary in order to answer the questions:

pmachapter-15

Lab 15-2

Analyze the Malware found in file Lab15-02.exe. Correct all anti-disassembly countermeasures before analyzing the binary in order to answer the questions:

Anti-Disassembly Fix:

The Malware contains several Anti-Disassembly techniques. Throughout the code several red highlighted lines are identified by IDA:

image-20250319232012287

In order to fix the disassembly these rogue OPCodes are converted to NOPs:

image-20250319235848653

Eventually, the code is then legible by IDA Pro:

image-20250319235822347

Analysis:

The Malware starts by calling WSAStartup, which initializes the Winsock library for a process. It must be called before using any Winsock functions.

Then, there’s a call to gethostname, which retrieve the local computer’s name. This value is stored in [ebp+name].

The code logic doesn’t make much sense, given the fact that after the call to gethostname, there’s a “test eax, eax”, which will set the Zero Flag if the function is successful, and thus it will jump to the end of the code printing “not enough name”:

image-20250320002051594

Ignoring this validation here, the Malware will enter a loop. On this Loop, it is using [ebp+eax+name]:

image-20250320030950840

Here eax is being used as an index. First eax is set to 0 at 00401073 (first line in the image below). Then, throughout this part of the code, eax is holding the value of the current character that is being compared:

image-20250320031213713

Because of the code logic here, there are some characters that are replaced. For instance, here “Z” is replaced by “A”:

image-20250320031309518

So, in total, the following changes are happening:

  1. Z replaced by A
  2. z replaced by a
  3. 9 replaced by 0
  4. All characters are increased by 1

image-20250320031457169

Thus, the hostname is altered. After looping in this cycle, the Malware will reach loc_40113F:

image-20250320003519040

Here, the Malware calls InternetOpenA, and InterOpenUrlA.

It is possible to see that the first parameter of InternetOpenA (lpszAgent), is stored in address [ebp+name] this is buffer that contains the altered hostname.

Looking at the paramenters of InterOpenUrlA, the second parameter lpszUrl, is the output (eax) of sub_401386:

image-20250320003712822

This function has to return a URL, that can be used in as a parameter to InternetOpenUrlA. And that’s exactly what it does:

image-20250320003922130

This function uses offsets on the stack and moves characters to these offsets, creating the following string (terminated with a null character):

http://www.practicalmalwareanalysis.com/bamboo.html

Then, _strdup is called, which returns a pointer to a string. The parameter that is passed to this function (eax) is a pointer to the base of the previously constructed string. At the end the stack is adjusted and the function returns.

So, this is the URL that is contacted using InternetOpenUrlA.

After contacting this URL, InternetReadFile is called, which will attempt to read up to 65535 bytes.

If the function is successful the content of the response will be parsed, the code will print “internet unable”, and then exits.

Looking at how the Malware is parsing the response, it is possible to see the usage of strstr, which will look for the first occurrence of a substring within a string (in this case the response), and then will return a pointer to the first occurrence of said string within that buffer:

image-20250320004809535

In this case, the Malware is looking for the string “Bamboo::”, which can be some sort of command in the C2 response.

Followed this, there’s a new strstr, this time with the parameter ”::”, and thus the Malware will search for the first occurrence of that substring, within the string. Up until here, the same string (C2 response) is reused.

After both calls to strstr, sub_40130F is called. Its output (eax), is passed to a variable called Filename:

image-20250320005513270

This function is similar to sub_401386, and it just creates a string, which is then returned:

Account Summary.xls.exe

image-20250320005452405

The Malware then allocates a buffer using malloc, and prepares the arguments to InternetOpenUrlA:

image-20250320010533635

The [ebp+Str] string, which is the parsed response after the 2 strstr calls, and will be used as the lpszUrl parameter in InternetOpenUrlA.

Thus, what the Malware is expecting in the response of the first request to the C2 is an URL:

Recapping the parsing steps:

  1. The Malware checks for the “Bamboo::” string
  2. Then checks for the ”::” string
  3. After validating the buffer has what it wants, moves the pointer by 8 bytes (skipping “Bamboo::”) by executing “add ecx, 8”

So, one example of what the Malware is expecting is something like this:

Bamboo::http://www.practicalmalwareanalysis.com/bamboo.exe

Although the Malware is using strstr, it isn’t taking advantage of the output, which moves the pointer to the first occurrence of the substring.

After calling InternetOpenUrlA, the Malware calls InternetReadFile, reading the response into the lpBuffer that was previously allocated using malloc:

image-20250320010930074

Finally, the Malware stores the response into a file (with the name “Account Summary.xls.exe”), and executes it using ShellExecuteA:

image-20250320011101375

C2 Simulation:

In order to test if indeed this is the behavior of the Malware, I decided to patch the code, removing “test eax, eax”, and jump part, after gethostname:

image-20250320012514351

I then launched a Python HTTP Server with 2 files. The first, bamboo.html:

image-20250320024703996

This file contains the String the Malware is looking for. After requesting the C2 server for the bamboo.html, the Malware receives the response:

image-20250320030057488

I then created a C program faking a second stage Malware.

image-20250320030030148

At the beginning the Malware wasn’t running, but then I figured it out that it was due to the fact that InternetReadFileA was forcing only reading 65535 bytes (0xFFFF hex):

image-20250320024922873

After patching this value to increase the size of the dwNumberOfBytesToRead, the second Malware executed sucessfully:

image-20250320024637563

Output from Process Explorer:

image-20250320025035158

Questions:

  1. ​ What URL is initially requested by the program?

    The URL that is initially requested is the following:

    http://www.practicalmalwareanalysis.com/bamboo.html
    
  2. How is the User-Agent generated?

    The Malware uses the hostname as a “template”, which is then modified with the following rules, by iterating over all characters of the string:

    1. Z replaced by A
    2. z replaced by a
    3. 9 replaced by 0
    4. All characters are increased by 1 (ROT-1)
  3. What does the program look for in the page it initially requests?

    The Program looks for a string that contains the prefix “Bamboo::”. It then uses a double call to strstr to position the pointer to that string to whatever comes after the ”::”. Since this string is passed to InternetOpenUrlA, the content that the Malware expects in this String, is a valid URL.

  4. What does the program do with the information it extracts from the page?

    The program downloads whatever is on that URL, stores that on a file called “Account Summary.xls.exe” and then executes it using ShellExecuteA.