Advertisement
opexxx

OfficeMalHunter.py

Jul 12th, 2014
381
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 31.23 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding : utf-8 -*-
  3. # OfficeMalHunter.py
  4. # Binjo @ 2009-06-01 16:35:41
  5. # Reverse 4 phun...
  6. #-------------------------------------------------------------------------------
  7. import os, sys
  8. from ctypes    import *
  9. from pythoncom import *
  10. from struct    import pack, unpack
  11.  
  12. k32  = windll.kernel32
  13. libc = cdll.msvcrt
  14. nt   = windll.ntdll
  15.  
  16. # RATING
  17. # Malicious index rating:
  18. #   Executables: 4
  19. #   Code       : 3
  20. #   STRINGS    : 2
  21. #   OLE/NOPs   : 1
  22. RATING_EXEC   = 4
  23. RATING_CODE   = 3
  24. RATING_STRS   = 2
  25. RATING_OLENOP = 1
  26.  
  27. g_IndentNum   = 0
  28. g_macro_flg   = 0
  29. g_macro_dir   = ''
  30. g_f_name      = ''
  31. g_f_size      = 0
  32. g_f_cnt       = None
  33.  
  34. g_power       = 0 # indicate the malicious power
  35.  
  36. A8            = c_byte * 8
  37. g_aOfficeSig  = A8( 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 )
  38.  
  39. A6            = c_byte * 6
  40. g_FldzSig     = A6( 0xD9, 0xEE, 0xD9, 0x74, 0x24, 0xF4 )
  41. g_CallPopSig1 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x58 )
  42. g_CallPopSig2 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x59 )
  43. g_CallPopSig3 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5A )
  44. g_CallPopSig4 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5B )
  45. g_CallPopSig5 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5E )
  46. g_CallPopSig6 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5F )
  47. g_CallPopSig7 = A6( 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D )
  48.  
  49. A5            = c_byte * 5
  50. g_FS30Sig1    = A5( 0x64, 0xA1, 0x30, 0x00, 0x00 ) # MOV EAX,DWORD PTR FS:[30]
  51. g_FS30Sig2    = A5( 0x64, 0x8B, 0x1D, 0x30, 0x00 ) # MOV EBX,DWORD PTR FS:[30]
  52. g_FS30Sig3    = A5( 0x64, 0x8B, 0x0D, 0x30, 0x00 ) # MOV ECX,DWORD PTR FS:[30]
  53. g_FS30Sig4    = A5( 0x64, 0x8B, 0x15, 0x30, 0x00 ) # MOV EDX,DWORD PTR FS:[30]
  54. g_FS30Sig5    = A5( 0x64, 0x8B, 0x35, 0x30, 0x00 ) # MOV ESI,DWORD PTR FS:[30]
  55. g_FS30Sig6    = A5( 0x64, 0x8B, 0x3D, 0x30, 0x00 ) # MOV EDI,DWORD PTR FS:[30]
  56.  
  57. A3            = c_byte * 3
  58. g_NopSig      = A3( 0x90, 0x90, 0x90 )
  59.  
  60. APIZ          = [
  61.     'UrlDownloadToFile',
  62.     'GetTempPath',
  63.     'GetWindowsDirectory',
  64.     'GetSystemDirectory',
  65.     'WinExec',
  66.     'IsBadReadPtr',
  67.     'IsBadWritePtr',
  68.     'CreateFile',
  69.     'CloseHandle',
  70.     'ReadFile',
  71.     'WriteFile',
  72.     'SetFilePointer',
  73.     'VirtualAlloc',
  74.     'GetProcAddr',
  75.     'LoadLibrary']
  76.  
  77. def usage():
  78.     """usage - show help here
  79.    """
  80.     h = k32.GetStdHandle( 0xFFFFFFF5 ) # STD_OUTPUT_HANDLE
  81.  
  82.     print "\nUsage:\n------\n",
  83.     print "OfficeMalScanner <PPT, DOC or XLS file> <scan | info> <brute> <debug>\n",
  84.     print "\nOptions:\n",
  85.     print "  scan  - scan for several shellcode heuristics and encrypted PE-Files\n",
  86.     print "  info  - dumps OLE structures, offsets+length and saves found VB-Macro code\n",
  87.     print "\nSwitches: (only enabled if option \"scan\" was selected)",
  88.     print "  brute - enables the \"brute force mode\" to find encrypted stuff\n",
  89.     print "  debug - prints out disassembly resp hexoutput if a heuristic was found\n",
  90.     print "\nExamples:\n",
  91.     print "  OfficeMalScanner evil.ppt scan brute debug\n",
  92.     print "  OfficeMalScanner evil.ppt scan\n",
  93.     print "  OfficeMalScanner evil.ppt info\n",
  94.     print "\nMalicious index rating:\n",
  95.     print "  Executables: 4\n",
  96.     print "  Code       : 3\n",
  97.     print "  STRINGS    : 2\n",
  98.     print "  OLE/NOPs   : 1\n",
  99.  
  100.     print "----------------------------------------------------------------------------\n",
  101.     k32.SetConsoleTextAttribute( h, 0x14 ), #FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY ),
  102.     print "    I strongly suggest you to scan malicious files in a safe environment\n",
  103.     print " like VMWARE, as this tool is written in C and might have exploitable bugs!\n",
  104.     k32.SetConsoleTextAttribute( h, 0x0F ), #FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY ),
  105.     print "----------------------------------------------------------------------------\n",
  106.  
  107.     return -1
  108.  
  109. def save_decompressed_macro( name, buffer, idx ):
  110.     """save decrompressed macro via RtlDecompressBuffer
  111.  
  112.    Arguments:
  113.    - `name`:
  114.    - `buffer`:
  115.    - `idx`:
  116.    """
  117.     dec_data = create_string_buffer(0x800)
  118.     final_size = c_ulong(0)
  119.  
  120.     nt.RtlDecompressBuffer(
  121.         2,                        # COMPRESSION_FORMAT_LZNT1
  122.         dec_data,                 # UncompressedBuffer
  123.         0x800,                    # UncompressedBufferSize
  124.         c_char_p(buffer[idx+1:]), # CompressedBuffer
  125.         0xFFFFFF - idx,           # CompressedBufferSize
  126.         byref(final_size)         # FinalUncompressedSize
  127.         )
  128.  
  129.     try:
  130.         if name == '': name = 'fvck'
  131.         f = open( "%s\%s" % (g_macro_dir, name), 'wb' )
  132.         f.write(dec_data.value)
  133.     except Exception, e:
  134.         print '[-] shit...%s' % e
  135.     finally:
  136.         f.close()
  137.  
  138. def dump_data( title, data, length ):
  139.     """dump specific length of data
  140.  
  141.    Arguments:
  142.    - `title`:
  143.    - `data`:
  144.    - `length`:
  145.    """
  146.     char_table = '................................ !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`' \
  147.         'abcdefghijklmnopqrstuvwxyz{|}~...............................................................................' \
  148.         '..................................................'
  149.  
  150.     libc.printf( "\n[ %s - %u bytes ]\n", title, length )
  151.  
  152.     if len(data) < length: length = len(data)
  153.  
  154.     for i in xrange(1, length+1):
  155.         libc.printf( "%02x ", unpack('B',data[i-1])[0] )
  156.         if i % 8  == 0: libc.printf(" ")
  157.         if i % 16 == 0:
  158.             libc.printf("| ")
  159.             j = i - 16
  160.             while ( j < i ):
  161.                 libc.printf( "%s", char_table[unpack('B', data[j])[0]] )
  162.                 j += 1
  163.             libc.printf("\n")
  164.  
  165.     if length % 16 != 0:
  166.         m = 16 - length % 16
  167.         n = 16 - length % 16
  168.         while n:
  169.             libc.printf( "   " )
  170.             if n % 8 == 0 and m != 8:
  171.                 libc.printf(" ")
  172.             n -= 1
  173.         libc.printf(" | ")
  174.         n = length - (16 - m)
  175.         while n < length:
  176.             libc.printf( "%s", char_table[unpack('B',data[n])[0]] )
  177.             n += 1
  178.  
  179.     libc.printf("\n")
  180.     print "--------------------------------------------------------------------------\n\n",
  181.  
  182. def print_stream_info( f, stg ):
  183.     """print stream info
  184.  
  185.    Arguments:
  186.    - `f`:
  187.    - `stg`:
  188.    """
  189.     if stg is None:
  190.         ost = StgOpenStorage( f, None, 0x10, None, 0 )
  191.         print_stream_info( None, ost )
  192.     else:
  193.         estat = stg.EnumElements()
  194.  
  195.         if estat:
  196.             s_info = estat.Next()
  197.             while s_info != ():
  198.                 i = 0
  199.                 global g_IndentNum
  200.                 while i < g_IndentNum:
  201.                     libc.printf(' ')
  202.                     i += 1
  203.  
  204.                 s_name = ''
  205.                 x_name = create_string_buffer(0x400)
  206.                 libc.wcstombs( x_name, c_wchar_p(s_info[0][0]), 0x400 )
  207.                 for c in x_name.value:
  208. #                for c in s_info[0][0].encode( 'ascii', 'ignore' ):
  209.                     if ord(c) > 122 or ord(c) <= 32: continue
  210.                     s_name += c
  211.                     libc.printf( c )
  212.  
  213.                 if s_info[0][1] - 1 > 3:
  214.                     print "   [TYPE: Unknown]\n",
  215.                 else:
  216.                     # python don't support switch...
  217.                     if s_info[0][1] == 1:
  218.                         print "   [TYPE: Storage]\n",
  219.  
  220.                         x_stg = stg.OpenStorage( s_info[0][0], None, 0x10, None, 0 )
  221.                         g_IndentNum += 1
  222.                         print_stream_info( None, x_stg )
  223.                         g_IndentNum -= 1
  224.  
  225.                     elif s_info[0][1] == 2:
  226.                         print "   [TYPE: Stream",
  227.  
  228.                         macro  = 0
  229.                         stream = stg.OpenStream( s_info[0][0], None, 0x10, 0 )
  230.                         s_len  = s_info[0][2]
  231.                         if s_len > 0x4000: s_len = 0x4000 # !!!!!!!!!!
  232.                         data   = stream.Read( s_len )
  233.  
  234.                         if (unpack( 'B', data[0] )[0] != 1  or
  235.                             unpack( 'B', data[1] )[0] != 22 or
  236.                             unpack( 'B', data[2] )[0] != 1):
  237.                             macro = 0
  238.                         else:
  239.                             for i in xrange(s_len - 3):
  240.                                 if (unpack( 'B', data[i] )[0] == 1 and
  241.                                     unpack( 'B', data[i+1] )[0] and
  242.                                     (unpack( 'B', data[i+2] )[0] & 0xF0 == 0xB0)):
  243.                                     macro = 1
  244.                                     global g_macro_flg
  245.                                     g_macro_flg = 1
  246.                                     break
  247.  
  248.                         if macro == 1:
  249.                             global g_macro_dir
  250.                             g_macro_dir = os.path.abspath( "%s\\%s-Macros" % (os.path.curdir, g_f_name) )
  251.                             if not os.path.isdir( g_macro_dir ):
  252.                                 os.mkdir( g_macro_dir )
  253.                             save_decompressed_macro( s_name, data, i )  # FIXME
  254.  
  255.                         for i in xrange( g_f_size ):
  256.                             if ( libc.memcmp( c_char_p(g_f_cnt[i:]), c_char_p(data), 5) == 0 ):
  257.                                 print " - OFFSET: 0x%x - LEN: %lu]" % (i, s_len)
  258.                                 break
  259.  
  260.                     elif s_info[0][1] == 3:
  261.                         print "   [TYPE: Lockbytes]\n",
  262.                     elif s_info[0][1] == 4:
  263.                         print "   [TYPE: Property]\n",
  264.  
  265.                 s_info = estat.Next()
  266.  
  267. def print_opcodz( raw_data ):
  268.     """print opcodz via Cadt.dll engine
  269.  
  270.    Arguments:
  271.    - `raw_data`:
  272.    """
  273.     data = raw_data
  274.     # cadt = cdll.LoadLibrary( 'Cadt.dll' )
  275.  
  276.     print ""
  277.  
  278.     # code = create_string_buffer(55)
  279.     # asm  = create_string_buffer(44)
  280.     # menm = create_string_buffer(1024)
  281.  
  282.     # for i in xrange(0x10):
  283.     #     libc.memset( code, 0, 55 )
  284.     #     libc.memset( asm,  0, 44 )
  285.     #     c_len = windll.cadt.InstrDecode( c_char_p(data), code, 0 )
  286.     #     windll.cadt.InstrDasm( code, asm, 0 )
  287.     #     windll.cadt.MakeMnemonic( menm, asm, byref(c_int(1)) )
  288.     #     data = data[c_len:]
  289.     #     print "%s\n" % menm.value,
  290.  
  291.     from distorm import Decode, Decode32Bits
  292.  
  293.     l = Decode( 0x100, data, Decode32Bits )
  294.     for i in l[:16]:
  295.         print "%-20s %s" % (i[3], i[2])
  296.  
  297. def main():
  298.     """TODO
  299.    """
  300.     mode_flg  = 0 # <scan | info> mode
  301.     debug_flg = 0
  302.     brute_flg = 0
  303.  
  304.     global g_power
  305.     global g_f_cnt
  306.     global g_f_size
  307.     global g_f_name
  308.  
  309.     h = k32.GetStdHandle( 0xFFFFFFF5 )
  310.     k32.SetConsoleTextAttribute( h, 0x03 ) # FOREGROUND_BLUE or FOREGROUND_GREEN
  311.  
  312.     # print title
  313.     print "\n+------------------------------------------+\n",
  314.     print "|           OfficeMalScanner v0.41         |\n",
  315.     print "|  Frank Boldewin / www.reconstructer.org  |\n",
  316.     print "+------------------------------------------+\n",
  317.  
  318.     k32.SetConsoleTextAttribute( h, 0x0F ) # FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  319.  
  320.     arg_len = len(sys.argv)
  321.     if arg_len < 3 or arg_len > 5:
  322.         usage()                                  # exit in usage...
  323.  
  324.     #
  325.     # parse argvs
  326.     #
  327.     if sys.argv[2].upper() == "INFO":
  328.  
  329.         if arg_len != 3: usage()                 # exit in usage...
  330.         print "\n[*] INFO mode selected\n",
  331.         mode_flg = 1
  332.  
  333.     elif sys.argv[2].upper() == "SCAN":
  334.  
  335.         print "\n[*] SCAN mode selected\n",
  336.         if arg_len > 3:
  337.             i = 3
  338.             while i < arg_len:
  339.                 if sys.argv[i].upper() == "DEBUG": debug_flg = 1
  340.                 if sys.argv[i].upper() == "BRUTE": brute_flg = 1
  341.                 i += 1
  342.     else:
  343.         usage()
  344.  
  345.     print "[*] Opening file %s\n" % sys.argv[1],
  346.     try:
  347.         f       = open( sys.argv[1], 'rb' )
  348.         g_f_cnt = f.read()
  349.         f.close()
  350.     except:
  351.         print "\nCannot open file %s\n" % sys.argv[1]
  352.         exit(-2)
  353.  
  354.     g_f_size = len(g_f_cnt)
  355.  
  356.     print "[*] Filesize is %lu (0x%x) Bytes\n" % ( g_f_size, g_f_size ),
  357.  
  358.     # skip GetFileSize/CreateFileMappingA/MapViewOfFile, since it's PYTHON ;-p
  359.  
  360.     # if libc.memcmp( byref(g_aOfficeSig), g_f_cnt, 8 ) != 0:
  361.     #     print "\nSorry, no PPT/DOC/XLS file!\n",
  362.     #     print "If this is an Office 2007 file it can be extracted\n",
  363.     #     print "with winzip and directly viewed with an XML-Editor!\n",
  364.     #     exit(-6)
  365.     # else:
  366.     #     print "[*] Valid file format found.\n",
  367.  
  368.     if mode_flg == 1:
  369.         """INFO"""
  370.         g_f_name = os.path.basename(sys.argv[1])
  371.  
  372.         # python's print will append a space...
  373.         libc.printf( "\n-----------------" )
  374.         i = 0
  375.         while i <= len(g_f_name) and i <= 62:
  376.             libc.printf( "-" )
  377.             i += 1
  378.         libc.printf("\n")
  379.  
  380.         k32.SetConsoleTextAttribute( h, 0x03 ) # FOREGROUND_BLUE or FOREGROUND_GREEN
  381.         print "[OLE Struct of: %s]\n" % g_f_name.upper(),
  382.         k32.SetConsoleTextAttribute( h, 0x0F ) # FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  383.  
  384.         libc.printf( "-----------------" )
  385.         i = 0
  386.         while i <= len(g_f_name) and i <= 62:
  387.             libc.printf( "-" )
  388.             i += 1
  389.         libc.printf("\n")
  390.  
  391.         print_stream_info( sys.argv[1], None )
  392.  
  393.         if g_macro_flg == 1:
  394.             print "-----------------------------------------------------------------------------\n",
  395.             k32.SetConsoleTextAttribute( h, 0x0E ) # FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  396.             print "                VB-MACRO CODE WAS FOUND INSIDE THIS FILE!\n",
  397.             print "               The decompressed Macro code was stored here:\n\n------> %s\n" % os.path.abspath(g_macro_dir),
  398.             k32.SetConsoleTextAttribute( h, 0x0F ) # FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  399.             print "-----------------------------------------------------------------------------\n",
  400.         else:
  401.             print "-----------------------\n",
  402.             print "No VB-Macro code found!\n",
  403.  
  404.     else:
  405.         """SCAN"""
  406.         print "[*] Scanning now...\n\n",
  407.  
  408.         for i in xrange(g_f_size):
  409.             if ( libc.memcmp( byref(g_FS30Sig1), g_f_cnt[i:], 5 ) == 0 or
  410.                  libc.memcmp( byref(g_FS30Sig2), g_f_cnt[i:], 5 ) == 0 or
  411.                  libc.memcmp( byref(g_FS30Sig3), g_f_cnt[i:], 5 ) == 0 or
  412.                  libc.memcmp( byref(g_FS30Sig4), g_f_cnt[i:], 5 ) == 0 or
  413.                  libc.memcmp( byref(g_FS30Sig5), g_f_cnt[i:], 5 ) == 0 or
  414.                  libc.memcmp( byref(g_FS30Sig6), g_f_cnt[i:], 5 ) == 0 ):
  415.                 print "FS:[30h] (Method 1) signature found at offset: 0x%x\n" % i,
  416.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  417.                 g_power += RATING_CODE
  418.  
  419.         for i in xrange(g_f_size):
  420.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x6A and
  421.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x30 and
  422.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0x64 and
  423.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0x8B ):
  424.                 print "FS:[30] (Method 2) signature found at offset: 0x%x\n" % i,
  425.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  426.                 g_power += RATING_CODE
  427.  
  428.         for i in xrange(g_f_size):
  429.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x33 and
  430.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xB3 and
  431.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0x64 and
  432.                  unpack( 'B', g_f_cnt[i+5] )[0] == 0x8B ):
  433.                 print "FS:[30] (Method 3) signature found at offset: 0x%x\n" % i,
  434.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  435.                 g_power += RATING_CODE
  436.  
  437.         for i in xrange(g_f_size):
  438.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x74 and
  439.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xC1 and
  440.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0x0D and
  441.                  unpack( 'B', g_f_cnt[i+5] )[0] == 0x03 ):
  442.                 print "API-Hashing signature found at offset: 0x%x\n" % i,
  443.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  444.                 g_power += RATING_CODE
  445.  
  446.         i = 0
  447.         while ( i < g_f_size ):
  448.             if ( libc.memcmp( byref(g_NopSig), g_f_cnt[i:], 3 ) == 0 ):
  449.                 print "NOP slides signature found at offset: 0x%x\n" % i,
  450.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  451.                 while unpack('B', g_f_cnt[i])[0] == 0x90: i += 1
  452.                 g_power += RATING_OLENOP
  453.             i += 1
  454.  
  455.         for api in APIZ:
  456.             for i in xrange(g_f_size):
  457.                 if libc.memcmp( c_char_p(api), g_f_cnt[i:], len(api) ) == 0:
  458.                     print "API-Name %s string found at offset: 0x%x\n" % (api, i),
  459.                     if debug_flg == 1: dump_data( "PE-File", g_f_cnt[i:], 0x100 )
  460.                     g_power += RATING_STRS
  461.  
  462.         for i in xrange(8, g_f_size):
  463.             if libc.memcmp( byref(g_aOfficeSig), g_f_cnt[i:], 8 ) == 0:
  464.                 print "Embedded OLE signature found at offset: 0x%x\n" % i,
  465.                 if debug_flg == 1: dump_data( "PE-File", g_f_cnt[i:], 0x100 )
  466.                 g_power += RATING_OLENOP
  467.  
  468.         for i in xrange(g_f_size):
  469.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x55 and
  470.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x8B and
  471.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xEC and
  472.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0x83 and
  473.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0xC4 ):
  474.                 print "Function prolog signature found at offset: 0x%x\n" % i,
  475.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  476.                 g_power += RATING_CODE
  477.  
  478.         for i in xrange(g_f_size):
  479.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x55 and
  480.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x8B and
  481.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xEC and
  482.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0x81 and
  483.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0xEC ):
  484.                 print "Function prolog signature found at offset: 0x%x\n" % i,
  485.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  486.                 g_power += RATING_CODE
  487.  
  488.         for i in xrange(g_f_size):
  489.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xFF and
  490.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x75 and
  491.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xFF and
  492.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0x55 ):
  493.                 print "PUSH DWORD[]/CALL[] signature found at offset: 0x%x\n" % i,
  494.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  495.                 g_power += RATING_CODE
  496.  
  497.         for i in xrange(g_f_size):
  498.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  499.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x34 and
  500.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xAA ):
  501.                 print "LODSB/STOSB XOR decryption signature found at offset: 0x%x\n" % i,
  502.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  503.                 g_power += RATING_CODE
  504.  
  505.         for i in xrange(g_f_size):
  506.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  507.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x04 and
  508.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xAA ):
  509.                 print "LODSB/STOSB ADD decryption signature found at offset: 0x%x\n" % i,
  510.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  511.                 g_power += RATING_CODE
  512.  
  513.         for i in xrange(g_f_size):
  514.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  515.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x2C and
  516.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xAA ):
  517.                 print "LODSB/STOSB SUB decryption signature found at offset: 0x%x\n" % i,
  518.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  519.                 g_power += RATING_CODE
  520.  
  521.         for i in xrange(g_f_size):
  522.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  523.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xD0 and
  524.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xC0 and
  525.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xAA ):
  526.                 print "LODSB/STOSB ROL decryption signature found at offset: 0x%x\n" % i,
  527.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  528.                 g_power += RATING_CODE
  529.  
  530.         for i in xrange(g_f_size):
  531.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  532.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xD0 and
  533.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xC8 and
  534.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0xAA ):
  535.                 print "LODSB/STOSB ROR decryption signature found at offset: 0x%x\n" % i,
  536.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  537.                 g_power += RATING_CODE
  538.  
  539.         for i in xrange(g_f_size):
  540.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  541.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xC0 and
  542.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xC0 and
  543.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0xAA ):
  544.                 print "LODSB/STOSB ROL decryption signature found at offset: 0x%x\n" % i,
  545.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  546.                 g_power += RATING_CODE
  547.  
  548.         for i in xrange(g_f_size):
  549.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAC and
  550.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xC0 and
  551.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0xC8 and
  552.                  unpack( 'B', g_f_cnt[i+4] )[0] == 0xAA ):
  553.                 print "LODSB/STOSB ROR decryption signature found at offset: 0x%x\n" % i,
  554.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  555.                 g_power += RATING_CODE
  556.  
  557.         for i in xrange(g_f_size):
  558.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x66 and
  559.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xAD and
  560.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0x66 and
  561.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0x35 and
  562.                  unpack( 'B', g_f_cnt[i+6] )[0] == 0x66 and
  563.                  unpack( 'B', g_f_cnt[i+7] )[0] == 0xAB ):
  564.                 print "LODSW/STOSW XOR decryption signature found at offset: 0x%x\n" % i,
  565.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  566.                 g_power += RATING_CODE
  567.  
  568.         for i in xrange(g_f_size):
  569.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x66 and
  570.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xAD and
  571.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0x66 and
  572.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0x05 and
  573.                  unpack( 'B', g_f_cnt[i+6] )[0] == 0x66 and
  574.                  unpack( 'B', g_f_cnt[i+7] )[0] == 0xAB ):
  575.                 print "LODSW/STOSW ADD decryption signature found at offset: 0x%x\n" % i,
  576.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  577.                 g_power += RATING_CODE
  578.  
  579.         for i in xrange(g_f_size):
  580.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0x66 and
  581.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0xAD and
  582.                  unpack( 'B', g_f_cnt[i+2] )[0] == 0x66 and
  583.                  unpack( 'B', g_f_cnt[i+3] )[0] == 0x2D and
  584.                  unpack( 'B', g_f_cnt[i+6] )[0] == 0x66 and
  585.                  unpack( 'B', g_f_cnt[i+7] )[0] == 0xAB ):
  586.                 print "LODSW/STOSW SUB decryption signature found at offset: 0x%x\n" % i,
  587.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  588.                 g_power += RATING_CODE
  589.  
  590.         for i in xrange(g_f_size):
  591.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAD and
  592.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x35 and
  593.                  unpack( 'B', g_f_cnt[i+6] )[0] == 0xAB ):
  594.                 print "LODSD/STOSD XOR decryption signature found at offset: 0x%x\n" % i,
  595.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  596.                 g_power += RATING_CODE
  597.  
  598.         for i in xrange(g_f_size):
  599.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAD and
  600.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x05 and
  601.                  unpack( 'B', g_f_cnt[i+6] )[0] == 0xAB ):
  602.                 print "LODSD/STOSD ADD decryption signature found at offset: 0x%x\n" % i,
  603.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  604.                 g_power += RATING_CODE
  605.  
  606.         for i in xrange(g_f_size):
  607.             if ( unpack( 'B', g_f_cnt[i]   )[0] == 0xAD and
  608.                  unpack( 'B', g_f_cnt[i+1] )[0] == 0x2D and
  609.                  unpack( 'B', g_f_cnt[i+6] )[0] == 0xAB ):
  610.                 print "LODSD/STOSD SUB decryption signature found at offset: 0x%x\n" % i,
  611.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  612.                 g_power += RATING_CODE
  613.  
  614.         for i in xrange(g_f_size):
  615.             if libc.memcmp( byref(g_FldzSig), g_f_cnt[i:], 6 ) == 0:
  616.                 print "FLDZ/FSTENV [esp-12] signature found at offset: 0x%x\n" % i,
  617.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  618.                 g_power += RATING_CODE
  619.  
  620.         for i in xrange(g_f_size):
  621.             if ( libc.memcmp( byref(g_CallPopSig1), g_f_cnt[i:], 6 ) == 0 or
  622.                  libc.memcmp( byref(g_CallPopSig2), g_f_cnt[i:], 6 ) == 0 or
  623.                  libc.memcmp( byref(g_CallPopSig3), g_f_cnt[i:], 6 ) == 0 or
  624.                  libc.memcmp( byref(g_CallPopSig4), g_f_cnt[i:], 6 ) == 0 or
  625.                  libc.memcmp( byref(g_CallPopSig5), g_f_cnt[i:], 6 ) == 0 or
  626.                  libc.memcmp( byref(g_CallPopSig6), g_f_cnt[i:], 6 ) == 0 or
  627.                  libc.memcmp( byref(g_CallPopSig7), g_f_cnt[i:], 6 ) == 0 ):
  628.                 print "CALL next/POP signature found at offset: 0x%x\n" % i,
  629.                 if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  630.                 g_power += RATING_CODE
  631.  
  632.         for i in xrange(g_f_size):
  633.             if ( unpack( 'B', g_f_cnt[i] )[0] == 0xEB and
  634.                  unpack( 'B', g_f_cnt[i+unpack('B',g_f_cnt[i+1])[0]+2] )[0] == 0xE8 ):
  635.                 jmp_off  = i + unpack('B',g_f_cnt[i+1])[0] + 2
  636. #                call_va  = unpack( '<L', g_f_cnt[jmp_off+1:jmp_off+5] )[0]  # python is much simple
  637.                 call_va  = unpack( 'B', g_f_cnt[jmp_off + 1] )[0]
  638.                 call_va += unpack( 'B', g_f_cnt[jmp_off + 2] )[0] << 8
  639.                 call_va += unpack( 'B', g_f_cnt[jmp_off + 3] )[0] << 16
  640.                 call_va += unpack( 'B', g_f_cnt[jmp_off + 4] )[0] << 24
  641.                 if ( jmp_off + call_va + 5 < g_f_size and
  642.                      ( unpack( 'B', g_f_cnt[jmp_off+call_va+5] )[0] == 0x58 or
  643.                        unpack( 'B', g_f_cnt[jmp_off+call_va+5] )[0] == 0x59 or
  644.                        unpack( 'B', g_f_cnt[jmp_off+call_va+5] )[0] == 0x5A or
  645.                        unpack( 'B', g_f_cnt[jmp_off+call_va+5] )[0] == 0x5B or
  646.                        unpack( 'B', g_f_cnt[jmp_off+call_va+5] )[0] == 0x5E or
  647.                        unpack( 'B', g_f_cnt[jmp_off+call_va+5] )[0] == 0x5F ) ):
  648.                     print "JMP [0xEB]/CALL/POP signature found at offset: 0x%x\n" % i,
  649.                     if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  650.                     g_power += RATING_CODE
  651.  
  652.         for i in xrange(g_f_size):
  653.             if ( unpack( 'B', g_f_cnt[i] )[0] == 0xE9 ):
  654. #                jmp_off = unpack( '<L', g_f_cnt[i+1:i+5] )[0]
  655.                 jmp_off  = unpack( 'B', g_f_cnt[i + 1] )[0]
  656.                 jmp_off += unpack( 'B', g_f_cnt[i + 2] )[0] << 8
  657.                 jmp_off += unpack( 'B', g_f_cnt[i + 3] )[0] << 16
  658.                 jmp_off += unpack( 'B', g_f_cnt[i + 4] )[0] << 24
  659.  
  660.                 if ( unpack( 'B', g_f_cnt[i+jmp_off+5] )[0] == 0xE8 ):
  661. #                    call_va  = unpack( '<L', g_f_cnt[i+jmp_off+6:jmp_off+10] )[0]  # python is much simple
  662.                     call_va  = unpack( 'B', g_f_cnt[i + jmp_off + 6] )[0]
  663.                     call_va += unpack( 'B', g_f_cnt[i + jmp_off + 7] )[0] << 8
  664.                     call_va += unpack( 'B', g_f_cnt[i + jmp_off + 8] )[0] << 16
  665.                     call_va += unpack( 'B', g_f_cnt[i + jmp_off + 9] )[0] << 24
  666.                     if not call_va:
  667.                         if ( i + jmp_off + 10 < g_f_size and
  668.                              ( unpack( 'B', g_f_cnt[i+jmp_off+10] )[0] == 0x58 or
  669.                                unpack( 'B', g_f_cnt[i+jmp_off+10] )[0] == 0x59 or
  670.                                unpack( 'B', g_f_cnt[i+jmp_off+10] )[0] == 0x5A or
  671.                                unpack( 'B', g_f_cnt[i+jmp_off+10] )[0] == 0x5B or
  672.                                unpack( 'B', g_f_cnt[i+jmp_off+10] )[0] == 0x5E or
  673.                                unpack( 'B', g_f_cnt[i+jmp_off+10] )[0] == 0x5F ) ):
  674.                             print "JMP [0xE9]/CALL/POP signature found at offset: 0x%x\n" % i,
  675.                             if debug_flg == 1: print_opcodz( g_f_cnt[i:] )
  676.                             g_power += RATING_CODE
  677.  
  678.         for i in xrange(g_f_size):
  679.             if ( libc.memcmp( c_char_p("MZ"), g_f_cnt[i:], 2 ) == 0 ):
  680.                 pe_off  = unpack( 'B', g_f_cnt[i+0x3C] )[0]
  681.                 pe_off += unpack( 'B', g_f_cnt[i+0x3D] )[0] << 8
  682.                 pe_off += unpack( 'B', g_f_cnt[i+0x3E] )[0] << 16
  683.                 pe_off += unpack( 'B', g_f_cnt[i+0x3F] )[0] << 24
  684.                 if ( libc.memcmp( c_char_p("PE"), g_f_cnt[i+pe_off:], 2 ) == 0):
  685.                     print "unencrypted MZ/PE signature found at offset: 0x%x\n" % i,
  686.                     if debug_flg == 1: dump_data( "PE-File", g_f_cnt[i:], 0x100 )
  687.                     g_power += RATING_EXEC
  688.  
  689.         if brute_flg == 1:
  690.             print "\nBrute-forcing for encrypted PE- and embedded OLE-files now...\n",
  691.             # TODO
  692.  
  693.         print "\n\nAnalysis finished!\n\n",
  694.  
  695.         if g_power:
  696.             k32.SetConsoleTextAttribute( h, 0x0E ) # FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  697.             libc.printf( "---------------------------------------------" )
  698.             i = 0
  699.             while i < len(g_f_name):
  700.                 libc.printf("-")
  701.                 i += 1
  702.             libc.printf( "\n%s seems to be malicious! Malicious Index = %02d\n", g_f_name, g_power )
  703.             libc.printf( "---------------------------------------------" )
  704.             i = 0
  705.             while i < len(g_f_name):
  706.                 libc.printf("-")
  707.                 i += 1
  708.             k32.SetConsoleTextAttribute( h, 0x0F ) # FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  709.         else:
  710.             k32.SetConsoleTextAttribute( h, 0x07 ) # FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED
  711.             print "---------------------------------------------------------------------\n",
  712.             print "             No malicious traces found in this file!\n",
  713.             print "Assure that this file is being scanned with the \"info\" parameter too.\n",
  714.             print "---------------------------------------------------------------------\n",
  715.             k32.SetConsoleTextAttribute( h, 0x0F ) # FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
  716.  
  717. #-------------------------------------------------------------------------------
  718. if __name__ == '__main__':
  719.     main()
  720. #-------------------------------------------------------------------------------
  721. # EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement