Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    def scan(self, filehandle, filename):
        try:
            mm = filehandle

            size = os.path.getsize(filename)
            if size == 68:
                fmd5 = cryptolib.md5(mm[:68])

                if fmd5 == '44d88612fea8a8f36de82e1278abb02f':
                    return True, 'EICAR-Test-File (not a virus)', 0

        except IOError:
            pass

        return False, '', -1
Ejemplo n.º 3
0
    def scan(self, filehandle, filename):
        try:
            mm = filehandle

            size = os.path.getsize(filename)  # 검사 대상 파일의 크기 계산
            if size == 68:
                # 크기가 일치한다면 MD5 해시 계산
                fmd5 = cryptolib.md5(mm[:68])

                # 파일에서 얻은 해시 값과 EICAR Test 악성코드의 해시 값이 일치하는가?
                if fmd5 == '44d88612fea8a8f36de82e1278abb02f':
                    return True, 'EICAR-Test-File (not a virus)', 0
        except IOError:
            pass

    # 악성코드 발견 못하면
        return False, '', -1
Ejemplo n.º 4
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        try:
            mm = filehandle

            size = os.path.getsize(filename)  # 검사 대상 파일 크기를 구한다.
            if size == 68:  # EICAR Test 악성코드의 크기와 일치하는가?
                # 크기가 일치한다면 MD5 해시 계산
                fmd5 = cryptolib.md5(mm[:68])
                
                # 파일에서 얻은 해시 값과 EICAR Test 악성코드의 해시 값이 일치하는가?
                if fmd5 == '44d88612fea8a8f36de82e1278abb02f':
                    return True, 'EICAR-Test-File (not a virus)', 0, kernel.INFECTED
        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        try:
            mm = filehandle

            # 미리 분석된 파일 포맷중에 PE 포맷이 있는가?
            if 'ff_pe' in fileformat:
                ff = fileformat['ff_pe']
                # print ff

                for section in ff['pe']['Sections']:
                    if (section['Characteristics'] & 0x20000000) == 0x20000000:  # 실행 속성?
                        # print section['Name'], hex(section['SizeRawData'])
                        fsize = section['SizeRawData']
                        if kavutil.handle_pattern_md5.match_size('emalware', fsize):
                            foff = section['PointerRawData']
                            fmd5 = cryptolib.md5(mm[foff:foff+fsize])
                            # print fsize, fmd5
                            vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                            if vname:
                                return True, vname, 0, kernel.INFECTED

            # 미리 분석된 파일 포맷중에 ELF 포맷이 있는가?
            elif 'ff_elf' in fileformat:
                ff = fileformat['ff_elf']

                if len(ff['elf']['Sections']):
                    for section in ff['elf']['Sections']:
                        if (section['Type'] & 0x1) == 0x1 and (section['Flag'] & 0x4) == 0x4:  # 프로그램 데이터이면서 실행 속성?
                            # print section['Name'], section['Size'], section['Offset']
                            fsize = section['Size']
                            if kavutil.handle_pattern_md5.match_size('emalware', fsize):
                                foff = section['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                                if vname:
                                    return True, vname, 0, kernel.INFECTED
                elif len(ff['elf']['ProgramHeaders']):
                    for ph in ff['elf']['ProgramHeaders']:
                        if (ph['Type'] & 0x1) == 0x1 and (ph['Flag'] & 0x1) == 0x1:
                            fsize = ph['Size']
                            if kavutil.handle_pattern_md5.match_size('emalware', fsize):
                                foff = ph['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                                if vname:
                                    return True, vname, 0, kernel.INFECTED

                # Mirai 변종 진단
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        fsize = section['Size']
                        foff = section['Offset']
                        if self.p_linux_mirai.match(mm[foff:foff+fsize]):
                            return True, 'Backdoor.Linux.Mirai.gen', 0, kernel.SUSPECT
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        vstring = []

                        foff = section['Offset']
                        ret = self.aho_mirai_a.search(mm[foff:foff + 0x200])

                        for n in ret[:len(self.mirai_a_strings)]:
                            vstring.append(n[1])

                        # print vstring
                        # print len(set(vstring)), len(self.mirai_a_strings)

                        if set(vstring) == set(self.mirai_a_strings):
                            return True, 'Backdoor.Linux.Mirai.a.gen', 0, kernel.SUSPECT

            # NSIS 같은 설치 프로그램의 경우 첨부 영역에 존재하는데..
            # 디컴파일하지 않고 오리지널 이미지 원본을 탐지하도록 했음..
            if 'ff_attach' in fileformat:
                foff = fileformat['ff_attach']['Attached_Pos']
                buf = mm[foff:]
                fmd5 = cryptolib.md5(buf)  # 첨부 위치부터 끝까지
                vname = kavutil.handle_pattern_md5.scan('emalware', len(buf), fmd5)
                if vname:
                    return True, vname, 0, kernel.INFECTED

        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Ejemplo n.º 8
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        try:
            mm = filehandle

            # 미리 분석된 파일 포맷중에 PE 포맷이 있는가?
            if 'ff_pe' in fileformat:
                ff = fileformat['ff_pe']

                # case 1 : 섹션 전체를 hash로 검사
                for idx, section in enumerate(ff['pe']['Sections']):
                    # if (section['Characteristics'] & 0x20000000) == 0x20000000:  # 실행 속성?
                    # print section['Name'], hex(section['SizeRawData'])
                    fsize = section['SizeRawData']
                    if fsize and kavutil.handle_pattern_md5.match_size(
                            'emalware', fsize):
                        foff = section['PointerRawData']
                        fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                        # print fsize, fmd5
                        vname = kavutil.handle_pattern_md5.scan(
                            'emalware', fsize, fmd5)
                        if vname:
                            vname = kavutil.normal_vname(vname)
                            return True, vname, 0, kernel.INFECTED

                # case 2. 마지막 섹션에 실행 파일 존재
                if len(ff['pe']['Sections']):
                    # 마지막 섹션
                    sec = ff['pe']['Sections'][-1]
                    off = sec['PointerRawData']
                    size = sec['SizeRawData']

                    # 실행 파일이 존재하는가?
                    exe_offs = [
                        m.start()
                        for m in re.finditer('MZ', mm[off:off + size])
                    ]

                    for exe_pos in exe_offs:
                        fsize = 0x1d5
                        if fsize and kavutil.handle_pattern_md5.match_size(
                                'emalware', fsize):
                            fmd5 = cryptolib.md5(mm[off + exe_pos:off +
                                                    exe_pos + fsize])
                            # print fsize, fmd5
                            vname = kavutil.handle_pattern_md5.scan(
                                'emalware', fsize, fmd5)
                            if vname:
                                # return True, vname, 0, kernel.INFECTED
                                idx = len(ff['pe']['Sections']) - 1
                                vname = kavutil.normal_vname(vname)
                                return True, vname, (0x80000000 +
                                                     idx), kernel.INFECTED

                # case 3. pdb를 이용해서 악성코드 검사
                if 'PDB_Name' in ff['pe']:
                    pdb_sigs = {
                        ':\\pz_git\\bin\\':
                        '<n>AdWare.Win32.Sokuxuan.gen',
                        ':\\CODE\\vitruvian\\':
                        '<n>AdWare.Win32.Vitruvian.gen',
                        '\\bin\\Release\\WebSparkle.':
                        '<n>AdWare.MSIL.BrowseFox.gen',
                        ':\\TeamCity\\BuildAgent1\\work\\':
                        '<n>WebToolbar.Win32.Agent.avi',
                    }

                    for pat in pdb_sigs.keys():
                        if ff['pe']['PDB_Name'].find(pat) != -1:
                            vname = kavutil.normal_vname(pdb_sigs[pat])
                            return True, vname, 0, kernel.INFECTED

                # case 4. Worm.Win32.Allaple.gen 검사
                ep_off = ff['pe']['EntryPointRaw']
                data = mm[ep_off:ep_off + 0x80]
                if self.p_allaple.search(data):
                    return True, 'Worm.Win32.Allaple.gen', 0, kernel.INFECTED

            # 미리 분석된 파일 포맷중에 ELF 포맷이 있는가?
            elif 'ff_elf' in fileformat:
                ff = fileformat['ff_elf']

                if len(ff['elf']['Sections']):
                    for section in ff['elf']['Sections']:
                        if (section['Type'] & 0x1) == 0x1 and (
                                section['Flag']
                                & 0x4) == 0x4:  # 프로그램 데이터이면서 실행 속성?
                            # print section['Name'], section['Size'], section['Offset']
                            fsize = section['Size']
                            if fsize and kavutil.handle_pattern_md5.match_size(
                                    'emalware', fsize):
                                foff = section['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan(
                                    'emalware', fsize, fmd5)
                                if vname:
                                    vname = kavutil.normal_vname(vname)
                                    return True, vname, 0, kernel.INFECTED
                elif len(ff['elf']['ProgramHeaders']):
                    for ph in ff['elf']['ProgramHeaders']:
                        if (ph['Type'] & 0x1) == 0x1 and (ph['Flag']
                                                          & 0x1) == 0x1:
                            fsize = ph['Size']
                            if fsize and kavutil.handle_pattern_md5.match_size(
                                    'emalware', fsize):
                                foff = ph['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan(
                                    'emalware', fsize, fmd5)
                                if vname:
                                    vname = kavutil.normal_vname(vname)
                                    return True, vname, 0, kernel.INFECTED

                # Mirai 변종 진단
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        fsize = section['Size']
                        foff = section['Offset']
                        if self.p_linux_mirai.match(mm[foff:foff+fsize]):
                            return True, 'Backdoor.Linux.Mirai.gen', 0, kernel.SUSPECT
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        vstring = []

                        foff = section['Offset']
                        ret = self.aho_mirai_a.search(mm[foff:foff + 0x200])

                        for n in ret[:len(self.mirai_a_strings)]:
                            vstring.append(n[1])

                        # print vstring
                        # print len(set(vstring)), len(self.mirai_a_strings)

                        if set(vstring) == set(self.mirai_a_strings):
                            return True, 'Backdoor.Linux.Mirai.a.gen', 0, kernel.SUSPECT

            # NSIS 같은 설치 프로그램의 경우 첨부 영역에 존재하는데..
            # 디컴파일하지 않고 오리지널 이미지 원본을 탐지하도록 했음..
            if 'ff_attach' in fileformat:
                foff = fileformat['ff_attach']['Attached_Pos']
                buf = mm[foff:]
                fsize = len(buf)
                if fsize and kavutil.handle_pattern_md5.match_size(
                        'emalware', fsize):
                    fmd5 = cryptolib.md5(buf)  # 첨부 위치부터 끝까지
                    vname = kavutil.handle_pattern_md5.scan(
                        'emalware', fsize, fmd5)
                    if vname:
                        vname = kavutil.normal_vname(vname)
                        return True, vname, 0, kernel.INFECTED

        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Ejemplo n.º 9
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        try:
            mm = filehandle

            # 미리 분석된 파일 포맷중에 PE 포맷이 있는가?
            if 'ff_pe' in fileformat:
                ff = fileformat['ff_pe']
                # print ff

                for section in ff['pe']['Sections']:
                    if (section['Characteristics']
                            & 0x20000000) == 0x20000000:  # 실행 속성?
                        # print section['Name'], hex(section['SizeRawData'])
                        fsize = section['SizeRawData']
                        if kavutil.handle_pattern_md5.match_size(
                                'emalware', fsize):
                            foff = section['PointerRawData']
                            fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                            # print fsize, fmd5
                            vname = kavutil.handle_pattern_md5.scan(
                                'emalware', fsize, fmd5)
                            if vname:
                                return True, vname, 0, kernel.INFECTED

            # 미리 분석된 파일 포맷중에 ELF 포맷이 있는가?
            elif 'ff_elf' in fileformat:
                ff = fileformat['ff_elf']

                if len(ff['elf']['Sections']):
                    for section in ff['elf']['Sections']:
                        if (section['Type'] & 0x1) == 0x1 and (
                                section['Flag']
                                & 0x4) == 0x4:  # 프로그램 데이터이면서 실행 속성?
                            # print section['Name'], section['Size'], section['Offset']
                            fsize = section['Size']
                            if kavutil.handle_pattern_md5.match_size(
                                    'emalware', fsize):
                                foff = section['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan(
                                    'emalware', fsize, fmd5)
                                if vname:
                                    return True, vname, 0, kernel.INFECTED
                elif len(ff['elf']['ProgramHeaders']):
                    for ph in ff['elf']['ProgramHeaders']:
                        if (ph['Type'] & 0x1) == 0x1 and (ph['Flag']
                                                          & 0x1) == 0x1:
                            fsize = ph['Size']
                            if kavutil.handle_pattern_md5.match_size(
                                    'emalware', fsize):
                                foff = ph['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan(
                                    'emalware', fsize, fmd5)
                                if vname:
                                    return True, vname, 0, kernel.INFECTED

                # Mirai 변종 진단
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        fsize = section['Size']
                        foff = section['Offset']
                        if self.p_linux_mirai.match(mm[foff:foff+fsize]):
                            return True, 'Backdoor.Linux.Mirai.gen', 0, kernel.SUSPECT
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        vstring = []

                        foff = section['Offset']
                        ret = self.aho_mirai_a.search(mm[foff:foff + 0x200])

                        for n in ret[:len(self.mirai_a_strings)]:
                            vstring.append(n[1])

                        # print vstring
                        # print len(set(vstring)), len(self.mirai_a_strings)

                        if set(vstring) == set(self.mirai_a_strings):
                            return True, 'Backdoor.Linux.Mirai.a.gen', 0, kernel.SUSPECT

            # NSIS 같은 설치 프로그램의 경우 첨부 영역에 존재하는데..
            # 디컴파일하지 않고 오리지널 이미지 원본을 탐지하도록 했음..
            if 'ff_attach' in fileformat:
                foff = fileformat['ff_attach']['Attached_Pos']
                buf = mm[foff:]
                fmd5 = cryptolib.md5(buf)  # 첨부 위치부터 끝까지
                vname = kavutil.handle_pattern_md5.scan(
                    'emalware', len(buf), fmd5)
                if vname:
                    return True, vname, 0, kernel.INFECTED

        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Ejemplo n.º 10
0
Archivo: pe.py Proyecto: jaepil/kicomav
    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
Ejemplo n.º 11
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        try:
            mm = filehandle

            # 미리 분석된 파일 포맷중에 PE 포맷이 있는가?
            if 'ff_pe' in fileformat:
                ff = fileformat['ff_pe']

                # case 1 : 섹션 전체를 hash로 검사
                for idx, section in enumerate(ff['pe']['Sections']):
                    # if (section['Characteristics'] & 0x20000000) == 0x20000000:  # 실행 속성?
                    # print section['Name'], hex(section['SizeRawData'])
                    fsize = section['SizeRawData']
                    if fsize and kavutil.handle_pattern_md5.match_size('emalware', fsize):
                        foff = section['PointerRawData']
                        fmd5 = cryptolib.md5(mm[foff:foff+fsize])
                        # print fsize, fmd5
                        vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                        if vname:
                            vname = kavutil.normal_vname(vname)
                            return True, vname, 0, kernel.INFECTED

                # case 2. 마지막 섹션에 실행 파일 존재
                if len(ff['pe']['Sections']):
                    # 마지막 섹션
                    sec = ff['pe']['Sections'][-1]
                    off = sec['PointerRawData']
                    size = sec['SizeRawData']

                    # 실행 파일이 존재하는가?
                    exe_offs = [m.start() for m in re.finditer('MZ', mm[off:off+size])]

                    for exe_pos in exe_offs:
                        fsize = 0x1d5
                        if fsize and kavutil.handle_pattern_md5.match_size('emalware', fsize):
                            fmd5 = cryptolib.md5(mm[off + exe_pos:off + exe_pos + fsize])
                            # print fsize, fmd5
                            vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                            if vname:
                                # return True, vname, 0, kernel.INFECTED
                                idx = len(ff['pe']['Sections']) - 1
                                vname = kavutil.normal_vname(vname)
                                return True, vname, (0x80000000 + idx), kernel.INFECTED

                # case 3. pdb를 이용해서 악성코드 검사
                if 'PDB_Name' in ff['pe']:
                    pdb_sigs = {
                        ':\\pz_git\\bin\\': '<n>AdWare.Win32.Sokuxuan.gen',
                        ':\\CODE\\vitruvian\\': '<n>AdWare.Win32.Vitruvian.gen',
                        '\\bin\\Release\\WebSparkle.': '<n>AdWare.MSIL.BrowseFox.gen',
                        ':\\TeamCity\\BuildAgent1\\work\\': '<n>WebToolbar.Win32.Agent.avi',
                    }

                    for pat in pdb_sigs.keys():
                        if ff['pe']['PDB_Name'].find(pat) != -1:
                            vname = kavutil.normal_vname(pdb_sigs[pat])
                            return True, vname, 0, kernel.INFECTED

                # case 4. Worm.Win32.Allaple.gen 검사
                ep_off = ff['pe']['EntryPointRaw']
                data = mm[ep_off:ep_off+0x80]
                if self.p_allaple.search(data):
                    return True, 'Worm.Win32.Allaple.gen', 0, kernel.INFECTED

            # 미리 분석된 파일 포맷중에 ELF 포맷이 있는가?
            elif 'ff_elf' in fileformat:
                ff = fileformat['ff_elf']

                if len(ff['elf']['Sections']):
                    for section in ff['elf']['Sections']:
                        if (section['Type'] & 0x1) == 0x1 and (section['Flag'] & 0x4) == 0x4:  # 프로그램 데이터이면서 실행 속성?
                            # print section['Name'], section['Size'], section['Offset']
                            fsize = section['Size']
                            if fsize and kavutil.handle_pattern_md5.match_size('emalware', fsize):
                                foff = section['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                                if vname:
                                    vname = kavutil.normal_vname(vname)
                                    return True, vname, 0, kernel.INFECTED
                elif len(ff['elf']['ProgramHeaders']):
                    for ph in ff['elf']['ProgramHeaders']:
                        if (ph['Type'] & 0x1) == 0x1 and (ph['Flag'] & 0x1) == 0x1:
                            fsize = ph['Size']
                            if fsize and kavutil.handle_pattern_md5.match_size('emalware', fsize):
                                foff = ph['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                                if vname:
                                    vname = kavutil.normal_vname(vname)
                                    return True, vname, 0, kernel.INFECTED

                # Mirai 변종 진단
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        fsize = section['Size']
                        foff = section['Offset']
                        if self.p_linux_mirai.match(mm[foff:foff+fsize]):
                            return True, 'Backdoor.Linux.Mirai.gen', 0, kernel.SUSPECT
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        vstring = []

                        foff = section['Offset']
                        ret = self.aho_mirai_a.search(mm[foff:foff + 0x200])

                        for n in ret[:len(self.mirai_a_strings)]:
                            vstring.append(n[1])

                        # print vstring
                        # print len(set(vstring)), len(self.mirai_a_strings)

                        if set(vstring) == set(self.mirai_a_strings):
                            return True, 'Backdoor.Linux.Mirai.a.gen', 0, kernel.SUSPECT

            # NSIS 같은 설치 프로그램의 경우 첨부 영역에 존재하는데..
            # 디컴파일하지 않고 오리지널 이미지 원본을 탐지하도록 했음..
            if 'ff_attach' in fileformat:
                foff = fileformat['ff_attach']['Attached_Pos']
                buf = mm[foff:]
                fsize = len(buf)
                if fsize and kavutil.handle_pattern_md5.match_size('emalware', fsize):
                    fmd5 = cryptolib.md5(buf)  # 첨부 위치부터 끝까지
                    vname = kavutil.handle_pattern_md5.scan('emalware', fsize, fmd5)
                    if vname:
                        vname = kavutil.normal_vname(vname)
                        return True, vname, 0, kernel.INFECTED

        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Ejemplo n.º 12
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        try:
            mm = filehandle

            # 미리 분석된 파일 포맷중에 PE 포맷이 있는가?
            if 'ff_pe' in fileformat:
                ff = fileformat['ff_pe']

                # case 1 : 섹션 전체를 hash로 검사
                for idx, section in enumerate(ff['pe']['Sections']):
                    # if (section['Characteristics'] & 0x20000000) == 0x20000000:  # 실행 속성?
                    # print section['Name'], hex(section['SizeRawData'])
                    fsize = section['SizeRawData']
                    if fsize and kavutil.handle_pattern_md5.match_size(
                            'emalware', fsize):
                        foff = section['PointerRawData']
                        fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                        # print fsize, fmd5
                        vname = kavutil.handle_pattern_md5.scan(
                            'emalware', fsize, fmd5)
                        if vname:
                            vname = kavutil.normal_vname(vname)
                            return True, vname, 0, kernel.INFECTED

                # case 2. 마지막 섹션에 실행 파일 존재
                if len(ff['pe']['Sections']):
                    # 마지막 섹션
                    sec = ff['pe']['Sections'][-1]
                    off = sec['PointerRawData']
                    size = sec['SizeRawData']

                    # 실행 파일이 존재하는가?
                    exe_offs = [
                        m.start()
                        for m in re.finditer('MZ', mm[off:off + size])
                    ]

                    for exe_pos in exe_offs:
                        fsize = 0x1d5
                        if fsize and kavutil.handle_pattern_md5.match_size(
                                'emalware', fsize):
                            fmd5 = cryptolib.md5(mm[off + exe_pos:off +
                                                    exe_pos + fsize])
                            # print fsize, fmd5
                            vname = kavutil.handle_pattern_md5.scan(
                                'emalware', fsize, fmd5)
                            if vname:
                                # return True, vname, 0, kernel.INFECTED
                                idx = len(ff['pe']['Sections']) - 1
                                vname = kavutil.normal_vname(vname)
                                return True, vname, (0x80000000 +
                                                     idx), kernel.INFECTED

            # 미리 분석된 파일 포맷중에 ELF 포맷이 있는가?
            elif 'ff_elf' in fileformat:
                ff = fileformat['ff_elf']

                if len(ff['elf']['Sections']):
                    for section in ff['elf']['Sections']:
                        if (section['Type'] & 0x1) == 0x1 and (
                                section['Flag']
                                & 0x4) == 0x4:  # 프로그램 데이터이면서 실행 속성?
                            # print section['Name'], section['Size'], section['Offset']
                            fsize = section['Size']
                            if fsize and kavutil.handle_pattern_md5.match_size(
                                    'emalware', fsize):
                                foff = section['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan(
                                    'emalware', fsize, fmd5)
                                if vname:
                                    vname = kavutil.normal_vname(vname)
                                    return True, vname, 0, kernel.INFECTED
                elif len(ff['elf']['ProgramHeaders']):
                    for ph in ff['elf']['ProgramHeaders']:
                        if (ph['Type'] & 0x1) == 0x1 and (ph['Flag']
                                                          & 0x1) == 0x1:
                            fsize = ph['Size']
                            if fsize and kavutil.handle_pattern_md5.match_size(
                                    'emalware', fsize):
                                foff = ph['Offset']
                                fmd5 = cryptolib.md5(mm[foff:foff + fsize])
                                # print fsize, fmd5
                                vname = kavutil.handle_pattern_md5.scan(
                                    'emalware', fsize, fmd5)
                                if vname:
                                    vname = kavutil.normal_vname(vname)
                                    return True, vname, 0, kernel.INFECTED

                # Mirai 변종 진단
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        fsize = section['Size']
                        foff = section['Offset']
                        if self.p_linux_mirai.match(mm[foff:foff+fsize]):
                            return True, 'Backdoor.Linux.Mirai.gen', 0, kernel.SUSPECT
                '''
                for section in ff['elf']['Sections']:
                    if section['Name'] == '.rodata':
                        vstring = []

                        foff = section['Offset']
                        ret = self.aho_mirai_a.search(mm[foff:foff + 0x200])

                        for n in ret[:len(self.mirai_a_strings)]:
                            vstring.append(n[1])

                        # print vstring
                        # print len(set(vstring)), len(self.mirai_a_strings)

                        if set(vstring) == set(self.mirai_a_strings):
                            return True, 'Backdoor.Linux.Mirai.a.gen', 0, kernel.SUSPECT

            # NSIS 같은 설치 프로그램의 경우 첨부 영역에 존재하는데..
            # 디컴파일하지 않고 오리지널 이미지 원본을 탐지하도록 했음..
            if 'ff_attach' in fileformat:
                foff = fileformat['ff_attach']['Attached_Pos']
                buf = mm[foff:]
                fsize = len(buf)
                if fsize and kavutil.handle_pattern_md5.match_size(
                        'emalware', fsize):
                    fmd5 = cryptolib.md5(buf)  # 첨부 위치부터 끝까지
                    vname = kavutil.handle_pattern_md5.scan(
                        'emalware', fsize, fmd5)
                    if vname:
                        vname = kavutil.normal_vname(vname)
                        return True, vname, 0, kernel.INFECTED

        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
    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
Ejemplo n.º 16
0
    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
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
Archivo: pe.py Proyecto: jaepil/kicomav
    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
Ejemplo n.º 19
0
    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