def feature(self, filehandle, filename, fileformat, filename_ex, malware_id): # Feature 추출 try: mm = filehandle # 미리 분석된 파일 포맷중에 PE 포맷이 있는가? if 'ff_pe' in fileformat: buf = mm[:] fmd5 = cryptolib.md5(buf).decode('hex') # 파일 전체 MD5 생성 header = 'PE\x00\x00' + struct.pack('<L', malware_id) + fmd5 pe = PE(mm, False, filename) pe_format = pe.parse() if not pe_format: return None pe_off = pe_format['PE_Position'] # pe.DOS_HEADER.e_lfanew ep = pe_format[ 'EntryPoint'] # pe.OPTIONAL_HEADER.AddressOfEntryPoint text_off = 0 text_size = 0 for sec in pe_format['Sections']: # pe.sections: rva = sec['RVA'] # sec.VirtualAddress vsize = sec['VirtualSize'] # sec.Misc_VirtualSize if rva <= ep <= rva + vsize: text_off = sec[ 'PointerRawData'] # sec.PointerToRawData text_size = sec['SizeRawData'] # sec.SizeOfRawData break # Feature 추출 f = kavutil.Feature() data = '' # 1. text 섹션에 대해서 엔트로피를 추출한다. data += f.entropy(mm[text_off:text_off + text_size]) # 2. PE 헤더 정보를 추출한다. data += mm[pe_off + 6:pe_off + 6 + 256] # 3. DATA 섹션 2-gram 추출하기 data_off = 0 data_size = 0 for sec in pe_format['Sections']: # pe.sections: if sec['Characteristics'] & 0x40000040 == 0x40000040: # if DATA and Read data_off = sec[ 'PointerRawData'] # sec.PointerToRawData data_size = sec['SizeRawData'] # sec.SizeOfRawData break data += f.k_gram(mm[data_off:data_off + data_size], 2) # 4. Import API 해시 추가하기 def import_api(l_pe_format): api_hash = set() l_data = '' if 'Import_API' in l_pe_format: imp_api = pe_format['Import_API'] # print imp_api for dll in imp_api.keys(): for api in dll: api_name = ('%s:%s' % (dll, api)).lower() api_hash.add( struct.pack( '<H', cryptolib.CRC16().calculate(api_name))) t = list(api_hash) l_data = ''.join(t) if len(l_data) < 256: l_data += '\x00' * (256 - len(l_data)) return l_data[:256] data += import_api(pe_format) open('pe.bin', 'ab').write(header + data) # Feature 파일 생성 return True except IOError: pass # Feature 추출 실패했음을 리턴한다. return False
def feature(self, filehandle, filename, fileformat, filename_ex, malware_id): # Feature 추출 try: mm = filehandle # 미리 분석된 파일 포맷중에 NSIS 포맷이 있는가? # 파일의 전체 영역에 대해 MD5를 구하기 위해 ff_attach를 확인한다. if 'ff_attach' in fileformat: foff = fileformat['ff_attach']['Attached_Pos'] # NSIS가 맞나? if mm[foff + 4:foff + 20] == '\xEF\xBE\xAD\xDENullsoftInst': buf = mm[:] fmd5 = cryptolib.md5(buf).decode('hex') # 파일 전체 MD5 생성 header = 'NSIS' + struct.pack('<L', malware_id) + fmd5 rname = tempfile.mktemp(prefix='ktmp') open(rname, 'wb').write(mm[foff:]) max_len = 0 max_extract_data = '' # 용량이 큰 파일 n = NSIS(rname, False) if n.parse() is False: n.close() return False for name in n.namelist(): data = n.read(name) if data is None: continue data_len = len(data) if max_len < data_len: max_len = data_len max_extract_data = data # Feature 추출 f = kavutil.Feature() data = '' # 1. NSIS 내부 파일 중 용량이 제일 큰 파일을 찾아 엔트로피를 추출한다. data += f.entropy(max_extract_data) # 2. NSIS 헤더 정보를 추출한다. data += n.nsis_header.header_data[:256] # 3. NSIS 헤더의 문자열을 추출 후 2-gram 처리한다. data += f.k_gram(n.nsis_header.header_data, 2) # 4. NSIS 스크립트의 OPcode를 추출한다. t = [0] * 256 off = n.nsis_header.nh.entries for i in range(n.nsis_header.nh.entries_num): nr = StructNsisRecord() memmove(addressof(nr), n.nsis_header.header_data[off:], sizeof(nr)) off += sizeof(nr) if t[nr.which & 0xff] < 0xff: t[nr.which & 0xff] += 1 # Opcode 등장 회수를 누적 data += ''.join(map(chr, t)) n.close() open('nsis.bin', 'ab').write(header + data) # Feature 파일 생성 os.remove(rname) return True except IOError: pass # Feature 추출 실패했음을 리턴한다. return False