SHARE
TWEET

Untitled

a guest Dec 12th, 2015 425 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
Pastebin PRO Summer Special!
Get 60% OFF on Pastebin PRO accounts!
Top