Yazzn R6

Packer Info

Today Im going to talk about how I reverse engineered a packed and obfuscated RainbowSix cheat. Lets start with what a packer is. "A packer is a type of software that is commonly used by malware authors and hackers to compress or encrypt an executable in order to obfuscate its code and data" - google.com. Static analysis is not a possibility with these applications since the only readable assembly is the packers stub.

Image 1

Sample Overview

Before formulating any plans of attack its important to get a general understanding of the files/folders that the application uses. Since this application is a DLL its safe to assume that another application is going to load/run our DLL. This is the first time I've seen a loader in the form of a DLL.

When we open run.bat we can see that rundll32.exe is going to run "main" inside of unknown_sample.dll

Image 1

Network Analysis

Usually when I look at what an application is doing network wise I use procmon.exe with the networking filter. This will not always work for all packers. some packers like Themidia if configured correctly can detect process monitoring applications and refuse to work. Luckily for us this packer does not detect procmon.

A quick look at procmon reveals that this applications is connecting to a server on port 443. As I'm sure most of you know, this is one of the ports designated for HTTPS. Now just to be clear, the protocol itself doesnt necessarily need to be HTTPS, but its pretty safe to assume. Our next step will be to open up Charles, or httpdebugger, depending on what you like, and taking a look at what is being sent. This was also around the time I got a reply from the person who emailed this sample in. I responded and asked them if I could possibly get some networking data from them (since they have an active subscription), they aggreed

Image 1

As we can see, there was an HTTPS request sent to wr-cheats.com/loader/mainldr.php. Looking at the query string data we can see what appears to be two hashes and a few other query strings. A closer look at these hashes reveals that both of their lengths are 32 hex charators long or 16 bytes (the same size as MD5). Lets break down each query string and what it appears to be used for.

  • action=getguid, theres also getldr (get loader) and getver (get version).
  • gameid=6, not really sure what this is for, maybe 5 is rust etc.
  • guid=eb382a028a7ff494997cbe535b0fb8dd, this is 123-[your hwid here (probably drives)] MD5 hashed, talk more about this in a bit.
  • rand=a26543d34a53aff0fe4cbea4f8614e1d, talk more about how this hash is derived in a bit.
  • ver=3, not sure if this is the version or not because I think that this cheat has been around longer then three seige updates.
  • Lets look at a networking sample from the person who submitted the sample. As you can see the server is returning a hash. I assumed that the server and the client both compute a hash and if they are equal then you have a valid hardware ID/active sub.

    (Image of getguid response from valid HWID/Sub.)

    After that it seams that the loader is downloaded from the server and then a hash of the version is also downloaded.

    I think its important that we always look at the networking that is going on before we jump into handling the binary. Almost all of the samples I get use HTTP(s) which offers little to no security. People who make malware/game cheats dont exhibit very good networking skills so altering an application via the network is usually one of the easier things to do. Nevertheless lets continue on to dumping the cheat and looking at it in ida.

    Network Overview

  • Client ---> Server: getguid request (Validate hwid/sub)
  • Server ---> Client: Either returns <--- This Hardware Id does not have an active sub, or a hash signifying hwid/sub.
  • Client ---> Server: Gets the actual cheat (dll)
  • Server ---> Client: Sends file.dll (cheat)
  • Client ---> Server: Get version of loader (MD5 hash)
  • Server ---> Client: Sends back a hash of the current version.
  • API Monitor/IDA Pro/Dump Analysis

    Since this application is packed we arent going to see much by just opening it in IDA. Lets dump it while its running and have a look at the imports. Since we saw some hashes earlier I'm going to keep my eyes open for anything MD5 hash related.

    After IDA finished I was able to see what the application was importing. The first handfull of imports is exactly what I was looking for.

    Now that we have an idea of how these hashs are created lets look at how they are made in Api Monitor. As we can see below, we are infact dealing with MD5 as suspected. Lets try and find how our guid is created. I have blurred some of this image since i cant remember if I spoofed my hardware ID or not.

    CryptHashData: The CryptHashData function adds data to a specified hash object. This function and CryptHashSessionKey can be called multiple times to compute the hash of long or discontinuous data streams.

    (Image of how our GUID is created)

    As you can see "123-" is prepended to our hwid (probably harddrive id) and then "lol" is appended. It is then hashed and the result is our "guid". This is shown below.

    CryptGetHashParam : The CryptGetHashParam function retrieves data that governs the operations of a hash object. The actual hash value can be retrieved by using this function.

    (Image of my GUID in bytes represented in HEX)

    After this another hash is computed that will be the expected result from the server if our hwid/sub is active. As you can see it takes a previous hash and appends "ichfickallenutten" or "Ich fick alle Nutten" which means "I fuck all hookers" in english. Interesting.

    (Image of the data that is hashed to give us the expected response from the server)
    (Image of the expected response from the server in HEX from)

    Plan Of Attack

    Now that we understand how the application works lets think of a few ways we can attack this application. Since this application is a DLL we can simply load it into our EXE with LoadLibrary. Since we know how the hashes are created we can simply hook the hash functions to return what we want. Putting all of this together we can make an executable that will import advapi.dll, hook specific functions and then include unknown_sample.dll and run it. The loader will also be effected by the hook since it is loaded into the same context/virtual memory as our executable.

    One such way of hooking would be to hook the EAT (Export Address Table). The EAT table contains RVA's (Relative Virtual Addresses) to the addresses of the actual functions.

    An example of how my exploit could work:

  • Import advapi.dll (the DLL containing the functions we are interested in hooking)
  • Overwrite the EAT table inside of advapi.dll so when GetProcAddress is called with CryptGetHashParam it returns the address of my function.
  • Finally my CryptGetHashParam will write to pdData and pdwDataLen whatever data that I want. This will be useful later when I want to force all hashs to be one thing.
  • To bad this is not possible due to the fact that the address of the function I define (which will be called instead of real CryptGetHashParam) is behind the base address of advapi.dll. In another words the address of my CryptGetHashParam is less then the base address of advapi.dll. The RVA of to my function will be bigger then 4 bytes! No good!

    Instead of writing an EAT hook im going to write a "trampoline" in assembly to make the execution of anything calling CryptGetHashParam jump to my CryptGetHashParam.

    Here is how the exploit is going to work:

  • GetProcAddress(LoadLibrary("advapi.dll"), "CryptGetHashParam"), this will get the address of the real CryptGetHashParam
  • mov rax, [absolute address], we are going to write this assembly to the address of CryptGetHashParam, then we are going to write jmp rax. This will give us the effect of a trampoline so everytime CryptGetHashParam is called it just calls my function. On another note the only way to call the original CryptGetHashParam is to write to bytes back in and then call it. I didnt ever need to actually call the original function since I already knew what I wanted the function to return.
  • After I set my hook up I then went on to auto loader_main = ((dll_main)GetProcAddress(LoadLibrary("unknown_sample.dll"), "main"));. I loaded the DLL loader and executed its main just as rundll32.exe would have.
  • Once we have the hook inplace we can just make it return the hashes from the person who sent me the loader. We should also emulate the webserver just in case anything crazy happens and the creator of this cheat decides to make file.dll a RAT.
  • And boom! All we need to do now is emulate the webserver (install self signed certs, add a line to the hosts file, etc). As you can see it works!

    As you can see the cheat now things that my code is the server and fully trusts it. On the other hand preventing attacks like these can be done very easily. All one has to do is to hash the public key of the server at compiletime and then compare hashes at runtime.