Guest User

Untitled

a guest
Dec 12th, 2015
638
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. from unicorn import *
  2. from unicorn.x86_const import *
  3. from capstone import *
  4. from capstone.x86 import *
  5. import pefile
  6. import struct
  7. import string
  8. import sys
  9.  
  10. stacksize = 0x10000
  11. verbose = True
  12.  
  13. # -------------------------------------------------------------------------------------------
  14. def char_size(s):
  15.     # data to small
  16.     if len(s) < 4:
  17.         return 0
  18.     b = struct.unpack_from('<BBBB', s, 0)
  19.     # first byte not printable
  20.     if b[0] == 0:
  21.         return 0
  22.     # X0X0
  23.     if chr(b[0]) in string.printable and b[1] == 0 and chr(b[2]) in string.printable and b[3] == 0:
  24.         return 2
  25.     # XX00
  26.     if chr(b[0]) in string.printable and chr(b[1]) in string.printable:
  27.         return 1
  28.  
  29.     return 0
  30.  
  31. # -------------------------------------------------------------------------------------------
  32. def get_string(data, offset):
  33.     s = str(data[ len(data)-offset : ])
  34.     size = len(s)
  35.  
  36.     cs = char_size(s)
  37.  
  38.     if cs == 0:
  39.         return '',0
  40.  
  41.     if cs == 1:
  42.         f = '<B'
  43.     else:
  44.         f = '<H'
  45.  
  46.     r = ''
  47.     i = 0
  48.     while True:
  49.         b = struct.unpack_from(f, s, i)[0]
  50.         # 0 byte, end string
  51.         if b == 0:
  52.             break
  53.         # invalid char, discard all
  54.         if chr(b) not in string.printable:
  55.             return '',0
  56.        
  57.         r += chr(b)
  58.         i += cs
  59.    
  60.     return r, cs
  61.  
  62. # -------------------------------------------------------------------------------------------
  63. def str_to_int(s):
  64.     try:
  65.         if s.startswith('0x'):
  66.             return int(s, 16)
  67.         if s.isdigit:
  68.             return int(s)
  69.     except ValueError:
  70.         print "Error, invalid integer string"
  71.         exit(-1)
  72.  
  73. # -------------------------------------------------------------------------------------------
  74. def str_type(t):
  75.     if t == 1:
  76.         return 'ASCII'
  77.     elif t == 2:
  78.         return 'UTF16'
  79.     else:
  80.         raise Exception("Invalid string type")
  81.  
  82. # -------------------------------------------------------------------------------------------
  83. def format_disasembly(ins):
  84.     opbytes = ''.join(('%02X'%(b)) for b in ins.bytes)
  85.     instr = '%s' % (ins.mnemonic)
  86.     if len(ins.op_str) > 0:
  87.         instr += ' %s' % (ins.op_str)
  88.     return '%08X  %s  %s' % (ins.address, opbytes.ljust(20, ' '), instr)
  89.  
  90. # -------------------------------------------------------------------------------------------
  91. def code_analyzer(pe, virtualaddress, max_instructions=128):
  92.     # get the raw offset from the virtualaddress
  93.     a_off = pe.get_offset_from_rva(virtualaddress - pe.OPTIONAL_HEADER.ImageBase)
  94.     # init disassembler lib
  95.     caps = Cs(CS_ARCH_X86, CS_MODE_32)
  96.     caps.detail = True
  97.     # init vars
  98.     code_len = 0
  99.     stack_offsets = []
  100.     jmpfound = False
  101.     # disassemble code and analyze the instructions
  102.     for ins in caps.disasm(pe.__data__[a_off:], virtualaddress, max_instructions):
  103.        
  104.         # increase code_len with current instruction size
  105.         code_len += ins.size
  106.         if verbose:
  107.             print format_disasembly(ins)
  108.        
  109.         # process operands
  110.         if ins.operands:
  111.             for ops in ins.operands:
  112.                 # memory access operands
  113.                 if ops.type == X86_OP_MEM:
  114.                     # ebp base register and disp value not 0
  115.                     if ops.value.mem.base == X86_REG_EBP and ops.value.mem.disp != 0:
  116.                         disp = abs(ops.value.mem.disp)
  117.                         # add new disp value
  118.                         if disp not in stack_offsets:
  119.                             stack_offsets.append(disp)
  120.         # process groups
  121.         if ins.groups:
  122.             # jump types
  123.             if ins.group(CS_GRP_JUMP):
  124.                 # JMP backwards
  125.                 if ins.id == X86_INS_JMP and int(ins.op_str, 16) < ins.address:
  126.                     jmpfound = True
  127.                     break
  128.            
  129.             # return types
  130.             elif ins.group(CS_GRP_RET):
  131.                 break
  132.    
  133.     # false if max instructions reached
  134.     if not jmpfound:
  135.         print "End decryption loop not found"
  136.         return 0,[]
  137.  
  138.     # paranoid mode
  139.     if len(stack_offsets) == 0:
  140.         print "No stack offsets found"
  141.         return 0,[]
  142.  
  143.     # ...
  144.     for offset in stack_offsets:
  145.         if offset > stacksize:
  146.             print "Stack offset 0x%08x is larger then the stacksize 0x%08x" %(offset, stacksize)
  147.             return 0,[]
  148.  
  149.     # return code length and stackoffsets sorted descending
  150.     return code_len, sorted(stack_offsets, reverse=True)
  151.  
  152. # -------------------------------------------------------------------------------------------
  153. def decrypt_string(filename, address):
  154.         # get virtualaddress
  155.         virtualaddress = str_to_int(address)
  156.        
  157.         # get some needed PE info from target file
  158.         pe = pefile.PE(filename)
  159.         imagebase = pe.OPTIONAL_HEADER.ImageBase
  160.         imagesize = pe.OPTIONAL_HEADER.SizeOfImage
  161.         stackaddress = imagebase + imagesize
  162.        
  163.         # run the code analyzer to locate and analyse the
  164.         # decryption loop
  165.         code_len, stack_offsets = code_analyzer(pe, virtualaddress)
  166.         if not code_len:
  167.             print "Failed to locate the decryption loop"
  168.             exit(-1)
  169.  
  170.         try:
  171.             # Initialize emulator
  172.             emu = Uc(UC_ARCH_X86, UC_MODE_32)
  173.            
  174.             # map memory at the imagebase and copy each section
  175.             # data to it's virtualaddress
  176.             emu.mem_map(imagebase, imagesize + stacksize)
  177.             for section in pe.sections:
  178.                 emu.mem_write(imagebase + section.VirtualAddress, section.get_data())
  179.            
  180.             # initialize stack registers ebp and esp
  181.             emu.reg_write(UC_X86_REG_ESP, stackaddress + stacksize)
  182.             emu.reg_write(UC_X86_REG_EBP, stackaddress + stacksize)
  183.            
  184.             # start emulator
  185.             emu.emu_start(virtualaddress, virtualaddress + code_len)
  186.            
  187.             # use the largest stack_offset value to define the min.
  188.             # ammount of stack data to read
  189.             ebp_addr = stackaddress + stacksize - stack_offsets[0]
  190.            
  191.             # read stack memory, largest stack_offset as size
  192.             data = emu.mem_read(ebp_addr, stack_offsets[0])
  193.            
  194.             # locate and print strings
  195.             print "offset   type   length   content"
  196.             print 32 * "="
  197.             for offset in stack_offsets:
  198.                 s, t = get_string(data, offset)
  199.                 if s:
  200.                     print "%06x   %s  %s   %s" % (offset, str_type(t), str(len(s)).rjust(6,' '), s)
  201.  
  202.         except UcError as e:
  203.             print "Error, %s" % (e)
  204.             return
  205.  
  206. # -------------------------------------------------------------------------------------------
  207. if __name__ == '__main__':
  208.     decrypt_string(sys.argv[1], sys.argv[2])
RAW Paste Data