def arclist(self, filename, fileformat): file_scan_list = [] # 검사 대상 정보를 모두 가짐 # 미리 분석된 파일 포맷중에 첨부 파일 포맷이 있는가? if 'ff_attach' in fileformat: pos = fileformat['ff_attach']['Attached_Pos'] file_scan_list.append(['arc_attach:%d' % pos, 'Attached']) if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'attach.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) kavutil.vprint(None, 'Attach Point', '0x%08X' % pos) with open(filename, 'rb') as fp: fp.seek(pos) buf = fp.read(0x80) print kavutil.vprint('Attach Point (Raw)') print kavutil.HexDump().Buffer(buf, 0, 0x80) print return file_scan_list
def arclist(self, filename, fileformat): fp = None mm = None file_scan_list = [] # 검사 대상 정보를 모두 가짐 # 미리 분석된 파일 포맷중에 PE 포맷이 있는가? if 'ff_pe' in fileformat: pe = fileformat['ff_pe']['pe'] ep_foff = pe['EntryPointRaw'] try: fp = open(filename, 'rb') mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) if mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2B: arc_name = 'arc_upx!nrv2b' elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2B: arc_name = 'arc_upx!nrv2b' elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2D: arc_name = 'arc_upx!nrv2d' elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2D: arc_name = 'arc_upx!nrv2d' elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2E: arc_name = 'arc_upx!nrv2e' elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2E: arc_name = 'arc_upx!nrv2e' else: raise ValueError if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'upx.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) print kavutil.vprint( 'UPX : only support \'nrv2b\' compress method.') kavutil.vprint(None, 'Compress Method', arc_name.split('!')[-1]) print name = 'UPX' file_scan_list.append([arc_name, name]) except IOError: pass except ValueError: pass if mm: mm.close() if fp: fp.close() return file_scan_list
def arclist(self, filename, fileformat): fp = None mm = None file_scan_list = [] # 검사 대상 정보를 모두 가짐 # 미리 분석된 파일 포맷중에 PE 포맷이 있는가? if 'ff_pe' in fileformat: pe = fileformat['ff_pe']['pe'] ep_foff = pe['EntryPointRaw'] try: fp = open(filename, 'rb') mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) if mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2B: arc_name = 'arc_upx!nrv2b' elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2B: arc_name = 'arc_upx!nrv2b' elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2D: arc_name = 'arc_upx!nrv2d' elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2D: arc_name = 'arc_upx!nrv2d' elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2E: arc_name = 'arc_upx!nrv2e' elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2E: arc_name = 'arc_upx!nrv2e' else: raise ValueError if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'upx.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) print kavutil.vprint('UPX : only support \'nrv2b\' compress method.') kavutil.vprint(None, 'Compress Method', arc_name.split('!')[-1]) print name = 'UPX' file_scan_list.append([arc_name, name]) except IOError: pass except ValueError: pass if mm: mm.close() if fp: fp.close() return file_scan_list
def format(self, filehandle, filename, filename_ex): ret = {} mm = filehandle if mm[:8] == '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1': # OLE 헤더와 동일 o = None try: o = ole.OleFile(filename) if '\x01Ole10Native' in o.listdir(): pics = o.openstream('\x01Ole10Native') buf = pics.read() if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'olenative.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) fileformat = analysis_ole10native(buf, self.verbose) if fileformat: ret = {'ff_ole10native': fileformat} except ole.Error: pass if o: o.close() return ret
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 try: # 미리 분석된 파일 포맷중에 PE 포맷이 있는가? if 'ff_pyc' in fileformat: if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'pyz.kmd') mm = filehandle # String 추출 if len(mm): if self.verbose: print kavutil.vprint('String') for match in self.p_string.finditer(mm): find_str = match.group() find_str_off = match.start() # 중요 문자열 시작전에 해당 문자열의 길이가 존재함 x = kavutil.get_uint32(mm, find_str_off - 4) if len(find_str) < x: continue buf = find_str[:x] fsize = len(buf) if self.verbose: fmd5 = cryptolib.md5(buf) kavutil.vprint(None, fmd5, '%3d : %s' % (fsize, buf)) if fsize and kavutil.handle_pattern_md5.match_size('emalware', fsize): fmd5 = cryptolib.md5(buf) # print fsize, fmd5 vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5) if vname: return True, vname, 0, kernel.INFECTED except IOError: pass # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 try: self.flags_off = {} flags = [] mm = filehandle # Virus.Win32.Small.a 검사 ret, vname = self.__scan_virus_win32_small_a(filehandle, fileformat) if ret: return True, vname, 0, kernel.INFECTED # Flag별 Signature를 만든다. # Flag - 0 : 파일의 처음 flags.append([int('0000' + mm[0:2].encode('hex'), 16), gen_checksums(mm[0:0x80])]) self.flags_off[0] = [0] # Flag - 1 : DOS EP # TODO # 미리 분석된 파일 포맷중에 PE 포맷이 있는가? if 'ff_pe' in fileformat: # Flag - 2 : PE EP ff = fileformat['ff_pe'] ep_off = ff['pe']['EntryPointRaw'] flags.append([int('0002' + mm[ep_off:ep_off+2].encode('hex'), 16), gen_checksums(mm[ep_off:ep_off+0x80])]) self.flags_off[2] = [ep_off] # Flag - 3 : 각 섹션의 헤더 flag3_off = [] for idx, section in enumerate(ff['pe']['Sections']): fsize = section['SizeRawData'] foff = section['PointerRawData'] flags.append([int('0003' + mm[foff:foff + 2].encode('hex'), 16), gen_checksums(mm[foff:foff+0x80])]) flag3_off.append(foff) self.flags_off[3] = flag3_off # Attach 영역이 존재하는가? if 'ff_attach' in fileformat: # Flag - 4 : Attach 영역 pos = fileformat['ff_attach']['Attached_Pos'] size = fileformat['ff_attach']['Attached_Size'] if size > 0x80: flags.append([int('0004' + mm[pos:pos+2].encode('hex'), 16), gen_checksums(mm[pos:pos + 0x80])]) self.flags_off[4] = [pos] cs_size = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80] if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 've.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) kavutil.vprint(None, 'MD5', cryptolib.md5(mm[:])) print kavutil.vprint('VE') vdb_name = os.path.split(filename)[-1] + '.vdb' kavutil.vprint(None, 'VDB File name', vdb_name) fp = open(vdb_name, 'w') for flag in flags: # kavutil.vprint(None, 'Flag', '%08X' % flag[0]) msg = 'Flag : %08x\n' % flag[0] fp.write(msg) for i, cs in enumerate(flag[1]): # kavutil.vprint(None, 'CS = %02X' % cs_pos[i], cs) msg = 'CS = %02x : %08x\n' % (cs_size[i], int(cs)) fp.write(msg) fp.write('\n') fp.close() for flag in flags: p1 = kavutil.handle_pattern_vdb.match_size('ve', flag[0]) # 일치하는 Flag가 있나? # print '%08x :' % flag[0], p1 # print flag[0] >> 16 if p1: for ve_id in p1.keys(): for idx in p1[ve_id]: cs1 = kavutil.handle_pattern_vdb.get_cs1(ve_id, idx) cs1_flag = cs1[0] cs1_off = cs1[1] cs1_size = cs1[2] cs1_crc = cs1[3] if flag[0] >> 16 == cs1_flag and cs1_off == 0 and cs1_size in cs_size: i = cs_size.index(cs1_size) # print '=', hex(flag[1][i]) if cs1_crc == flag[1][i]: # 1차 패턴이 같은가? vname = self.__scan_cs2(mm, ve_id, idx) if vname: return True, vname, 0, kernel.INFECTED else: buf = self.__get_data_crc32(mm, cs1_flag, cs1_off, cs1_size) if cs1_crc == int(gen_checksum(mm, cs1_off, cs1_size), 16): vname = self.__scan_cs2(mm, ve_id, idx) if vname: return True, vname, 0, kernel.INFECTED except IOError: pass kavutil.handle_pattern_vdb.__save_mem() # 메모리 용량을 낮추기 위해 사용 # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 zfile = None mm = filehandle try: if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'hwpx.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) print if 'ff_hwpx' in fileformat: zfile = zipfile.ZipFile(filename) # zip 파일 열기 for name in zfile.namelist(): if name.lower().find('mimetype') != -1: data = zfile.read(name) if self.verbose: kavutil.vprint('mimetype') kavutil.vprint(None, 'body', '%s' % data) print if data != 'application/hwp+zip': if zfile: zfile.close() return True, 'Exploit.HWPX.Generic', 0, kernel.INFECTED elif name.lower().find('preview/prvtext.txt') != -1: pass # PrevText.txt는 검사하지 않음 elif name.lower().find( 'bindata') == -1: # Bindata 이외의 파일들은 주로 XML try: data = zfile.read(name) dict_data = xml_parse(data) if self.verbose: kavutil.vprint(name) print json.dumps(dict_data, indent=2) print except: if zfile: zfile.close() return True, 'Exploit.HWPX.Generic', 0, kernel.INFECTED except IOError: pass if zfile: zfile.close() # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def parse(self): mm = self.mm pe_format = {'PE_Position': 0, 'EntryPoint': 0, 'SectionNumber': 0, 'Sections': None, 'EntryPointRaw': 0, 'FileAlignment': 0} try: if mm[0:2] != 'MZ': # MZ로 시작하나? raise ValueError dos_header = DOS_HEADER() ctypes.memmove(ctypes.addressof(dos_header), mm[0:], ctypes.sizeof(dos_header)) # PE 표식자 위치 알아내기 pe_pos = dos_header.e_lfanew # PE 인가? if mm[pe_pos:pe_pos + 4] != 'PE\x00\x00': raise ValueError pe_format['PE_Position'] = pe_pos # File Header 읽기 file_header = FILE_HEADER() file_header_size = ctypes.sizeof(file_header) # file_header_size : 0x14 ctypes.memmove(ctypes.addressof(file_header), mm[pe_pos + 4:], file_header_size) # Optional Header 읽기 optional_header = OPTIONAL_HEADER() optional_header_size = ctypes.sizeof(optional_header) ctypes.memmove(ctypes.addressof(optional_header), mm[pe_pos + 4 + file_header_size:], optional_header_size) # Optional Header의 Magic ID? if optional_header.Magic != 0x10b: raise ValueError # Entry Point 구하기 pe_ep = optional_header.AddressOfEntryPoint pe_format['EntryPoint'] = pe_ep # Image Base 구하기 pe_img = optional_header.ImageBase pe_format['ImageBase'] = pe_img # File Alignment 구하기 self.pe_file_align = optional_header.FileAlignment pe_format['FileAlignment'] = self.pe_file_align # Section 개수 구하기 section_num = file_header.NumberOfSections pe_format['SectionNumber'] = section_num # Optional Header 크기 구하기 opthdr_size = file_header.SizeOfOptionalHeader pe_format['OptionalHederSize'] = opthdr_size # Data Directory 읽기 data_directory_size = ctypes.sizeof(DATA_DIRECTORY()) # data_directory_size : 8 num_data_directory = (opthdr_size - optional_header_size) / data_directory_size off_data_directory = pe_pos + 4 + file_header_size + optional_header_size for i in range(num_data_directory): dx = DATA_DIRECTORY() ctypes.memmove(ctypes.addressof(dx), mm[off_data_directory + (i * data_directory_size):], data_directory_size) self.data_directories.append(dx) # 섹션 시작 위치 section_pos = pe_pos + 4 + file_header_size + opthdr_size # 모든 섹션 정보 추출 for i in range(section_num): section = {} section_header = SECTION_HEADER() section_header_size = ctypes.sizeof(section_header) # section_header_size : 0x28 s = section_pos + (section_header_size * i) ctypes.memmove(ctypes.addressof(section_header), mm[s:], section_header_size) sec_name = ctypes.cast(section_header.Name, ctypes.c_char_p) section['Name'] = sec_name.value.replace('\x00', '') section['VirtualSize'] = section_header.Misc_VirtualSize section['RVA'] = section_header.VirtualAddress section['SizeRawData'] = section_header.SizeOfRawData section['PointerRawData'] = section_header.PointerToRawData section['Characteristics'] = section_header.Characteristics self.sections.append(section) pe_format['Sections'] = self.sections # EntryPoint의 파일에서의 위치 구하기 ep_raw, sec_idx = self.rva_to_off(pe_ep) pe_format['EntryPointRaw'] = ep_raw # EP의 Raw 위치 pe_format['EntryPoint_in_Section'] = sec_idx # EP가 포함된 섹션 # 리소스 분석 try: rsrc_rva = self.data_directories[image_directory_entry.RESOURCE].VirtualAddress # 리소스 위치(RVA) rsrc_size = self.data_directories[image_directory_entry.RESOURCE].Size # 리소스 크기 except IndexError: rsrc_rva = 0 rsrc_size = 0 if rsrc_rva: # 리소스가 존재한가? try: rsrc_off, rsrc_idx = self.rva_to_off(rsrc_rva) # 리소스 위치 변환 if rsrc_off > self.filesize: raise ValueError t_size = self.sections[rsrc_idx]['SizeRawData'] if not (len(mm[rsrc_off:rsrc_off + rsrc_size]) == rsrc_size or \ len(mm[rsrc_off:rsrc_off + t_size]) == t_size): # 충분한 리소스가 존재하지 않음 raise ValueError # Type 체크 num_type_name = kavutil.get_uint16(mm, rsrc_off+0xC) num_type_id = kavutil.get_uint16(mm, rsrc_off + 0xE) for i in range(num_type_name + num_type_id): type_id = kavutil.get_uint32(mm, rsrc_off + 0x10 + (i*8)) name_id_off = kavutil.get_uint32(mm, rsrc_off + 0x14 + (i * 8)) # Type이 사용자가 정의한 이름 or RCDATA? if type_id & 0x80000000 == 0x80000000 or type_id == 0xA or type_id == 0: if type_id & 0x80000000 == 0x80000000: # 사용자가 정의한 이름 추출 string_off = (type_id & 0x7FFFFFFF) + rsrc_off len_name = kavutil.get_uint16(mm, string_off) rsrc_type_name = mm[string_off + 2:string_off + 2 + (len_name * 2):2] elif type_id == 0xA: rsrc_type_name = 'RCDATA' else: rsrc_type_name = '%d' % type_id # Name ID name_id_off = (name_id_off & 0x7FFFFFFF) + rsrc_off if name_id_off > self.filesize: raise ValueError num_name_id_name = kavutil.get_uint16(mm, name_id_off + 0xC) num_name_id_id = kavutil.get_uint16(mm, name_id_off + 0xE) for j in range(num_name_id_name + num_name_id_id): name_id_id = kavutil.get_uint32(mm, name_id_off + 0x10 + (j * 8)) language_off = kavutil.get_uint32(mm, name_id_off + 0x14 + (j * 8)) # 리소스 영역의 최종 이름 생성 if name_id_id & 0x80000000 == 0x80000000: string_off = (name_id_id & 0x7FFFFFFF) + rsrc_off if string_off > self.filesize: raise ValueError len_name = kavutil.get_uint16(mm, string_off) rsrc_name_id_name = mm[string_off + 2:string_off + 2 + (len_name * 2):2] string_name = rsrc_type_name + '/' + rsrc_name_id_name else: string_name = rsrc_type_name + '/' + hex(name_id_id).upper()[2:] # Language language_off = (language_off & 0x7FFFFFFF) + rsrc_off if language_off > self.filesize: raise ValueError num_language_name = kavutil.get_uint16(mm, language_off + 0xC) num_language_id = kavutil.get_uint16(mm, language_off + 0xE) for k in range(num_language_name + num_language_id): # language_id = kavutil.get_uint32(mm, language_off + 0x10 + (k * 8)) data_entry_off = kavutil.get_uint32(mm, language_off + 0x14 + (k * 8)) data_entry_off = (data_entry_off & 0x7FFFFFFF) + rsrc_off data_rva = kavutil.get_uint32(mm, data_entry_off) data_off, _ = self.rva_to_off(data_rva) if data_off > self.filesize: continue data_size = kavutil.get_uint32(mm, data_entry_off + 4) if data_size > self.filesize: continue if data_size > 8192: # 최소 8K 이상인 리소스만 데이터로 추출 if 'Resource_UserData' in pe_format: pe_format['Resource_UserData'][string_name] = (data_off, data_size) else: pe_format['Resource_UserData'] = {string_name: (data_off, data_size)} except (struct.error, ValueError) as e: pass # if 'Resource_UserData' in pe_format: # print pe_format['Resource_UserData'] # Import API 분석 try: imp_rva = self.data_directories[image_directory_entry.IMPORT].VirtualAddress # Import API 위치(RVA) imp_size = self.data_directories[image_directory_entry.IMPORT].Size # Import API 크기 except IndexError: imp_rva = 0 imp_size = 0 if imp_rva: # Import API 존재 imp_api = {} # print 'IMP : %08X' % imp_rva imp_off = self.rva_to_off(imp_rva)[0] # print hex(imp_off), imp_size imp_data = mm[imp_off:imp_off+imp_size] if len(imp_data) == imp_size: for i in range(imp_size / 0x14): # DLL 정보 크기가 0x14 try: dll_rva = kavutil.get_uint32(imp_data, (i*0x14)+0xC) api_rva = kavutil.get_uint32(imp_data, (i * 0x14)) bo = 2 if api_rva == 0: api_rva = kavutil.get_uint32(imp_data, (i*0x14)+0x10) bo = 0 # print hex(api_rva) if dll_rva == 0: # DLL 정보가 없음 break t_off = self.rva_to_off(dll_rva)[0] dll_name = p_str.search(mm[t_off:t_off+0x20]).group() # print '[+]', dll_name imp_api[dll_name] = [] t_off = self.rva_to_off(api_rva)[0] while True: try: api_name_rva = kavutil.get_uint32(mm, t_off) except struct.error: break if api_name_rva & 0x80000000 == 0x80000000: # Odinal API t_off += 4 continue if api_name_rva == 0: break t = self.rva_to_off(api_name_rva)[0] # print hex(t_off), hex(t) api_name = p_str.search(mm[t+bo:t+bo+0x20]).group() # print ' ', api_name imp_api[dll_name].append(api_name) t_off += 4 except struct.error: pass # end if pe_format['Import_API'] = imp_api # 디지털 인증서 분석 try: cert_off = self.data_directories[image_directory_entry.SECURITY].VirtualAddress # 유일하게 RVA가 아닌 오프셋 cert_size = self.data_directories[image_directory_entry.SECURITY].Size # 디지털 인증서 크기 except IndexError: cert_off = 0 cert_size = 0 if cert_off: # 디지털 인증서 존재 if cert_off + cert_size <= len(mm[:]): # UPack의 경우 이상한 값이 셋팅 됨 pe_format['CERTIFICATE_Offset'] = cert_off pe_format['CERTIFICATE_Size'] = cert_size # Debug 정보 분석 try: debug_rva = self.data_directories[image_directory_entry.DEBUG].VirtualAddress # RVA debug_size = self.data_directories[image_directory_entry.DEBUG].Size # 크기 if debug_size < 0x1C: raise ValueError except (IndexError, ValueError) as e: debug_rva = 0 debug_size = 0 if debug_rva: # Debug 정보 존재 t = self.rva_to_off(debug_rva)[0] debug_off = kavutil.get_uint32(mm, t + 0x18) debug_size = kavutil.get_uint32(mm, t + 0x10) debug_data = mm[debug_off:debug_off + debug_size] if debug_data[:4] == 'RSDS': pe_format['PDB_Name'] = debug_data[0x18:] else: pe_format['PDB_Name'] = 'Not support Type : %s' % debug_data[:4] if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'pe.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) kavutil.vprint(None, 'MD5', cryptolib.md5(mm[:])) print kavutil.vprint('PE') kavutil.vprint(None, 'EntryPoint', '%08X' % pe_format['EntryPoint']) kavutil.vprint(None, 'EntryPoint (Section)', '%d' % pe_format['EntryPoint_in_Section']) # 섹션 보기 if section_num: print kavutil.vprint('Section Header') print ' %-8s %-8s %-8s %-8s %-8s %-8s' % ('Name', 'VOFF', 'VSIZE', 'FOFF', 'FSIZE', 'EXEC') print ' ' + ('-' * (9*6 - 1)) for s in self.sections: print ' %-8s %08X %08X %08X %08X %-05s' % (s['Name'], s['RVA'], s['VirtualSize'], s['PointerRawData'], s['SizeRawData'], s['Characteristics'] & 0x20000000 == 0x20000000) if section_num: print kavutil.vprint('Section MD5') print ' %-8s %-8s %-32s' % ('Name', 'FSIZE', 'MD5') print ' ' + ('-' * ((9 * 2 - 1)+32)) for s in self.sections: # if s['Characteristics'] & 0x20000000 == 0x20000000: off = s['PointerRawData'] size = s['SizeRawData'] fmd5 = cryptolib.md5(mm[off:off+size]) if size else '-' print ' %-8s %8d %s' % (s['Name'], size, fmd5) print kavutil.vprint('Entry Point (Raw)') print kavutil.HexDump().Buffer(mm[:], pe_format['EntryPointRaw'], 0x80) print if 'PDB_Name' in pe_format: kavutil.vprint('PDB Information') kavutil.vprint(None, 'Name', '%s' % repr(pe_format['PDB_Name'])) print repr(pe_format['PDB_Name']) print except (ValueError, struct.error) as e: return None return pe_format
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 mm = filehandle o = None try: # 미리 분석된 파일 포맷중에 OLE 포맷이 있는가? if 'ff_ole' in fileformat: o = ole.OleFile(filename) # 취약점 공격인가? if len(o.exploit): if o: o.close() return True, o.exploit[0], MALWARE_ID_OLE, kernel.INFECTED ole_lists = o.listdir() for pps_name in ole_lists: if pps_name.lower().find( '/vba/dir') != -1: # 오피스 97 매크로 존재 여부 pics = o.openstream(pps_name) data = pics.read() ret, decom_data = decompress(data) # dir 스트림 압축 해제 if ret: vba_modules = analysis_dir_stream(decom_data) t = pps_name.split('/') for vba in vba_modules: t[-1] = vba[0] t_pps_name = '/'.join(t) t_pics = o.openstream( t_pps_name) # 매크로가 존재하는 스트림 열기 t_data = t_pics.read() if len(t_data) == 0: # 데이터가 없으면 다음 vba 체크 continue t_ret, buf = decompress( t_data[vba[1]:]) # 매크로 소스코드 획득 완료 buf = buf.replace('\r\n', '\n') if t_ret: if self.verbose: # 매크로 소스코드 출력 kavutil.vprint('Macro Source') kavutil.vprint(None, 'PPS', '%s' % t_pps_name) print buf buf = self.p_vba_cmt.sub('', buf) # 주석문 제거 buf = buf.lower() # 영어 소문자로 통일 key_words = self.p_vba_word.findall(buf) vba_keyword_crc32 = set() for i in range(len(key_words) - 1): word = key_words[i] + key_words[i + 1] c = zlib.crc32(word) & 0xffffffffL vba_keyword_crc32.add(c) # 테스트 if self.verbose: max_len = len(key_words[0]) t_word = [] for i in range(len(key_words) - 1): word = key_words[i] + key_words[i + 1] c = zlib.crc32(word) & 0xffffffffL t_word.append([ c, key_words[i], key_words[i + 1] ]) if len(key_words[i + 1]) > max_len: max_len = len(key_words[i + 1]) t_l = '+-' + ('-' * 8) + '-+-' + ( '-' * max_len) + '-+-' + ( '-' * max_len) + '-+' print t_l msg = '| %%-8s | %%-%ds | %%-%ds |' % ( max_len, max_len) print msg % ('CRC32', 'Keyword #1', 'Keyword #2') print t_l msg = '| %%08X | %%-%ds | %%-%ds |' % ( max_len, max_len) for n in t_word: print msg % (n[0], n[1], n[2]) print t_l # Heuristic 검사 for macro_crc in self.word97_macro_crcs: if macro_crc.issubset( vba_keyword_crc32): if o: o.close() return True, 'Virus.MSWord.Generic', MALWARE_ID_WORD97, kernel.SUSPECT except IOError: pass except ole.Error: pass if o: o.close() # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.INFECTED
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 try: self.flags_off = {} flags = [] mm = filehandle # Flag별 Signature를 만든다. # Flag - 0 : 파일의 처음 flags.append([ int('0000' + mm[0:2].encode('hex'), 16), gen_checksums(mm[0:0x80]) ]) self.flags_off[0] = [0] # Flag - 1 : DOS EP # TODO # 미리 분석된 파일 포맷중에 PE 포맷이 있는가? if 'ff_pe' in fileformat: # Flag - 2 : PE EP ff = fileformat['ff_pe'] ep_off = ff['pe']['EntryPointRaw'] flags.append([ int('0002' + mm[ep_off:ep_off + 2].encode('hex'), 16), gen_checksums(mm[ep_off:ep_off + 0x80]) ]) self.flags_off[2] = [ep_off] # Flag - 3 : 각 섹션의 헤더 flag3_off = [] for idx, section in enumerate(ff['pe']['Sections']): fsize = section['SizeRawData'] foff = section['PointerRawData'] flags.append([ int('0003' + mm[foff:foff + 2].encode('hex'), 16), gen_checksums(mm[foff:foff + 0x80]) ]) flag3_off.append(foff) self.flags_off[3] = flag3_off cs_size = [ 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80 ] if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 've.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) kavutil.vprint(None, 'MD5', cryptolib.md5(mm[:])) print kavutil.vprint('VE') vdb_name = os.path.split(filename)[-1] + '.vdb' kavutil.vprint(None, 'VDB File name', vdb_name) fp = open(vdb_name, 'w') for flag in flags: # kavutil.vprint(None, 'Flag', '%08X' % flag[0]) msg = 'Flag : %08x\n' % flag[0] fp.write(msg) for i, cs in enumerate(flag[1]): # kavutil.vprint(None, 'CS = %02X' % cs_pos[i], cs) msg = 'CS = %02x : %08x\n' % (cs_size[i], int(cs)) fp.write(msg) fp.write('\n') fp.close() for flag in flags: p1 = kavutil.handle_pattern_vdb.match_size( 've', flag[0]) # 일치하는 Flag가 있나? # print '%08x :' % flag[0], p1 # print flag[0] >> 16 if p1: for ve_id in p1.keys(): for idx in p1[ve_id]: cs1 = kavutil.handle_pattern_vdb.get_cs1( ve_id, idx) cs1_flag = cs1[0] cs1_off = cs1[1] cs1_size = cs1[2] cs1_crc = cs1[3] if flag[0] >> 16 == cs1_flag and cs1_off == 0 and cs1_size in cs_size: i = cs_size.index(cs1_size) # print '=', hex(flag[1][i]) if cs1_crc == flag[1][i]: # 1차 패턴이 같은가? vname = self.__scan_cs2(mm, ve_id, idx) if vname: return True, vname, 0, kernel.INFECTED else: buf = self.__get_data_crc32( mm, cs1_flag, cs1_off, cs1_size) if cs1_crc == int( gen_checksum(mm, cs1_off, cs1_size), 16): vname = self.__scan_cs2(mm, ve_id, idx) if vname: return True, vname, 0, kernel.INFECTED except IOError: pass kavutil.handle_pattern_vdb.__save_mem() # 메모리 용량을 낮추기 위해 사용 # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def parse(self): fileformat = {} mm = self.mm try: # EP e_entry = get_uint64(mm, 0x18, self.endian) # 섹션 헤더 정보 e_phoff = get_uint64(mm, 0x20, self.endian) e_shoff = get_uint64(mm, 0x28, self.endian) e_phnum = get_uint16(mm, 0x38, self.endian) e_shnum = get_uint16(mm, 0x3C, self.endian) e_shstrndx = get_uint16(mm, 0x3E, self.endian) # 섹션 이름이 저장된 테이블 name_table_off = get_uint64(mm, e_shoff + (0x40 * e_shstrndx) + 0x18, self.endian) name_table_size = get_uint64(mm, e_shoff + (0x40 * e_shstrndx) + 0x20, self.endian) name_table = mm[name_table_off:name_table_off + name_table_size] # print name_table.split('\x00') # print hex(name_table_off), hex(name_table_size) # 섹션 정보 구하기 for i in range(e_shnum): section = {} name_off = get_uint32(mm, e_shoff + (0x40 * i), self.endian) section['Name'] = name_table[name_off:].split('\x00', 1)[0] section['Type'] = get_uint32(mm, e_shoff + (0x40 * i) + 4, self.endian) section['Flag'] = get_uint64(mm, e_shoff + (0x40 * i) + 8, self.endian) section['RVA'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x10, self.endian) section['Offset'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x18, self.endian) section['Size'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x20, self.endian) self.sections.append(section) fileformat['Sections'] = self.sections fileformat['EntryPoint'] = e_entry # EntryPoint의 파일에서의 위치 구하기 ep_raw, sec_idx = self.rva_to_off(e_entry) fileformat['EntryPointRaw'] = ep_raw # EP의 Raw 위치 fileformat['EntryPoint_in_Section'] = sec_idx # EP가 포함된 섹션 if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'elf.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) print kavutil.vprint('ELF64') kavutil.vprint(None, 'Entry Point', '0x%016X' % e_entry) kavutil.vprint(None, 'Entry Point (Raw)', '0x%016X' % ep_raw) kavutil.vprint(None, 'Program Header Off', '0x%016X' % e_phoff) kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum) kavutil.vprint(None, 'Section Header Off', '0x%016X' % e_shoff) kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum) if e_shnum: print kavutil.vprint('Section Header') print ' %-15s %-8s %-16s %-16s %-16s %-16s' % ( 'Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size') print ' ' + ('-' * (76 + 16)) for p in self.sections: print ' %-15s %08X %016X %016X %016X %016X' % ( p['Name'], p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size']) print kavutil.vprint('Entry Point (Raw)') print kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80) print except (ValueError, struct.error) as e: pass return fileformat
def unarc(self, arc_engine_id, arc_name, fname_in_arc): fp = None mm = None data = None if arc_engine_id.find('arc_upx') != -1: filename = fname_in_arc try: # UPX로 압축된 파일 열기 fp = open(arc_name, 'rb') mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) p = pe.PE(mm, False, arc_name) pe_format = p.parse() # PE 파일 분석 if pe_format is None: return ValueError pe_img = pe_format['ImageBase'] pe_ep = pe_format['EntryPoint'] sections = pe_format['Sections'] ep_raw = pe_format['EntryPointRaw'] # EP의 Raw 위치 ep_nsec = pe_format['EntryPoint_in_Section'] # EP는 몇번째 섹션에 있는가? foff = 0 ssize = 0 dsize = 0 for section in sections: ssize = section['VirtualSize'] rva = section['RVA'] if rva <= pe_ep < rva+ssize: foff = section['PointerRawData'] i = sections.index(section) if i != 0: upx0 = sections[i-1]['RVA'] upx1 = sections[i]['RVA'] dsize = sections[i-1]['VirtualSize'] + ssize break if ssize == 0 or dsize == 0: raise ValueError upx_data_rva = kavutil.get_uint32(mm, ep_raw+2) sec_rva = sections[ep_nsec]['RVA'] skew = upx_data_rva - sec_rva - pe_img if mm[ep_raw+1] != '\xBE' or skew <= 0 or skew > 0xFFF: skew = 0 elif skew > ssize: skew = 0 else: raise ValueError data = mm[foff+skew:foff+ssize-skew] unpack_data = '' # UPX 해제된 이미지 if arc_engine_id[8:] == 'nrv2b': # UPX 알고리즘 중 nrv2b 압축인가? try: ret_val, unpack_data = upx_inflate2b(data, dsize, pe_ep, upx0, upx1, pe_img) except OverflowError: raise ValueError if self.verbose: kavutil.vprint('Decompress') kavutil.vprint(None, 'Compressed Size', '%d' % len(data)) if unpack_data == '': # 압축 해제 실패 kavutil.vprint(None, 'Decompress Size', 'Error') else: kavutil.vprint(None, 'Decompress Size', '%d' % len(unpack_data)) print if unpack_data == '': # 압축 해제 실패 raise ValueError data = unpack_data except IOError: pass except ValueError: pass if mm: mm.close() if fp: fp.close() return data return None
def parse(self): fileformat = {} mm = self.mm try: # EP e_entry = get_uint64(mm, 0x18, self.endian) # 섹션 헤더 정보 e_phoff = get_uint64(mm, 0x20, self.endian) e_shoff = get_uint64(mm, 0x28, self.endian) e_phnum = get_uint16(mm, 0x38, self.endian) e_shnum = get_uint16(mm, 0x3C, self.endian) e_shstrndx = get_uint16(mm, 0x3E, self.endian) # 섹션 이름이 저장된 테이블 name_table_off = get_uint64(mm, e_shoff + (0x40 * e_shstrndx) + 0x18, self.endian) name_table_size = get_uint64(mm, e_shoff + (0x40 * e_shstrndx) + 0x20, self.endian) name_table = mm[name_table_off:name_table_off+name_table_size] # print name_table.split('\x00') # print hex(name_table_off), hex(name_table_size) # 섹션 정보 구하기 for i in range(e_shnum): section = {} name_off = get_uint32(mm, e_shoff + (0x40 * i), self.endian) section['Name'] = name_table[name_off:].split('\x00', 1)[0] section['Type'] = get_uint32(mm, e_shoff + (0x40 * i) + 4, self.endian) section['Flag'] = get_uint64(mm, e_shoff + (0x40 * i) + 8, self.endian) section['RVA'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x10, self.endian) section['Offset'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x18, self.endian) section['Size'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x20, self.endian) self.sections.append(section) fileformat['Sections'] = self.sections fileformat['EntryPoint'] = e_entry # EntryPoint의 파일에서의 위치 구하기 ep_raw, sec_idx = self.rva_to_off(e_entry) fileformat['EntryPointRaw'] = ep_raw # EP의 Raw 위치 fileformat['EntryPoint_in_Section'] = sec_idx # EP가 포함된 섹션 if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'elf.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) print kavutil.vprint('ELF64') kavutil.vprint(None, 'Entry Point', '0x%016X' % e_entry) kavutil.vprint(None, 'Entry Point (Raw)', '0x%016X' % ep_raw) kavutil.vprint(None, 'Program Header Off', '0x%016X' % e_phoff) kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum) kavutil.vprint(None, 'Section Header Off', '0x%016X' % e_shoff) kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum) if e_shnum: print kavutil.vprint('Section Header') print ' %-15s %-8s %-16s %-16s %-16s %-16s' % ('Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size') print ' ' + ('-' * (76 + 16)) for p in self.sections: print ' %-15s %08X %016X %016X %016X %016X' % (p['Name'], p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size']) print kavutil.vprint('Entry Point (Raw)') print kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80) print except (ValueError, struct.error) as e: pass return fileformat
def unarc(self, arc_engine_id, arc_name, fname_in_arc): fp = None mm = None data = None if arc_engine_id.find('arc_upx') != -1: filename = fname_in_arc try: # UPX로 압축된 파일 열기 fp = open(arc_name, 'rb') mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) p = pe.PE(mm, False, arc_name) pe_format = p.parse() # PE 파일 분석 if pe_format is None: return ValueError pe_img = pe_format['ImageBase'] pe_ep = pe_format['EntryPoint'] sections = pe_format['Sections'] ep_raw = pe_format['EntryPointRaw'] # EP의 Raw 위치 ep_nsec = pe_format[ 'EntryPoint_in_Section'] # EP는 몇번째 섹션에 있는가? foff = 0 ssize = 0 dsize = 0 for section in sections: ssize = section['VirtualSize'] rva = section['RVA'] if rva <= pe_ep < rva + ssize: foff = section['PointerRawData'] i = sections.index(section) if i != 0: upx0 = sections[i - 1]['RVA'] upx1 = sections[i]['RVA'] dsize = sections[i - 1]['VirtualSize'] + ssize break if ssize == 0 or dsize == 0: raise ValueError upx_data_rva = kavutil.get_uint32(mm, ep_raw + 2) sec_rva = sections[ep_nsec]['RVA'] skew = upx_data_rva - sec_rva - pe_img if mm[ep_raw + 1] != '\xBE' or skew <= 0 or skew > 0xFFF: skew = 0 elif skew > ssize: skew = 0 else: raise ValueError data = mm[foff + skew:foff + ssize - skew] unpack_data = '' # UPX 해제된 이미지 if arc_engine_id[8:] == 'nrv2b': # UPX 알고리즘 중 nrv2b 압축인가? try: ret_val, unpack_data = upx_inflate2b( data, dsize, pe_ep, upx0, upx1, pe_img) except OverflowError: raise ValueError if unpack_data == '': # 압축 해제 실패 raise ValueError if self.verbose: kavutil.vprint('Decompress') kavutil.vprint(None, 'Compressed Size', '%d' % len(data)) kavutil.vprint(None, 'Decompress Size', '%d' % len(unpack_data)) print data = unpack_data except IOError: pass except ValueError: pass if mm: mm.close() if fp: fp.close() return data return None
def parse(self): fileformat = {} mm = self.mm try: # EP e_entry = get_uint32(mm, 0x18, self.endian) # ELF 헤더 정보 e_ident = ord(mm[7]) e_machine = get_uint16(mm, 0x12, self.endian) e_phoff = get_uint32(mm, 0x1C, self.endian) e_shoff = get_uint32(mm, 0x20, self.endian) e_phnum = get_uint16(mm, 0x2C, self.endian) e_shnum = get_uint16(mm, 0x30, self.endian) e_shstrndx = get_uint16(mm, 0x32, self.endian) # 프로그램 헤더 정보 구하기 for i in range(e_phnum): program_header = {} program_header['Type'] = get_uint32(mm, e_phoff + (0x20 * i) + 0, self.endian) program_header['Flag'] = get_uint32( mm, e_phoff + (0x20 * i) + 0x18, self.endian) program_header['RVA'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x8, self.endian) program_header['Offset'] = get_uint32( mm, e_phoff + (0x20 * i) + 0x4, self.endian) program_header['Size'] = get_uint32( mm, e_phoff + (0x20 * i) + 0x10, self.endian) self.program_headers.append(program_header) fileformat['ProgramHeaders'] = self.program_headers # 섹션 이름이 저장된 테이블 name_table_off = get_uint32(mm, e_shoff + (0x28 * e_shstrndx) + 0x10, self.endian) name_table_size = get_uint32(mm, e_shoff + (0x28 * e_shstrndx) + 0x14, self.endian) name_table = mm[name_table_off:name_table_off + name_table_size] # print name_table.split('\x00') # print hex(name_table_off), hex(name_table_size) # 섹션 정보 구하기 for i in range(e_shnum): section = {} name_off = get_uint32(mm, e_shoff + (0x28 * i), self.endian) section['Name'] = name_table[name_off:].split('\x00', 1)[0] section['Type'] = get_uint32(mm, e_shoff + (0x28 * i) + 4, self.endian) section['Flag'] = get_uint32(mm, e_shoff + (0x28 * i) + 8, self.endian) section['RVA'] = get_uint32(mm, e_shoff + (0x28 * i) + 0xC, self.endian) section['Offset'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x10, self.endian) section['Size'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x14, self.endian) self.sections.append(section) fileformat['Sections'] = self.sections fileformat['EntryPoint'] = e_entry # EntryPoint의 파일에서의 위치 구하기 ep_raw, sec_idx = self.rva_to_off(e_entry) fileformat['EntryPointRaw'] = ep_raw # EP의 Raw 위치 fileformat['EntryPoint_in_Section'] = sec_idx # EP가 포함된 섹션 if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'elf.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) print kavutil.vprint('ELF32') if e_ident in self.ident: msg1 = self.ident[e_ident] else: msg1 = 'Unknown' if e_machine in self.machine: msg2 = self.machine[e_machine] else: msg2 = 'Unknown' kavutil.vprint(None, 'Identifies', '%s (%s)' % (msg1, msg2)) kavutil.vprint(None, 'Entry Point', '0x%08X' % e_entry) kavutil.vprint(None, 'Entry Point (Raw)', '0x%08X' % ep_raw) kavutil.vprint(None, 'Program Header Off', '0x%08X' % e_phoff) kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum) kavutil.vprint(None, 'Section Header Off', '0x%08X' % e_shoff) kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum) if e_phnum: print kavutil.vprint('Program Header') print ' %-8s %-8s %-8s %-8s %-8s' % ( 'Type', 'Flag', 'RVA', 'Offset', 'Size') print ' ' + ('-' * 44) for p in self.program_headers: print ' %08X %08X %08X %08X %08X' % ( p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size']) if e_shnum: print kavutil.vprint('Section Header') print ' %-15s %-8s %-8s %-8s %-8s %-8s' % ( 'Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size') print ' ' + ('-' * (44 + 16)) for p in self.sections: print ' %-15s %08X %08X %08X %08X %08X' % ( p['Name'], p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size']) print kavutil.vprint('Entry Point (Raw)') print kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80) print except (ValueError, struct.error) as e: pass return fileformat
def analysis_ole10native(mm, verbose=False): fileformat = {} try: size = kavutil.get_uint32(mm, 0) if mm[4:6] == '\x02\x00': if len(mm) == size + 4: fileformat['size'] = len(mm) # 포맷 주요 정보 저장 label = mm[6:6 + MAX_PATH].split('\x00', 1)[0] fileformat['label'] = label off = 6 + len(label) + 1 fname = mm[off:off + MAX_PATH].split('\x00', 1)[0] off += len(fname) + 1 off += 2 # flag unknown_size = ord(mm[off]) off += 1 + unknown_size + 2 command = mm[off:off + MAX_PATH].split('\x00', 1)[0] off += len(command) + 1 data_size = kavutil.get_uint32(mm, off) fileformat['data_off'] = off + 4 fileformat['data_size'] = data_size if len(mm) < off + data_size: # 오류 raise ValueError if verbose: print kavutil.vprint('Ole10Native Stream') kavutil.vprint(None, 'Size', '0x%08X' % size) kavutil.vprint(None, 'Label', label) kavutil.vprint(None, 'File Name', fname) kavutil.vprint(None, 'Command Line', command) kavutil.vprint(None, 'Data Offset', '0x%08X' % (off + 4)) kavutil.vprint(None, 'Data Size', '0x%08X' % data_size) print kavutil.vprint('Data Dump') print kavutil.HexDump().Buffer(mm[:], off + 4, 0x80) print return fileformat except ValueError: pass except struct.error: pass return None
def parse(self): fileformat = {} mm = self.mm try: # EP e_entry = get_uint32(mm, 0x18, self.endian) # ELF 헤더 정보 e_ident = ord(mm[7]) e_machine = get_uint16(mm, 0x12, self.endian) e_phoff = get_uint32(mm, 0x1C, self.endian) e_shoff = get_uint32(mm, 0x20, self.endian) e_phnum = get_uint16(mm, 0x2C, self.endian) e_shnum = get_uint16(mm, 0x30, self.endian) e_shstrndx = get_uint16(mm, 0x32, self.endian) # 프로그램 헤더 정보 구하기 for i in range(e_phnum): program_header = {} program_header['Type'] = get_uint32(mm, e_phoff + (0x20 * i) + 0, self.endian) program_header['Flag'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x18, self.endian) program_header['RVA'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x8, self.endian) program_header['Offset'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x4, self.endian) program_header['Size'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x10, self.endian) self.program_headers.append(program_header) fileformat['ProgramHeaders'] = self.program_headers # 섹션 이름이 저장된 테이블 name_table_off = get_uint32(mm, e_shoff + (0x28 * e_shstrndx) + 0x10, self.endian) name_table_size = get_uint32(mm, e_shoff + (0x28 * e_shstrndx) + 0x14, self.endian) name_table = mm[name_table_off:name_table_off+name_table_size] # print name_table.split('\x00') # print hex(name_table_off), hex(name_table_size) # 섹션 정보 구하기 for i in range(e_shnum): section = {} name_off = get_uint32(mm, e_shoff + (0x28 * i), self.endian) section['Name'] = name_table[name_off:].split('\x00', 1)[0] section['Type'] = get_uint32(mm, e_shoff + (0x28 * i) + 4, self.endian) section['Flag'] = get_uint32(mm, e_shoff + (0x28 * i) + 8, self.endian) section['RVA'] = get_uint32(mm, e_shoff + (0x28 * i) + 0xC, self.endian) section['Offset'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x10, self.endian) section['Size'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x14, self.endian) self.sections.append(section) fileformat['Sections'] = self.sections fileformat['EntryPoint'] = e_entry # EntryPoint의 파일에서의 위치 구하기 ep_raw, sec_idx = self.rva_to_off(e_entry) fileformat['EntryPointRaw'] = ep_raw # EP의 Raw 위치 fileformat['EntryPoint_in_Section'] = sec_idx # EP가 포함된 섹션 if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'elf.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) print kavutil.vprint('ELF32') if e_ident in self.ident: msg1 = self.ident[e_ident] else: msg1 = 'Unknown' if e_machine in self.machine: msg2 = self.machine[e_machine] else: msg2 = 'Unknown' kavutil.vprint(None, 'Identifies', '%s (%s)' % (msg1, msg2)) kavutil.vprint(None, 'Entry Point', '0x%08X' % e_entry) kavutil.vprint(None, 'Entry Point (Raw)', '0x%08X' % ep_raw) kavutil.vprint(None, 'Program Header Off', '0x%08X' % e_phoff) kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum) kavutil.vprint(None, 'Section Header Off', '0x%08X' % e_shoff) kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum) if e_phnum: print kavutil.vprint('Program Header') print ' %-8s %-8s %-8s %-8s %-8s' % ('Type', 'Flag', 'RVA', 'Offset', 'Size') print ' ' + ('-' * 44) for p in self.program_headers: print ' %08X %08X %08X %08X %08X' % (p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size']) if e_shnum: print kavutil.vprint('Section Header') print ' %-15s %-8s %-8s %-8s %-8s %-8s' % ('Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size') print ' ' + ('-' * (44 + 16)) for p in self.sections: print ' %-15s %08X %08X %08X %08X %08X' % (p['Name'], p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size']) print kavutil.vprint('Entry Point (Raw)') print kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80) print except (ValueError, struct.error) as e: pass return fileformat
def parse(self): self.fp = open(self.filename, 'rb') fsize = os.path.getsize(self.filename) if fsize == 0: return False self.mm = mmap.mmap(self.fp.fileno(), 0, access=mmap.ACCESS_READ) flag = kavutil.get_uint32(self.mm, 0) head_size = kavutil.get_uint32(self.mm, 0x14) comp_size = kavutil.get_uint32(self.mm, 0x18) data, case_type = self.get_data() # NSIS의 모든 데이터를 가진다. self.body_data = data self.case_type = case_type if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'nsis.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) print kavutil.vprint('NSIS') kavutil.vprint(None, 'Flag', '%d' % flag) kavutil.vprint(None, 'Uncompress Case', '%d' % case_type) print kavutil.vprint('Uncompress Data') print kavutil.HexDump().Buffer(data, 0, 0x80) s = self.nsis_header.namelist_ex() if len(s): print kavutil.vprint('File Extract') print for t in s: (foff, fname, ftime, extract_type) = t print "%08X | %-45s | %s" % (foff, fname, ftime if ftime != '' else 'N/A') return True
def __scan_asn1(self, filehandle, filename, fileformat, filename_ex): mm = filehandle ff = fileformat['ff_pe'] cert_off = ff['pe'].get('CERTIFICATE_Offset', 0) cert_size = ff['pe'].get('CERTIFICATE_Size', 0) if cert_off != 0 and cert_size != 0: if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'adware.kmd') # 인증서 추출 cert_data = mm[cert_off:cert_off + cert_size] asn1 = ASN1() asn1.set_data(cert_data[8:]) try: r = asn1.parse() # Signed Data 이면서 버전 정보가 1인가? if r[0][0] == '2A 86 48 86 F7 0D 01 07 02' and r[0][1][0][0] == '01': signeddata = r[0][1][0] certificates = signeddata[3] signerinfo = r[0][1][0][-1] issuer_and_serialnumber = signerinfo[0][1] issuer_serial = issuer_and_serialnumber[1] for cert in certificates: if cert[0][1] == issuer_serial: # 동일한 일련번호 찾기 for x in cert[0][5]: if x[0][0] == '55 04 03': # Common Name signer_name = x[0][1] break else: continue # no break encountered break else: raise IndexError # 일련번호의 길이가 제각각이라 md5 고정길이로 만듬 fmd5 = cryptolib.md5(issuer_serial) fsize = kavutil.get_uint16(fmd5.decode('hex'), 0) if self.verbose: kavutil.vprint('Signer') kavutil.vprint(None, 'Name', signer_name) kavutil.vprint(None, 'Serial Number', issuer_serial) msg = '%d:%s: # %s, %s\n' % (fsize, fmd5, signer_name, cryptolib.sha256(mm)) open('adware.mdb', 'at').write(msg) if fsize and kavutil.handle_pattern_md5.match_size('adware', fsize): vname = kavutil.handle_pattern_md5.scan('adware', fsize, fmd5) if vname: pos = ff['pe'].get('EntryPointRaw', 0) if mm[pos:pos + 4] == '\xff\x25\x00\x20': pf = 'MSIL' else: pf = 'Win32' vname = kavutil.normal_vname(vname, pf) return True, vname, 0, kernel.INFECTED except IndexError: pass # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def __scan_asn1(self, filehandle, filename, fileformat, filename_ex): mm = filehandle ff = fileformat['ff_pe'] cert_off = ff['pe'].get('CERTIFICATE_Offset', 0) cert_size = ff['pe'].get('CERTIFICATE_Size', 0) if cert_off != 0 and cert_size != 0: if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'adware.kmd') # 인증서 추출 cert_data = mm[cert_off:cert_off + cert_size] asn1 = ASN1() asn1.set_data(cert_data[8:]) try: r = asn1.parse() # Signed Data 이면서 버전 정보가 1인가? if r[0][0] == '2A 86 48 86 F7 0D 01 07 02' and r[0][1][0][ 0] == '01': signeddata = r[0][1][0] certificates = signeddata[3] signerinfo = r[0][1][0][-1] issuer_and_serialnumber = signerinfo[0][1] issuer_serial = issuer_and_serialnumber[1] for cert in certificates: if cert[0][1] == issuer_serial: # 동일한 일련번호 찾기 for x in cert[0][5]: if x[0][0] == '55 04 03': # Common Name signer_name = x[0][1] break else: continue # no break encountered break else: raise IndexError # 일련번호의 길이가 제각각이라 md5 고정길이로 만듬 fmd5 = cryptolib.md5(issuer_serial) fsize = kavutil.get_uint16(fmd5.decode('hex'), 0) if self.verbose: kavutil.vprint('Signer') kavutil.vprint(None, 'Name', signer_name) kavutil.vprint(None, 'Serial Number', issuer_serial) msg = '%d:%s: # %s, %s\n' % (fsize, fmd5, signer_name, cryptolib.sha256(mm)) open('adware.mdb', 'at').write(msg) if fsize and kavutil.handle_pattern_md5.match_size( 'adware', fsize): vname = kavutil.handle_pattern_md5.scan( 'adware', fsize, fmd5) if vname: pos = ff['pe'].get('EntryPointRaw', 0) if mm[pos:pos + 4] == '\xff\x25\x00\x20': pf = 'MSIL' else: pf = 'Win32' vname = kavutil.normal_vname(vname, pf) return True, vname, 0, kernel.INFECTED except IndexError: pass # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 mm = filehandle o = None try: # 미리 분석된 파일 포맷중에 OLE 포맷이 있는가? if 'ff_ole' in fileformat: o = ole.OleFile(filename) ole_lists = o.listdir() for pps_name in ole_lists: if pps_name.lower().find('/vba/dir') != -1: # 오피스 97 매크로 존재 여부 pics = o.openstream(pps_name) data = pics.read() ret, decom_data = decompress(data) # dir 스트림 압축 해제 if ret: vba_modules = analysis_dir_stream(decom_data) t = pps_name.split('/') for vba in vba_modules: t[-1] = vba[0] t_pps_name = '/'.join(t) t_pics = o.openstream(t_pps_name) # 매크로가 존재하는 스트림 열기 t_data = t_pics.read() t_ret, buf = decompress(t_data[vba[1]:]) # 매크로 소스코드 획득 완료 buf = buf.replace('\r\n', '\n') if t_ret: if self.verbose: # 매크로 소스코드 출력 kavutil.vprint('Macro Source') kavutil.vprint(None, 'PPS', '%s' % t_pps_name) print buf buf = self.p_vba_cmt.sub('', buf) # 주석문 제거 buf = buf.lower() # 영어 소문자로 통일 key_words = self.p_vba_word.findall(buf) vba_keyword_crc32 = set() for i in range(len(key_words)-1): word = key_words[i] + key_words[i+1] c = zlib.crc32(word) & 0xffffffffL vba_keyword_crc32.add(c) # 테스트 if self.verbose: max_len = len(key_words[0]) t_word = [] for i in range(len(key_words)-1): word = key_words[i] + key_words[i+1] c = zlib.crc32(word) & 0xffffffffL t_word.append([c, key_words[i], key_words[i+1]]) if len(key_words[i+1]) > max_len: max_len = len(key_words[i+1]) t_l = '+-' + ('-' * 8) + '-+-' + ('-' * max_len) + '-+-' + ('-' * max_len) + '-+' print t_l msg = '| %%-8s | %%-%ds | %%-%ds |' % (max_len, max_len) print msg % ('CRC32', 'Keyword #1', 'Keyword #2') print t_l msg = '| %%08X | %%-%ds | %%-%ds |' % (max_len, max_len) for n in t_word: print msg % (n[0], n[1], n[2]) print t_l # Heuristic 검사 for macro_crc in self.word97_macro_crcs: if macro_crc.issubset(vba_keyword_crc32): return True, 'Virus.MSWord.Generic', MALWARE_ID_WORD97, kernel.SUSPECT except IOError: pass except ole.Error: pass if o: o.close() # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.INFECTED
def parse(self): mm = self.mm pe_format = { 'PE_Position': 0, 'EntryPoint': 0, 'SectionNumber': 0, 'Sections': None, 'EntryPointRaw': 0, 'FileAlignment': 0 } try: if mm[0:2] != 'MZ': # MZ로 시작하나? raise ValueError # PE 표식자 위치 알아내기 pe_pos = kavutil.get_uint32(mm, 0x3C) # PE 인가? if mm[pe_pos:pe_pos + 4] != 'PE\x00\x00': raise ValueError pe_format['PE_Position'] = pe_pos # Optional Header의 Magic ID? if mm[pe_pos + 0x18:pe_pos + 0x18 + 2] != '\x0B\x01': raise ValueError # Entry Point 구하기 pe_ep = kavutil.get_uint32(mm, pe_pos + 0x28) pe_format['EntryPoint'] = pe_ep # Image Base 구하기 pe_img = kavutil.get_uint32(mm, pe_pos + 0x34) pe_format['ImageBase'] = pe_img # File Alignment 구하기 self.pe_file_align = kavutil.get_uint32(mm, pe_pos + 0x3C) pe_format['FileAlignment'] = self.pe_file_align # Section 개수 구하기 section_num = kavutil.get_uint16(mm, pe_pos + 0x6) pe_format['SectionNumber'] = section_num # Optional Header 크기 구하기 opthdr_size = kavutil.get_uint16(mm, pe_pos + 0x14) pe_format['OptionalHederSize'] = opthdr_size # t섹션 시작 위치 section_pos = pe_pos + 0x18 + opthdr_size # 모든 섹션 정보 추출 for i in range(section_num): section = {} s = section_pos + (0x28 * i) section['Name'] = mm[s:s + 8].replace('\x00', '') section['VirtualSize'] = kavutil.get_uint32(mm, s + 8) section['RVA'] = kavutil.get_uint32(mm, s + 12) section['SizeRawData'] = kavutil.get_uint32(mm, s + 16) section['PointerRawData'] = kavutil.get_uint32(mm, s + 20) section['Characteristics'] = kavutil.get_uint32(mm, s + 36) self.sections.append(section) pe_format['Sections'] = self.sections # EntryPoint의 파일에서의 위치 구하기 ep_raw, sec_idx = self.rva_to_off(pe_ep) pe_format['EntryPointRaw'] = ep_raw # EP의 Raw 위치 pe_format['EntryPoint_in_Section'] = sec_idx # EP가 포함된 섹션 # 리소스 분석 rsrc_rva = kavutil.get_uint32(mm, pe_pos + 0x88) # 리소스 위치(RVA) rsrc_size = kavutil.get_uint32(mm, pe_pos + 0x8C) # 리소스 크기 if rsrc_rva: # 리소스가 존재한가? try: rsrc_off, _ = self.rva_to_off(rsrc_rva) # 리소스 위치 변환 # Type 체크 num_type_name = kavutil.get_uint16(mm, rsrc_off + 0xC) num_type_id = kavutil.get_uint16(mm, rsrc_off + 0xE) for i in range(num_type_name + num_type_id): type_id = kavutil.get_uint32(mm, rsrc_off + 0x10 + (i * 8)) name_id_off = kavutil.get_uint32( mm, rsrc_off + 0x14 + (i * 8)) # Type이 사용자가 정의한 이름 or RCDATA? if type_id & 0x80000000 == 0x80000000 or type_id == 0xA: if type_id & 0x80000000 == 0x80000000: # 사용자가 정의한 이름 추출 string_off = (type_id & 0x7FFFFFFF) + rsrc_off len_name = kavutil.get_uint16(mm, string_off) rsrc_type_name = mm[string_off + 2:string_off + 2 + (len_name * 2):2] else: rsrc_type_name = 'RCDATA' # Name ID name_id_off = (name_id_off & 0x7FFFFFFF) + rsrc_off num_name_id_name = kavutil.get_uint16( mm, name_id_off + 0xC) num_name_id_id = kavutil.get_uint16( mm, name_id_off + 0xE) for j in range(num_name_id_name + num_name_id_id): name_id_id = kavutil.get_uint32( mm, name_id_off + 0x10 + (j * 8)) language_off = kavutil.get_uint32( mm, name_id_off + 0x14 + (j * 8)) # 리소스 영역의 최종 이름 생성 if name_id_id & 0x80000000 == 0x80000000: string_off = (name_id_id & 0x7FFFFFFF) + rsrc_off len_name = kavutil.get_uint16( mm, string_off) rsrc_name_id_name = mm[string_off + 2:string_off + 2 + (len_name * 2):2] string_name = rsrc_type_name + '/' + rsrc_name_id_name else: string_name = rsrc_type_name + '/' + hex( name_id_id).upper()[2:] # Language language_off = (language_off & 0x7FFFFFFF) + rsrc_off num_language_name = kavutil.get_uint16( mm, language_off + 0xC) num_language_id = kavutil.get_uint16( mm, language_off + 0xE) for k in range(num_language_name + num_language_id): # language_id = kavutil.get_uint32(mm, language_off + 0x10 + (k * 8)) data_entry_off = kavutil.get_uint32( mm, language_off + 0x14 + (k * 8)) data_entry_off = (data_entry_off & 0x7FFFFFFF) + rsrc_off data_rva = kavutil.get_uint32( mm, data_entry_off) data_off, _ = self.rva_to_off(data_rva) data_size = kavutil.get_uint32( mm, data_entry_off + 4) if data_size > 8192: # 최소 8K 이상인 리소스만 데이터로 추출 if 'Resource_UserData' in pe_format: pe_format['Resource_UserData'][ string_name] = (data_off, data_size) else: pe_format['Resource_UserData'] = { string_name: (data_off, data_size) } except struct.error: pass # if 'Resource_UserData' in pe_format: # print pe_format['Resource_UserData'] # Import API 분석 imp_rva = kavutil.get_uint32(mm, pe_pos + 0x80) # Import API 위치(RVA) imp_size = kavutil.get_uint32(mm, pe_pos + 0x84) # Import API 크기 if imp_rva: # Import API 존재 imp_api = {} # print 'IMP : %08X' % imp_rva imp_off = self.rva_to_off(imp_rva)[0] # print hex(imp_off), imp_size imp_data = mm[imp_off:imp_off + imp_size] for i in range(imp_size / 0x14): # DLL 정보 크기가 0x14 try: dll_rva = kavutil.get_uint32(imp_data, (i * 0x14) + 0xC) api_rva = kavutil.get_uint32(imp_data, (i * 0x14)) bo = 2 if api_rva == 0: api_rva = kavutil.get_uint32( imp_data, (i * 0x14) + 0x10) bo = 0 # print hex(api_rva) if dll_rva == 0: # DLL 정보가 없음 break t_off = self.rva_to_off(dll_rva)[0] dll_name = p_str.search(mm[t_off:t_off + 0x20]).group() # print '[+]', dll_name imp_api[dll_name] = [] t_off = self.rva_to_off(api_rva)[0] while True: try: api_name_rva = kavutil.get_uint32(mm, t_off) except struct.error: break if api_name_rva & 0x80000000 == 0x80000000: # Odinal API t_off += 4 continue if api_name_rva == 0: break t = self.rva_to_off(api_name_rva)[0] # print hex(t_off), hex(t) api_name = p_str.search(mm[t + bo:t + bo + 0x20]).group() # print ' ', api_name imp_api[dll_name].append(api_name) t_off += 4 except struct.error: pass pe_format['Import_API'] = imp_api # 디지털 인증서 분석 cert_off = kavutil.get_uint32(mm, pe_pos + 0x98) # 디지털 인증서 위치(유일하게 RVA가 아닌 오프셋) cert_size = kavutil.get_uint32(mm, pe_pos + 0x9C) # 디지털 인증서 크기 if cert_off: # 디지털 인증서 존재 if cert_off + cert_size <= len(mm[:]): # UPack의 경우 이상한 값이 셋팅 됨 pe_format['CERTIFICATE_Offset'] = cert_off pe_format['CERTIFICATE_Size'] = cert_size if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'pe.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) kavutil.vprint(None, 'MD5', cryptolib.md5(mm[:])) print kavutil.vprint('PE') kavutil.vprint(None, 'EntryPoint', '%08X' % pe_format['EntryPoint']) kavutil.vprint(None, 'EntryPoint (Section)', '%d' % pe_format['EntryPoint_in_Section']) # 섹션 보기 if section_num: print kavutil.vprint('Section Header') print ' %-8s %-8s %-8s %-8s %-8s %-8s' % ( 'Name', 'VOFF', 'VSIZE', 'FOFF', 'FSIZE', 'EXEC') print ' ' + ('-' * (9 * 6 - 1)) for s in self.sections: print ' %-8s %08X %08X %08X %08X %-05s' % ( s['Name'], s['RVA'], s['VirtualSize'], s['PointerRawData'], s['SizeRawData'], s['Characteristics'] & 0x20000000 == 0x20000000) if section_num: print kavutil.vprint('Section MD5') print ' %-8s %-8s %-32s' % ('Name', 'FSIZE', 'MD5') print ' ' + ('-' * ((9 * 2 - 1) + 32)) for s in self.sections: if s['Characteristics'] & 0x20000000 == 0x20000000: off = s['PointerRawData'] size = s['SizeRawData'] fmd5 = cryptolib.md5(mm[off:off + size]) print ' %-8s %8d %s' % (s['Name'], size, fmd5) print kavutil.vprint('Entry Point (Raw)') print kavutil.HexDump().Buffer(mm[:], pe_format['EntryPointRaw'], 0x80) print except ValueError: return None return pe_format
def scan(self, filehandle, filename, fileformat, filename_ex): # 악성코드 검사 zfile = None mm = filehandle try: if 'ff_eps' in fileformat: if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'eps.kmd') kavutil.vprint(None, 'File name', os.path.split(filename)[-1]) print scan_ptns = [] eps_keywords = fileformat['ff_eps'] # Keyword 추출 if self.verbose: kavutil.vprint('EPS Keyword') for i, name in enumerate(eps_keywords): kavutil.vprint(None, 'Keyword #%d' % (i+1), name) print if 'string' in eps_keywords: scan_ptns.append(self.p_hex1) if 'hexstring' in eps_keywords or 'readhexstring' in eps_keywords: scan_ptns.append(self.p_hex2) for i, ptn in enumerate(scan_ptns): # Hex 문자열이 존재하는가? t_hex = ptn.findall(mm) if self.verbose and len(t_hex) > 0: kavutil.vprint('HEX #%d' % (i+1)) for i, x in enumerate(t_hex): kavutil.vprint(None, 'Hex String #%d' % (i+1), x) print # 화이트 리스트 제거 s_hex = ''.join(t_hex) p = re.compile(r'\s|<|>') t = p.sub('', s_hex) if len(t) > 10 * 1024: # 10K 이상인가? return True, 'Trojan.EPS.Generic', 0, kernel.INFECTED except IOError: pass # 악성코드를 발견하지 못했음을 리턴한다. return False, '', -1, kernel.NOT_FOUND
def analysis_ole10native(mm, verbose=False): fileformat = {} try: if mm[:2] == '\x02\x00': size = len(mm) fileformat['size'] = size # 포맷 주요 정보 저장 label = mm[2:2 + MAX_PATH].split('\x00', 1)[0] fileformat['label'] = label off = 2 + len(label) + 1 fname = mm[off:off + MAX_PATH].split('\x00', 1)[0] off += len(fname) + 1 off += 2 # flag unknown_size = ord(mm[off]) off += 1 + unknown_size + 2 command = mm[off:off + MAX_PATH].split('\x00', 1)[0] off += len(command) + 1 data_size = kavutil.get_uint32(mm, off) fileformat['data_off'] = off + 4 fileformat['data_size'] = data_size if len(mm) < off + data_size: # 오류 raise ValueError if verbose: print kavutil.vprint('Ole10Native Stream') kavutil.vprint(None, 'Size', '0x%08X' % size) kavutil.vprint(None, 'Label', label) kavutil.vprint(None, 'File Name', fname) kavutil.vprint(None, 'Command Line', command) kavutil.vprint(None, 'Data Offset', '0x%08X' % (off + 4)) kavutil.vprint(None, 'Data Size', '0x%08X' % data_size) print kavutil.vprint('Data Dump') print kavutil.HexDump().Buffer(mm[:], off + 4, 0x80) print return fileformat except ValueError: pass except struct.error: pass return None
def parse(self): self.temp_name = tempfile.mktemp(prefix='knsf') # NSIS 위치 읽기 fp = open(self.filename, 'rb') fp.seek(self.start_offset) data = fp.read() fp.close() open(self.temp_name, 'wb').write(data) self.fp = open(self.temp_name, 'rb') fsize = os.path.getsize(self.temp_name) if fsize == 0: return False self.mm = mmap.mmap(self.fp.fileno(), 0, access=mmap.ACCESS_READ) flag = kavutil.get_uint32(self.mm, 0) head_size = kavutil.get_uint32(self.mm, 0x14) comp_size = kavutil.get_uint32(self.mm, 0x18) data, case_type = self.get_data() # NSIS의 모든 데이터를 가진다. self.body_data = data self.case_type = case_type if self.verbose: print '-' * 79 kavutil.vprint('Engine') kavutil.vprint(None, 'Engine', 'nsis.kmd') kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1]) print kavutil.vprint('NSIS') kavutil.vprint(None, 'Flag', '%d' % flag) kavutil.vprint(None, 'Uncompress Case', '%d' % case_type) print kavutil.vprint('Uncompress Data') print kavutil.HexDump().Buffer(data, 0, 0x80) s = self.nsis_header.namelist_ex() if len(s): print kavutil.vprint('File Extract') print for t in s: (foff, fname, ftime, extract_type) = t print "%08X | %-45s | %s" % (foff, fname, ftime if ftime != '' else 'N/A') return True