Understanding Malware #1
This is a new section I am starting, where instead of reverse engineering malware, I will be demonstrating how certain malware works, at a source code level. Whilst someone malicious could easily take all of the information and put it into their own malware, they would have wasted quite a lot of time, and are not very good at blackhat activities. All of the information that I will be talking about on this site is freely available, from basic socket connections to DLL Injections – allowing any script kiddies to copy and paste malware. As none of the information will include extreme 1337 0dayz, most of their malware will get picked up by Anti Malware programs – just like using an unencoded meterpreter payload. The main reason I am creating this section is to teach people, who are interested in malware analysis, how malware works at a basic level, and what API calls to look out for when determining if something is in fact malicious. Without further ado, let us begin.
#1: Basic Reverse TCP Connection
A reverse TCP connection is used in a lot of remote access malware, in order to get through the firewall. A lot of System Administrators used to only block incoming connections on ports that were not important, such as port 4444, but they did not block outgoing connections. Due to this, attackers were able to gain remote access by having the victim connect back to their system. Now this is becoming a more well known technique, attackers are more and more frequently using HTTP, port 80, to communicate with the victim – this is because it is quite unlikely for a system administrator to block outgoing connections through port 80. In this example, I will be creating a very simple application in C for Windows, that connects to a server, sends a message, receives a message, and then exits. The server will be written in Python and run off of a Linux machine, although it would work on Windows.
Setting Up a Template
First, we need to import the necessary functions:
As you can see, winsock2.h is imported. This is the most important import for this type of program, as it contains code required for communicating over the network. Whilst WinSock is important, you could use the default BSD socket headers, however you would require a Unix Emulation Library, such as CygWin, which allows you to use sys/socket.h. In this example I will be focusing on winsock.h. We also lay out two functions here; WinMain and nConnect_To_Server. WinMain is the entry point for Windows applications, however using main() works as well. nConnect_To_Server is the function which will be responsible for connecting to the server, sending and receiving, and then cleaning up.
For WinMain I used a basic if statement to check the return value of nConnect_To_Server, and if it was 0 (successful connection), the program would print that the connection was successful. Otherwise, it would display that the connection. In a fully developed remote access tool, this would probably contain several functions before the connection routine, in order to check for any active analysis methods. Now we are finished with the WinMain function, we can move onto the connection function.
First things first, when writing a program that utilizes WinSock for communication, you must initialize WinSock by calling WSAStartup. WSAStartup allows you to “request” what version of WinSock you want to use, which in this case is 2.0. It checks to see if WinSock is present on the machine, and then loads the DLL into the process. The information about the loaded WinSock DLL is stored in the &wsaData structure that we declared at the top. After WinSock has been initialized, we can create a Socket Descriptor, using socket(). This is what allows us to communicate over the network. The first argument, AF_INET, specifies that we want to communicate over IPv4, and SOCK_STREAM, which creates a reliable, two way byte stream between the client and the server. If the socket descriptor cannot be created, the return value is INVALID_SOCKET, and so the program checks for that and handles the error. We also store the attackers IP address and Port to connect to in serv_IP and serv_Port.
Now we have created the socket descriptor, we can connect to the remote server using the connect() API call. However, before doing that, we must fill up the Serv_Addr structure with the IP address, Port, and the communication method that we use (IPv4). This will convert the remote address to a machine readable format. We then pass this structure and the socket descriptor we created to the connect() function, which will attempt to make a connection to the attackers machine. If it fails, it returns SOCKET_ERROR. If it does return SOCKET_ERROR, the program uses closesocket() in order to close the socket descriptor. Otherwise, the program continues execution.
Now that we are successfully connected to the remote server, we can send and receive data. In order to send data, we can use the send() API call which takes 4 arguments. The first argument is the socket descriptor which we have created. The second is the data you want to send, and the third is the size (in bytes) of the data. The final argument allows you to set a flag that determines how the data is sent, but that is not important here, so we can set it to 0. If the send() fails, it will return SOCKET_ERROR, so we can use this to perform proper error handling by closing the socket and returning.
The recv() call allows us to receive data from a socket descriptor and store it in a buffer. This call also takes 4 arguments; the socket descriptor, the buffer that will store the received data, the size of the data to be received, and the flags – which will be set to 0 again. As with send() and connect(), as SOCKET_ERROR is returned if the call fails.
Finally, closesocket() is called, with the argument being the socket descriptor itself. It also returns SOCKET_ERROR if the call fails.
Once the socket has been closed, we can simply use return 0; to signal that the function completed successfully. So now we have finished the code, we can go ahead and compile it – in this case I will be using GCC in order to compile the program. As it uses Windows API, this must be compiled on a Windows system.
When compiling the code, if you use the regular:
C:\MinGW\bin> gcc Client.c -o Client.exe
You will receive the error shown in the image above. This is because you must link ws2_32 in order for the program to be able to use Winsock functions. To do this, just type:
C:\MinGW\bin> gcc Client.c -o Client.exe -lws2_32
And we successfully managed to compile the code!
If you want to run it, you will need to have a valid listener (server) to connect to, otherwise this will happen:
If you don’t fancy coding your own server for this program, you can always use nc (netcat), which is nearly always installed on UNIX machines:
All you have to do is set netcat to listen on port 4444, or whichever port you chose, and then start the client up. If you do want to create a simple server, here is a basic one in Python.
Your main() function can be very simple, as it is just calling the connection function. You also only need to import one API in Python; socket.
Here is the basic server/listener that first creates a socket descriptor, just like we did in C. It then binds the program to the host and port, so that no other application can listen on that port. The program then calls listen() which waits for a connection, and sock.accept() will accept the remote connection. recv() receives the message from the client, send() sends the message to the client, and close() closes the socket connection. This is in a try statement, so if there are any errors during runtime, it will exit and return 1. After starting this up and then running the client, we get this:
So that is the end of the first post, hopefully you’ve learnt something from this – or it has refreshed your memory. If you want/don’t want to see more of these types of posts or you have any ideas on what I could talk about for the next one then feel free to DM me on Twitter (@0verfl0w_). If you still don’t understand how something works, the best place to go is MSDN, which is packed full of information about Windows API calls – one of (if not the) best place to go if you have any problems!