Fwrapper Update & Example

A very small change has been pushed to the Bitbucket repo for fwrapper. I removed the static name for the class instance. When I first wrote the script I thought why would anyone need two instances? Today I came across a good example of when we would need that. A piece of malware I analyzed used a 256 byte XOR key to decode it's C2, configs and some data. In the code below we can see a simple XOR loop.

byte_4102C28 is the start of the 256 byte XOR key and byte_4103CC is the start of the encoded data. We can see the encoded data in the yellow section. The length of the data is 0x3033. With the new version of fwrapper we can select and highlight the data and then create an instance of fwrapper. Below is an example of highlighting the key, creating an instance called key and doing the same with the encoded data.

Python>key = fwrapper()
Python>len(key.buffer)
256
Python>data = fwrapper()
Python>len(data.buffer)
12340
Python>hex(len(data.buffer))
0x3033

Now we just need to mimic the assembly in python


A quick print to verify the data and now we can patch the IDB.
Python>temp
iexplore.exe;outlook.exe;firefox.exe;opera.exe;skype.exe;msnmsgr.exe;yahoomessenger.exe;msmsgs.exe;wscntfy.exe;wuauclt.exe
Python>data.buffer = temp
Python>data.patch()

The new version can be found on BitBucket

# Name: 
#    fwrapper.py
# Version: 
#    0.2
        # removed static instance name 
# Description: 
#    This script can be used to carve out data and work with data in IDA.           
# Author
#    alexander<dot>hanel<at>gmail<dot>com

import sys 
import idaapi 

class fwrapper():
    def __init__(self):
        self.start = SelStart()
        self.end = SelEnd()
        self.buffer = ''
        self.ogLen = None
        self.status = True
        self.run()
        
    def checkBounds(self):
        if self.start is BADADDR or self.end is BADADDR:
            self.status = False 

    def getData(self):
        
        self.ogLen = self.end - self.start  
        try:
            for byte in GetManyBytes(self.start, self.ogLen):
                self.buffer = self.buffer + byte
        except:
            self.status = False
        return
        
    def run(self):
        self.checkBounds()
        if self.status == False:
            sys.stdout.write('ERROR: Please select valid data')
            return 
        self.getData()
         
    def patch(self):
        'patch idb with data in fwrapper.buffer'
        for index, byte in enumerate(self.buffer):
             PatchByte(self.start+index, ord(byte))
             
    def importb(self):
        'import file to save to buffer'
        fileName = AskFile(0, "*.*", 'Import File')
        try:
            self.buffer = open(fileName, 'r').read()
        except:
            sys.stdout.write('ERROR: Cannot access file')
               
    def export(self):
        'save the selected buffer to a file'
        exportFile = AskFile(1, "*.*", 'Export Buffer')
        f = open(exportFile, 'wb')
        f.write(self.buffer)
        f.close()

No comments:

Post a Comment