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 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): 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
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): 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 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 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