Post

PMA - Lab 09-01

PMA - Lab 09-01

Questions

Analyze the malware found in the file Lab09-01.exe using OllyDbg and IDA Pro to answer the following questions. This malware was initially analyzed in the Chapter 3 labs using basic static and dynamic analysis techniques.

1
2
3
4
5
6
7
Questions:
1. How can you get this malware to install itself?
2. What are the command-line options for this program? What is the password requirement?
3. How can you use OllyDbg to permanently patch this malware, so that it doesn’t require the special command-line password?
4. What are the host-based indicators of this malware?
5. What are the different actions this malware can be instructed to take via the network?
6. Are there any useful network-based signatures for this malware?

Note: This is the same file as in Lab 03-04!

Answers

Analyzing the Malware

Note: I answer all the questions at the end.
Let’s start by opening “Lab09-01.exe” with x32dbg, then let’s press on “run” to get to the entry point:
Files

Now that we are at the entry point, let’s go down and search for a call (with an address that is not recognized as a known function) with the GetCommandLine function before it:
Files

We can see the call to the address 0x402AF0 at 0x403945 and this is our main, another option is to open this in IDA and look at main address there (because IDA can find main):
Files
Files

Now that we found main, let’s put a breakpoint at it (F2 on the line) and start run there, we can see that at the start there is a check if the number of command line arguments is equals to 1:
Files

We pass it because we didn’t provide any arguments.

Note: the order of parameters…
Files

Now we enter the function 401000 and we can see there are registry checks there:
Files

we can see in the picture above that it checks if the registry path “SOFTWARE\Microsoft \XPS” exists (Note the space). And base on my answers for Lab 6-3 question 4 - from this link: How to read a registry key and its values (VBScript)
Files

So we can see its in HKLM, so the path is “HKLM\SOFTWARE\Microsoft \XPS”. We can see that it got a non 0 return value, meaning it doesnt exists, to we dont take the “je” (jump equals) and we set eax to 0, and return back.

Because of than, when it returns, it gets to the function 0x402410:
Files

In that function, we can see calls to GetModuleFileName, and based on the parameters we know its the current file name (Because hModule is 0):
Files
Files
Files

We can now follow the lpFileName address in dump, as I showed in the picture above, and see what we get back, so after we run over the call, we can see at that address we have the file path:
Files

After that the call to “GetShortPathNameW” - retrieves the short path form of the specified path. So it turns to this:
Files

Now after some memory operations we can see the call to ShellExecute:
Files

Where the parameters lpFile and lpParameters are on the stack:
Files

So it calls cmd.exe and tries to delete the Lab09-01.exe file from disk.
But we have an open handle to the file because we have it open in x32dbg, so the deletion failed.
Then the program exits on the next call.

So at this point we can provide more command line arguments to satisfy the check at the start.

Now if we remember what we saw when we analyzed the program at Lab 3-4, when we run strings, we saw 3 options that we had guessed are for the parameters:
Files We can try to use those.

Another option is to open it in IDA and find those parameters, we can go to main and check the path where argc is not equals to 1:
Files

We can see a “cmp” at the bottom, where argv+4 (Which is “Str1” at the end) is compared with a string, let’s check this string:
Files

Now we need to turn it to a string, let’s press “a” on it, and we can see it is one of the parameters:
Files

Following that, we have a few more checks, so we also convert them:
Files

So in IDA we found “-c” in addition to the rest:
Files

The options are: “-cc”, “-c”, “-re”, “-in”.

Now that we know at least one of the parameters, let’s continue with providing the first one, “-in” as an argument to x32dbg.
To do this we press: File -> Change Command Line:
Files
Then let’s add -in to it:
Files
Now when we restart and run again, we can see that it is actually taking the jump (the red line, ZF=0) after comparing the number of arguments, meaning we succeeded in changing the command line:
Files

Ok, so we can see that the next call is to 0x402510 at the address 0x402B2E, and we can see that it passes the pointer to the last element in argv to that function:
Files

Now, in this section we have at least 2 possible options, we can fully analyze the function, or we can understand that it just checks the parameter (for something like a password) and instead of analyzing it, we can just patch the binary to always return the positive result.
So let’s do both options!

Option 1 - Analyzing:

At the start of the function 0x402510, we can see it calculates the length of the parameter sent (the last element in argv - which is “-in” right now) to 4 and if its not 4 it take that jump and exit this function:
(“repne scasb” is strlen, ecx will be the size after the “not” and “add”)
Files

So we know that the last parameter should be 4 characters long, let’s see more of this function by changing the ZF register on the jump to be zero and continue the function analysis:
Files
And we can see it will now take the jump:
Files

We can see that it starts by comparing the first character of our input (corrently “-in”) which is “-“ to the letter “a”:
Files

Let’s again change the flags (ZF) and continue even though we failed the check.
So the second checks basically substracts the first letter (found in edx) from the second character (found in al) and makes sure the result is equals to 1, meaning that because the first character is “a” the second one should be “b”:
Files

45(“-“) - 105(“i”) = 60(“<”) (example of the input “-in”):
Files

Now, because the next character is based on the ones before it, we can modify the command line and add “ab” to the commandline for now:
Files

Now we run again to get the third value. In here, it’s multiplying al (1) by dl (63) meaning that the next value will be 0x63=”c”, we can now change the command line and go again.
Files

In the last one, it just adds 1 to the last value, so the last letter is “d”
(because as we know from the start, the argument should only be 4 chars long)
Files

So after changing the command line and adding “abcd” at the end, we can see that it passes the function successfully and we can continue after.

Option 2 - Patching:

We can see that the first section we analyzed checked if we entered 4 character long last argument:
Files

And if we didn’t, it takes the jump at 0x402527 to 0x40252D. There, we can see “xor eax eax” meaning eax will return 0, and it jumps to 0x4025A0 which is the end. That means that unsuccessful runs will return 0, while we can see that a successful run will return eax=1:
Files

So let’s patch this function to always return 1 no matter what!

To do that we will patch the following into the executable:

1
2
B8 01 00 00 00     MOV EAX, 0x1 
C3                 RET

Now let’s start patching the binary - the way we do that is as follows:
Because it “call”s the function, we can immidiatly at the start of the subroutine patch the change we want (to return eax=1). After that, ret will return and fix the stack, so we are just skeeping all the rest of the logic in this function.
We start by Right-Clicking on the address we want to patch (the start of the funcion in our case) -> Assemble
Files
In here, we write the assembly we want instead (make sure “Keep Size” is not selected because our instruction is longer and that could break the exe):
Files
Then we click ok, we can see it changed the bytes at that address (they are now in red), and it opened again at the next instruction:
Files
So let’s also change the next instruction to “ret” and click ok:
Files
Now we can see what we changed:
Files
Now let’s save the patch - click: File -> Patch file
Files
Then in the window that opens, we can see our changes. We can then select what to patch, in this case we want everything that we did, so let’s click “Patch File” to save the patched file:
Files
And give it a name:
Files
Then we just open the patched file in x32dbg instead, and we now have the patch! So let’s continue with our analysis.

Parameters Option: “-in”

We can see next that we pass both our parameter (“-in” in that case, based on our cmdline) and another hardcoded string (“-in”) again to the function:
Files
Note: we can use IDA to quickly see that this function at 0x40380F is really “__mbscmp”:
Files

So it compares our argument with the string “-in”, and based on that it jumps (this is the comparison we discovered before, it just compares to the possible arguments we can give the malware and acts accordingly…)
We can see after that, because we did provide the “-in” argument, it has a check for 3 arguments provided in general (argc=3):
Files

Because our command line is “lab09-01.exe -in abcd” it passed this check. If we wanted to do this without the password - by patching, we can change this check or just provide a random string after “-in”.

Next we can see a call to get the executable name:
Files

And right after, we can see a call to the address 0x402600 where it passes the executable name as a parameter:
Files

Now we get to a very long function, so let’s glance over the function and stop on the interesting calls.
We can see a call to OpenSCManagerA and to OpenServiceA right after, with the service name being “Lab09-01” - the file name:
Files
Files
Files

It then checks if this service exists, and take the jump if it doesn’t. After that we can see that it calls CreateServiceA:
Files
Files
If not, it calls ChangeServiceConfigA.

After that we can see it copies the file to the path “C:\WINDOWS\system32\Lab09-01.exe”:
Files

Then, we can see a call to 0x4015B0, so let’s take a look in it. We can see another call inside it to 0x4014E0 where it passes both the kernel32.dll path, and our malware path (in system32). Then it opens the kernel32.dll file, and calls GetFileTime - which retrieves the date and time that a file or directory was created, last accessed, and last modified.
Files

After, it opens our malware file “Lab09-01” in system32, and call SetFileTime - which sets the date and time that the specified file or directory was created, last accessed, or last modified.
Files
So it sets the file time of “C:\windows\system32\Lab09-01.exe” to the same time as kernel32.dll - this is preforming a technique called “timestomping”.

After that we can see a call to 0x401070 with those arguments:
Files

In it, we can see a call to RegCreateKeyExA - which creates the specified registry key to the key “HKLM\SOFTWARE\Microsoft \XPS” (Note: With a space after Microsoft!), and if the key already exists, the function opens it.
After that it calls RegSetValueExA to set the subkey “Configuration” with the type of “REG_BINARY”. To get the value, we can see cbData is equals to 1000 meaning - “The size of the information pointed to by the lpData parameter, in bytes.”
Files
Files
To see the full 1000 bytes, we can do the following: Right Click the address on the stack -> Follow DWORD In Dump -> Select a Dump and then we can see the value in the Dump:
Files
In it, we can see it contains 4 strings:

  1. ups
  2. hxxp://www[.]practicalmalwareanalysis[.]com
  3. 80
  4. 60

This looks like a network configuration.
After that the malware finished execution.

But when we provided the “-in” option we can see at the start, that there is also an option with one more argument (that we missed):
Files
We can see that in that option, we can also provide the service name as an argument in the command line:
Files

Now that we finished with this option, we can check the other command line options to see what they do.
(Note - The options: “-cc”, “-c”, “-re”, “-in”)

Parameters Option: “-re”

Let continue with the option “-re” but go over it quickly in IDA because we renamed a number of functions related to it.
We can see that as it was for the “-in” option, in this option we also can have 1 more parameter:
Files

And we can see it has the same usage - to provide a custom service name:
Files

Now when we enter it we can see this is the exact same as in “-in” instead its deleting everything:
Files

It deletes the service, then it deletes the file in system32:
Files

After that, it is setting up the config in the registry, and then we can see a new call we didn’t see in the “-in”:
Files

We can see it is used to delete the registry config:
Files
So this option is just to delete the malware!

Parameters Option: “-c”

Next we can take a look at the “-c” option.
Now, because we renamed those in IDA we can quickly know what this option does.
we start by making sure there are 7 arguments (Lab09-01.exe -c abcd ??? ??? ??? ???):
Files

So we have 4 new parameters, let’s check what they do.
We can see that all the malware does with them is just pass it to the function we renamed as “mw_set_up_config_registry”:
Files

So we can put custom options instead of those 4:

  1. ups
  2. hxxp://www[.]practicalmalwareanalysis[.]com
  3. 80
  4. 60

So this option is used to change the registry config to something custom!

Parameters Option: “-cc”

let’s continue with the last option “-cc”.
We can see that this option needs 3 parameters, we know those are (Lab09-01.exe -cc abcd)
Files

We can then see that there is only a call to 2 subroutines:
Files

Going over the first one “sub_401280” we can see it queries the key “Configuration” in “HKLM\SOFTWARE\Microsoft \XPS” for its value:
Files

Then we have a long section of memory operations, and looking at it and viewing it in x32dbg, its saves the values found in the registry to the addresses sent as parameters to this function:
Files
We can see that the stack after the call to the subroutine contains those strings in the addresses that were sent:
Files
Then we can see the call to the second function, where it passes all those parameters including a string format:
Files
Meaning this is probably printf.
We can also take a look at it in IDA. We can remember this exact function format from past labs we have done, this is a printf subroutine:
Files
let’s check and see if we will get the print:
Files
Yes, this option is to print the config.

Parameters Summary

So to sum those parameters: “-cc”, “-c”, “-re”, “-in”

  1. -in = Install the malware
  2. -re = Remove the malware
  3. -c = Change the config
  4. -cc = Print the config

Parameters Option: Nothing Provided

Now we have one last option - if we don’t provide any parameters, but the sub_401000 will return eax=1 so it wont delete itself:
Files
And we can see that the sub_401000 just checks if the registry key exists, meaning it will happen only when the malware is installed:
Files
If it does, we can see a call to “sub_402360” let’s check it quickly in IDA for now:
Files
The general flow of the function:
Files
So the main functionality is in the middle, in “sub_402020”.
In this function we can see that it gets a string value from the “sub_401E60”, then it compares it to some strings:
Files
The strings are:

  1. SLEEP
  2. UPLOAD
  3. DOWNLOAD
  4. CMD
  5. NOTHING

Those look like commands, let’s see what each command does.

Command: SLEEP

The check for the command:
Files
What it does:
Files
So this function uses strtok - which is used for tokenizing strings. These strings are a set of tokens using delimiters/separators characters.
Meaning it starts by splitting the input by “ “, then taking the first string “SLEEP”, but it wants what’s after it, so it calls strtok again, and it gets what’s after the “ “. It uses atoi to convert it from an int to a string, then it multiplies it by 1000 and call Sleep, meaning it will be the number of seconds.

So the format for sleep is: “SLEEP num_of_seconds”.

Command: UPLOAD

The check for the command:
Files
What it does:
Files
We can see that the format for the UPLOAD is “UPLOAD int string”.
Let’s see how the string and int get used in “sub_4019E0” (Note: “name” is the url gotten from the registry config):
Files
So we can see that it passes the “name” (the string) and the “hostshort” (the int), let’s see their usage in “sub_401640”:
Files
Files
We can see the following flow:

  1. WSAStartup - Initiates the use of the Winsock DLL by a process.
  2. gethostbyname - Retrieves host information corresponding to a host name from a host database.
  3. socket - Based on parameters, IPv4, SOCK_STREAM, IPPROTO_TCP.
  4. htons - Function converts a ”u_short” from host to TCP/IP network byte order (which is big-endian).
  5. connect - Establishes a connection to a specified socket. I wanted to take a deeper look at the connect function, to understand where the IP and PORT comes from.
    So we know “name” is the sockaddr structure, based on the parameters provided to the connect function:
    Files
    This structure will contain the port and ip, and as we can see it is in “var_1A4” which is a local variable:
    Files
    Now we can see it accesses it a couple of times, for example it sets an offset in it to the return value of htons.
    To understand that structure, we can take a look at it:
    Files
    Note: The structure changes based on “sa_family”, those values can be found in winsocket.h, and if we look above we can see it sets it to 2 = AF_INET:
    Files
    So we have the “sockaddr_in” structure, if we take a look, sa_data at zero offset is the port - meaning the result of htons is the port. Another thing to look at is that it movs eax to offset 2 at 0x004016D7 (which should be the IP address, because its after the port which is saved in a u_short -> 2 bytes). That value comes from edx, which comes from ecx, which comes from eax+0x0C where eax is “var_194” which comes from the return value of gethostbyname and that is the struct hostent:
    Files
    Now based on that struct, “char*” byte size in 32 bit is 4 bytes, and short is 2 bytes, meaning “char** h_addr_list” is at offset: 4 + 4 + 2 + 2 = 12 = 0xC, so it is indeed getting the first IP address in “h_addr_list”. It connect to it and if it is successful, it should return 0, meaning it takes the jump (jnz) and it will return eax = 0.
    After that, it returns to the calling function, and we can see it creates a file based on the string parameter provided (after the “UPLOAD”):
    Files
    And right after is recieves the data from the socket, it writes it to that file:
    Files
    And it also timestomp it at the end:
    Files

So the option Upload - connects to the remote server, receives data and write it to a local file. So unlike its name, it is actually downloading a file, not uploading.
And the format for UPLOAD is: “UPLOAD port_to_connect_to file_name_to_create”.

Command: DOWNLOAD

This one looks almost exactly like UPLOAD, so let’s go over it quickly.
The parameters we provide are almost exactly the same, so the format is also “DOWNLOAD int string
Files
We can see a call to the exact same subroutine as in UPLOAD sub_401640, which I renamed:
Files
After that it opens a file and read from it:
Files
And send it back over the socket:
Files

So this option connects to the remote server, opens a file, reads its data and sends it back. so unlike its name, it is actually uploading a file, not downloading. And the format for DOWNLOAD is: “DOWNLOAD port_to_connect_to file_name_to_send”

Command: CMD

It looks like the format for this command is: “CMD int`string”.
Files
Then it sends the string and “rb” to _popen - Creates a pipe and executes a command.
Files
Files
And if it worked, it goes here, and we can see a call to sub_401790:
Files
We can see it sends “name” which is the URL sent that was provided as an argument to the subroutine.
Let’s see what sub_401790 does:
It starts by connecting to the URL in the provided port.
Files
Then it reads from the “stream” which it has passed as an argument to this function. This stream was the return value from _popen, meaning it reads the output of the passed command, and then send it back over the network.
Files

So this option executes a command and sends the output back to based on the port provided.
And the format for CMD is: “CMD port_to_connect_to`command to execute

Command: NOTHING

It does nothing:
Files

Getting the Commands

Now the last part we are missing is where do they get those commands from?
Let’s take a look at the subroutine that we have passed before - “sub_401E60”: Files
Now we can see a few calls to other subroutines, instead of reversing it, we can debug it quickly in x32dbg.
General flow:
Files
The first two calls are to those 2 subroutines:
Files
Let’s see what we get in the return values in x32dbg:
So let’s open it, make sure we installed the malware (using “-in” and passwords parameters), and then change the commandline back to include nothing and press:
Ctrl+G -> enter “402036” -> F2 - to put a breakpoint on the call to “sub_401E60”, then step into and get to the function calls we found above.
Before calling “sub_401420”:
Files
And after:
Files
So we can see it returns the URL found in the registry config key, let’s check what the next subroutine returns.
We can see it returned 0x50 (80) and thats the port:
Files

Now let’s take a look at the next function - “sub_401D80”:
Files
We can see that it gets a seemingly random value, let’s run it a few times and see the result:
Files
A few examples:
Files
Files
Files
So we can see a format: “XXXX/XXXX.XXX” where X=[a-zA-Z0-9]
This looks like a URL, let’s see the next subroutine “sub_401AF0”:
Files
And we can see that it sends this URL like format to that subroutine:
Files
But it failed, we didn’t take the jump right after:
Files
So let’s take a look inside it, and check if we renamed something inside it in IDA already:
Files
So we can see at the start a call to connect by the URL and PORT provided, let’s see in x32dbg what we provide it:
Files
So yes, it connect to “hxxp://www[.]practicalmalwareanalysis[.]com” on port 80, let’s see what happens after.
We can see the following strings being used: “GET “ and “ HTTP/1.0\r\n\r\n”
Files
Files
and those functions being called:
Files
And
Files
Let’s debug and see those being called. We can see that it failed the jump to connect (makes sense…), so let’s change the flag and continue:
Files
Files
Now we can see we have reached the “send” API, based on the address 0x401BE6 (IDA translated the ordinal for us):
Files
Files
We can see that we are passing the buffer to the send function as: “GET YL4u/rfBi.zNV HTTP/1.0\r\n\r\n” and because we know the HTTP protocol (before HTTP/2) expects all data in human readable format, we are sending an HTTP Get request to “hxxp://www[.]practicalmalwareanalysis[.]com:80/YL4u/rfBi.zNV” where the last part is the randomly generated page we get.
After that we can guess that we receive the page, and let’s check what we do with it after:
Files
we can see that it transfers the receive data to the “Str” parameter we sent this function.
Then let’s take a look at what happens after this subroutine:
Files
We can see that it calls the function _strstr which “returns a pointer to the first index of a specified substring in another string. The main goal of strstr() is to search for a substring within a larger string and it helps to find the first occurrence of a specified substring.”
So it searches for the occurrence of “`'`'`” and uses that to split the returned value. - This is where we get the commands from!

Now we finished to analyze all of the malware, let’s fill out the questions below!

1. How can you get this malware to install itself?

As we saw when we analyzed the malware, for it to install itself we need to provide it with the following command line: “Lab09-01.exe -in abcd”. “-in” to install the malware and the password we need to provide.

2. What are the command-line options for this program? What is the password requirement?

Based on our analysis, we saw the password is “abcd”.
The command-line options are:

  1. -in = Install the malware
  2. -re = Remove the malware
  3. -c = Change the config
  4. -cc = Print the config

3. How can you use OllyDbg to permanently patch this malware, so that it doesn’t require the special command-line password?

We saw how to do that in our analysis - I showed both options, how to find the password and how to patch it.

4. What are the host-based indicators of this malware?

  • Registry Key: “HKLM\Software\Microsoft \XPS\Configuration”
  • A Service: “??? Manager Service” - where “???” can be a parameter provided at install time or the name of the malware executable.
  • A Local File: The malware copies itself to system32, where its name can be the original malware executable name or the service name.

5. What are the different actions this malware can be instructed to take via the network?

  1. SLEEP - Sleeps for the number of seconds provided.
    Format: “SLEEP num_of_seconds
  2. UPLOAD - So this option connects to the remote server, receives data and write it to a local file (so unlike its name, it is actually downloading a file, not uploading)
    Format: “UPLOAD port_to_connect_to file_name_to_create
  3. DOWNLOAD - This option connects to the remote server, opens a file reads its data and sends it. So unlike its name, it is actually uploading a file, not downloading.
    Format: “DOWNLOAD port_to_connect_to file_name_to_create
  4. CMD - executes a command and sends the output back.
    Format: “CMD port_to_connect_to`command to execute
  5. NOTHING - Does nothing.
    Format: “NOTHING”

6. Are there any useful network-based signatures for this malware?

An HTTP connection to: “hxxp://www[.]practicalmalwareanalysis[.]com:80/XXXX/XXXX.XXX” where the “X”s are random characters in [a-zA-Z0-9] - And there are no other HTTP headers.
Note: www[.]practicalmalwareanalysis[.]com and port 80 are configurable in the registry config! But those are the default values.

This post is licensed under CC BY 4.0 by the author.