Exemple #1
0
    def arclist(self, filename, fileformat):
        file_scan_list = []  # 검사 대상 정보를 모두 가짐

        # 미리 분석된 파일 포맷중에 첨부 파일 포맷이 있는가?
        if 'ff_attach' in fileformat:
            pos = fileformat['ff_attach']['Attached_Pos']
            file_scan_list.append(['arc_attach:%d' % pos, 'Attached'])

            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'attach.kmd')
                kavutil.vprint(None, 'File name', os.path.split(filename)[-1])
                kavutil.vprint(None, 'Attach Point', '0x%08X' % pos)

                with open(filename, 'rb') as fp:
                    fp.seek(pos)
                    buf = fp.read(0x80)

                    print
                    kavutil.vprint('Attach Point (Raw)')
                    print
                    kavutil.HexDump().Buffer(buf, 0, 0x80)

                print

        return file_scan_list
Exemple #2
0
    def arclist(self, filename, fileformat):
        file_scan_list = []  # 검사 대상 정보를 모두 가짐

        # 미리 분석된 파일 포맷중에 첨부 파일 포맷이 있는가?
        if 'ff_attach' in fileformat:
            pos = fileformat['ff_attach']['Attached_Pos']
            file_scan_list.append(['arc_attach:%d' % pos, 'Attached'])

            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'attach.kmd')
                kavutil.vprint(None, 'File name', os.path.split(filename)[-1])
                kavutil.vprint(None, 'Attach Point', '0x%08X' % pos)

                with open(filename, 'rb') as fp:
                    fp.seek(pos)
                    buf = fp.read(0x80)

                    print
                    kavutil.vprint('Attach Point (Raw)')
                    print
                    kavutil.HexDump().Buffer(buf, 0, 0x80)

                print

        return file_scan_list
Exemple #3
0
    def arclist(self, filename, fileformat):
        fp = None
        mm = None
        file_scan_list = []  # 검사 대상 정보를 모두 가짐

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

            try:
                fp = open(filename, 'rb')
                mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)

                if mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2B:
                    arc_name = 'arc_upx!nrv2b'
                elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2B:
                    arc_name = 'arc_upx!nrv2b'
                elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2D:
                    arc_name = 'arc_upx!nrv2d'
                elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2D:
                    arc_name = 'arc_upx!nrv2d'
                elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2E:
                    arc_name = 'arc_upx!nrv2e'
                elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2E:
                    arc_name = 'arc_upx!nrv2e'
                else:
                    raise ValueError

                if self.verbose:
                    print '-' * 79
                    kavutil.vprint('Engine')
                    kavutil.vprint(None, 'Engine', 'upx.kmd')
                    kavutil.vprint(None, 'File name',
                                   os.path.split(filename)[-1])

                    print
                    kavutil.vprint(
                        'UPX : only support \'nrv2b\' compress method.')
                    kavutil.vprint(None, 'Compress Method',
                                   arc_name.split('!')[-1])
                    print

                name = 'UPX'
                file_scan_list.append([arc_name, name])
            except IOError:
                pass
            except ValueError:
                pass

            if mm:
                mm.close()

            if fp:
                fp.close()

        return file_scan_list
Exemple #4
0
    def arclist(self, filename, fileformat):
        fp = None
        mm = None
        file_scan_list = []  # 검사 대상 정보를 모두 가짐

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

            try:
                fp = open(filename, 'rb')
                mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)

                if mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2B:
                    arc_name = 'arc_upx!nrv2b'
                elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2B:
                    arc_name = 'arc_upx!nrv2b'
                elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2D:
                    arc_name = 'arc_upx!nrv2d'
                elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2D:
                    arc_name = 'arc_upx!nrv2d'
                elif mm[ep_foff + 0x69:ep_foff + 0x69 + 13] == UPX_NRV2E:
                    arc_name = 'arc_upx!nrv2e'
                elif mm[ep_foff + 0x71:ep_foff + 0x71 + 13] == UPX_NRV2E:
                    arc_name = 'arc_upx!nrv2e'
                else:
                    raise ValueError

                if self.verbose:
                    print '-' * 79
                    kavutil.vprint('Engine')
                    kavutil.vprint(None, 'Engine', 'upx.kmd')
                    kavutil.vprint(None, 'File name', os.path.split(filename)[-1])

                    print
                    kavutil.vprint('UPX : only support \'nrv2b\' compress method.')
                    kavutil.vprint(None, 'Compress Method', arc_name.split('!')[-1])
                    print

                name = 'UPX'
                file_scan_list.append([arc_name, name])
            except IOError:
                pass
            except ValueError:
                pass

            if mm:
                mm.close()

            if fp:
                fp.close()

        return file_scan_list
Exemple #5
0
    def format(self, filehandle, filename, filename_ex):
        ret = {}

        mm = filehandle

        if mm[:8] == '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1':  # OLE 헤더와 동일
            o = None
            try:
                o = ole.OleFile(filename)
                if '\x01Ole10Native' in o.listdir():
                    pics = o.openstream('\x01Ole10Native')
                    buf = pics.read()

                    if self.verbose:
                        print '-' * 79
                        kavutil.vprint('Engine')
                        kavutil.vprint(None, 'Engine', 'olenative.kmd')
                        kavutil.vprint(None, 'File name',
                                       os.path.split(filename)[-1])

                    fileformat = analysis_ole10native(buf, self.verbose)
                    if fileformat:
                        ret = {'ff_ole10native': fileformat}
            except ole.Error:
                pass

            if o:
                o.close()

        return ret
Exemple #6
0
    def format(self, filehandle, filename, filename_ex):
        ret = {}

        mm = filehandle

        if mm[:8] == '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1':  # OLE 헤더와 동일
            o = None
            try:
                o = ole.OleFile(filename)
                if '\x01Ole10Native' in o.listdir():
                    pics = o.openstream('\x01Ole10Native')
                    buf = pics.read()

                    if self.verbose:
                        print '-' * 79
                        kavutil.vprint('Engine')
                        kavutil.vprint(None, 'Engine', 'olenative.kmd')
                        kavutil.vprint(None, 'File name', os.path.split(filename)[-1])

                    fileformat = analysis_ole10native(buf, self.verbose)
                    if fileformat:
                        ret = {'ff_ole10native': fileformat}
            except ole.Error:
                pass

            if o:
                o.close()

        return ret
Exemple #7
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
Exemple #8
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
Exemple #9
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        zfile = None
        mm = filehandle

        try:
            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'hwpx.kmd')
                kavutil.vprint(None, 'File name', os.path.split(filename)[-1])
                print

            if 'ff_hwpx' in fileformat:
                zfile = zipfile.ZipFile(filename)  # zip 파일 열기

                for name in zfile.namelist():
                    if name.lower().find('mimetype') != -1:
                        data = zfile.read(name)

                        if self.verbose:
                            kavutil.vprint('mimetype')
                            kavutil.vprint(None, 'body', '%s' % data)
                            print

                        if data != 'application/hwp+zip':
                            if zfile:
                                zfile.close()

                            return True, 'Exploit.HWPX.Generic', 0, kernel.INFECTED

                    elif name.lower().find('preview/prvtext.txt') != -1:
                        pass  # PrevText.txt는 검사하지 않음

                    elif name.lower().find(
                            'bindata') == -1:  # Bindata 이외의 파일들은 주로 XML
                        try:
                            data = zfile.read(name)
                            dict_data = xml_parse(data)

                            if self.verbose:
                                kavutil.vprint(name)
                                print json.dumps(dict_data, indent=2)
                                print
                        except:
                            if zfile:
                                zfile.close()

                            return True, 'Exploit.HWPX.Generic', 0, kernel.INFECTED

        except IOError:
            pass

        if zfile:
            zfile.close()

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

        try:
            # 미리 분석된 파일 포맷중에 OLE 포맷이 있는가?
            if 'ff_ole' in fileformat:
                o = ole.OleFile(filename)

                # 취약점 공격인가?
                if len(o.exploit):
                    if o:
                        o.close()

                    return True, o.exploit[0], MALWARE_ID_OLE, kernel.INFECTED

                ole_lists = o.listdir()

                for pps_name in ole_lists:
                    if pps_name.lower().find(
                            '/vba/dir') != -1:  # 오피스 97 매크로 존재 여부
                        pics = o.openstream(pps_name)
                        data = pics.read()
                        ret, decom_data = decompress(data)  # dir 스트림 압축 해제
                        if ret:
                            vba_modules = analysis_dir_stream(decom_data)

                            t = pps_name.split('/')

                            for vba in vba_modules:
                                t[-1] = vba[0]
                                t_pps_name = '/'.join(t)

                                t_pics = o.openstream(
                                    t_pps_name)  # 매크로가 존재하는 스트림 열기
                                t_data = t_pics.read()

                                if len(t_data) == 0:  # 데이터가 없으면 다음 vba 체크
                                    continue

                                t_ret, buf = decompress(
                                    t_data[vba[1]:])  # 매크로 소스코드 획득 완료
                                buf = buf.replace('\r\n', '\n')

                                if t_ret:
                                    if self.verbose:
                                        # 매크로 소스코드 출력
                                        kavutil.vprint('Macro Source')
                                        kavutil.vprint(None, 'PPS',
                                                       '%s' % t_pps_name)
                                        print buf

                                    buf = self.p_vba_cmt.sub('', buf)  # 주석문 제거
                                    buf = buf.lower()  # 영어 소문자로 통일

                                    key_words = self.p_vba_word.findall(buf)

                                    vba_keyword_crc32 = set()
                                    for i in range(len(key_words) - 1):
                                        word = key_words[i] + key_words[i + 1]
                                        c = zlib.crc32(word) & 0xffffffffL
                                        vba_keyword_crc32.add(c)

                                    # 테스트
                                    if self.verbose:
                                        max_len = len(key_words[0])

                                        t_word = []
                                        for i in range(len(key_words) - 1):
                                            word = key_words[i] + key_words[i +
                                                                            1]
                                            c = zlib.crc32(word) & 0xffffffffL
                                            t_word.append([
                                                c, key_words[i],
                                                key_words[i + 1]
                                            ])

                                            if len(key_words[i + 1]) > max_len:
                                                max_len = len(key_words[i + 1])

                                        t_l = '+-' + ('-' * 8) + '-+-' + (
                                            '-' * max_len) + '-+-' + (
                                                '-' * max_len) + '-+'
                                        print t_l
                                        msg = '| %%-8s | %%-%ds | %%-%ds |' % (
                                            max_len, max_len)
                                        print msg % ('CRC32', 'Keyword #1',
                                                     'Keyword #2')
                                        print t_l

                                        msg = '| %%08X | %%-%ds | %%-%ds |' % (
                                            max_len, max_len)
                                        for n in t_word:
                                            print msg % (n[0], n[1], n[2])

                                        print t_l

                                    # Heuristic 검사
                                    for macro_crc in self.word97_macro_crcs:
                                        if macro_crc.issubset(
                                                vba_keyword_crc32):
                                            if o:
                                                o.close()
                                            return True, 'Virus.MSWord.Generic', MALWARE_ID_WORD97, kernel.SUSPECT

        except IOError:
            pass
        except ole.Error:
            pass

        if o:
            o.close()

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.INFECTED
Exemple #12
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
Exemple #13
0
    def parse(self):
        fileformat = {}
        mm = self.mm

        try:
            # EP
            e_entry = get_uint64(mm, 0x18, self.endian)

            # 섹션 헤더 정보
            e_phoff = get_uint64(mm, 0x20, self.endian)
            e_shoff = get_uint64(mm, 0x28, self.endian)
            e_phnum = get_uint16(mm, 0x38, self.endian)
            e_shnum = get_uint16(mm, 0x3C, self.endian)
            e_shstrndx = get_uint16(mm, 0x3E, self.endian)

            # 섹션 이름이 저장된 테이블
            name_table_off = get_uint64(mm,
                                        e_shoff + (0x40 * e_shstrndx) + 0x18,
                                        self.endian)
            name_table_size = get_uint64(mm,
                                         e_shoff + (0x40 * e_shstrndx) + 0x20,
                                         self.endian)
            name_table = mm[name_table_off:name_table_off + name_table_size]
            # print name_table.split('\x00')
            # print hex(name_table_off), hex(name_table_size)

            # 섹션 정보 구하기
            for i in range(e_shnum):
                section = {}

                name_off = get_uint32(mm, e_shoff + (0x40 * i), self.endian)
                section['Name'] = name_table[name_off:].split('\x00', 1)[0]
                section['Type'] = get_uint32(mm, e_shoff + (0x40 * i) + 4,
                                             self.endian)
                section['Flag'] = get_uint64(mm, e_shoff + (0x40 * i) + 8,
                                             self.endian)
                section['RVA'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x10,
                                            self.endian)
                section['Offset'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x18,
                                               self.endian)
                section['Size'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x20,
                                             self.endian)

                self.sections.append(section)

            fileformat['Sections'] = self.sections
            fileformat['EntryPoint'] = e_entry

            # EntryPoint의 파일에서의 위치 구하기
            ep_raw, sec_idx = self.rva_to_off(e_entry)
            fileformat['EntryPointRaw'] = ep_raw  # EP의 Raw 위치
            fileformat['EntryPoint_in_Section'] = sec_idx  # EP가 포함된 섹션

            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'elf.kmd')
                kavutil.vprint(None, 'File name',
                               os.path.split(self.filename)[-1])

                print
                kavutil.vprint('ELF64')

                kavutil.vprint(None, 'Entry Point', '0x%016X' % e_entry)
                kavutil.vprint(None, 'Entry Point (Raw)', '0x%016X' % ep_raw)
                kavutil.vprint(None, 'Program Header Off', '0x%016X' % e_phoff)
                kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum)
                kavutil.vprint(None, 'Section Header Off', '0x%016X' % e_shoff)
                kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum)

                if e_shnum:
                    print
                    kavutil.vprint('Section Header')
                    print '    %-15s %-8s %-16s %-16s %-16s %-16s' % (
                        'Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size')
                    print '    ' + ('-' * (76 + 16))

                    for p in self.sections:
                        print '    %-15s %08X %016X %016X %016X %016X' % (
                            p['Name'], p['Type'], p['Flag'], p['RVA'],
                            p['Offset'], p['Size'])

                print
                kavutil.vprint('Entry Point (Raw)')
                print
                kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80)
                print
        except (ValueError, struct.error) as e:
            pass

        return fileformat
Exemple #14
0
    def unarc(self, arc_engine_id, arc_name, fname_in_arc):
        fp = None
        mm = None
        data = None

        if arc_engine_id.find('arc_upx') != -1:
            filename = fname_in_arc

            try:
                # UPX로 압축된 파일 열기
                fp = open(arc_name, 'rb')
                mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)

                p = pe.PE(mm, False, arc_name)
                pe_format = p.parse()  # PE 파일 분석
                if pe_format is None:
                    return ValueError

                pe_img = pe_format['ImageBase']
                pe_ep = pe_format['EntryPoint']
                sections = pe_format['Sections']
                ep_raw = pe_format['EntryPointRaw']  # EP의 Raw 위치
                ep_nsec = pe_format['EntryPoint_in_Section']  # EP는 몇번째 섹션에 있는가?

                foff = 0
                ssize = 0
                dsize = 0

                for section in sections:
                    ssize = section['VirtualSize']
                    rva = section['RVA']
                    if rva <= pe_ep < rva+ssize:
                        foff = section['PointerRawData']
                        i = sections.index(section)
                        if i != 0:
                            upx0 = sections[i-1]['RVA']
                            upx1 = sections[i]['RVA']
                            dsize = sections[i-1]['VirtualSize'] + ssize
                        break

                if ssize == 0 or dsize == 0:
                    raise ValueError

                upx_data_rva = kavutil.get_uint32(mm, ep_raw+2)
                sec_rva = sections[ep_nsec]['RVA']

                skew = upx_data_rva - sec_rva - pe_img

                if mm[ep_raw+1] != '\xBE' or skew <= 0 or skew > 0xFFF:
                    skew = 0
                elif skew > ssize:
                    skew = 0
                else:
                    raise ValueError

                data = mm[foff+skew:foff+ssize-skew]

                unpack_data = ''  # UPX 해제된 이미지

                if arc_engine_id[8:] == 'nrv2b':  # UPX 알고리즘 중 nrv2b 압축인가?
                    try:
                        ret_val, unpack_data = upx_inflate2b(data, dsize, pe_ep, upx0, upx1, pe_img)
                    except OverflowError:
                        raise ValueError

                if self.verbose:
                    kavutil.vprint('Decompress')
                    kavutil.vprint(None, 'Compressed Size', '%d' % len(data))
                    if unpack_data == '':  # 압축 해제 실패
                        kavutil.vprint(None, 'Decompress Size', 'Error')
                    else:
                        kavutil.vprint(None, 'Decompress Size', '%d' % len(unpack_data))
                    print

                if unpack_data == '':  # 압축 해제 실패
                    raise ValueError

                data = unpack_data
            except IOError:
                pass
            except ValueError:
                pass

            if mm:
                mm.close()

            if fp:
                fp.close()

            return data

        return None
Exemple #15
0
    def parse(self):
        fileformat = {}
        mm = self.mm

        try:
            # EP
            e_entry = get_uint64(mm, 0x18, self.endian)

            # 섹션 헤더 정보
            e_phoff = get_uint64(mm, 0x20, self.endian)
            e_shoff = get_uint64(mm, 0x28, self.endian)
            e_phnum = get_uint16(mm, 0x38, self.endian)
            e_shnum = get_uint16(mm, 0x3C, self.endian)
            e_shstrndx = get_uint16(mm, 0x3E, self.endian)

            # 섹션 이름이 저장된 테이블
            name_table_off = get_uint64(mm, e_shoff + (0x40 * e_shstrndx) + 0x18, self.endian)
            name_table_size = get_uint64(mm, e_shoff + (0x40 * e_shstrndx) + 0x20, self.endian)
            name_table = mm[name_table_off:name_table_off+name_table_size]
            # print name_table.split('\x00')
            # print hex(name_table_off), hex(name_table_size)

            # 섹션 정보 구하기
            for i in range(e_shnum):
                section = {}

                name_off = get_uint32(mm, e_shoff + (0x40 * i), self.endian)
                section['Name'] = name_table[name_off:].split('\x00', 1)[0]
                section['Type'] = get_uint32(mm, e_shoff + (0x40 * i) + 4, self.endian)
                section['Flag'] = get_uint64(mm, e_shoff + (0x40 * i) + 8, self.endian)
                section['RVA'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x10, self.endian)
                section['Offset'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x18, self.endian)
                section['Size'] = get_uint64(mm, e_shoff + (0x40 * i) + 0x20, self.endian)

                self.sections.append(section)

            fileformat['Sections'] = self.sections
            fileformat['EntryPoint'] = e_entry

            # EntryPoint의 파일에서의 위치 구하기
            ep_raw, sec_idx = self.rva_to_off(e_entry)
            fileformat['EntryPointRaw'] = ep_raw  # EP의 Raw 위치
            fileformat['EntryPoint_in_Section'] = sec_idx  # EP가 포함된 섹션

            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'elf.kmd')
                kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1])

                print
                kavutil.vprint('ELF64')

                kavutil.vprint(None, 'Entry Point', '0x%016X' % e_entry)
                kavutil.vprint(None, 'Entry Point (Raw)', '0x%016X' % ep_raw)
                kavutil.vprint(None, 'Program Header Off', '0x%016X' % e_phoff)
                kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum)
                kavutil.vprint(None, 'Section Header Off', '0x%016X' % e_shoff)
                kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum)

                if e_shnum:
                    print
                    kavutil.vprint('Section Header')
                    print '    %-15s %-8s %-16s %-16s %-16s %-16s' % ('Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size')
                    print '    ' + ('-' * (76 + 16))

                    for p in self.sections:
                        print '    %-15s %08X %016X %016X %016X %016X' % (p['Name'], p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size'])

                print
                kavutil.vprint('Entry Point (Raw)')
                print
                kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80)
                print
        except (ValueError, struct.error) as e:
            pass

        return fileformat
Exemple #16
0
    def unarc(self, arc_engine_id, arc_name, fname_in_arc):
        fp = None
        mm = None
        data = None

        if arc_engine_id.find('arc_upx') != -1:
            filename = fname_in_arc

            try:
                # UPX로 압축된 파일 열기
                fp = open(arc_name, 'rb')
                mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)

                p = pe.PE(mm, False, arc_name)
                pe_format = p.parse()  # PE 파일 분석
                if pe_format is None:
                    return ValueError

                pe_img = pe_format['ImageBase']
                pe_ep = pe_format['EntryPoint']
                sections = pe_format['Sections']
                ep_raw = pe_format['EntryPointRaw']  # EP의 Raw 위치
                ep_nsec = pe_format[
                    'EntryPoint_in_Section']  # EP는 몇번째 섹션에 있는가?

                foff = 0
                ssize = 0
                dsize = 0

                for section in sections:
                    ssize = section['VirtualSize']
                    rva = section['RVA']
                    if rva <= pe_ep < rva + ssize:
                        foff = section['PointerRawData']
                        i = sections.index(section)
                        if i != 0:
                            upx0 = sections[i - 1]['RVA']
                            upx1 = sections[i]['RVA']
                            dsize = sections[i - 1]['VirtualSize'] + ssize
                        break

                if ssize == 0 or dsize == 0:
                    raise ValueError

                upx_data_rva = kavutil.get_uint32(mm, ep_raw + 2)
                sec_rva = sections[ep_nsec]['RVA']

                skew = upx_data_rva - sec_rva - pe_img

                if mm[ep_raw + 1] != '\xBE' or skew <= 0 or skew > 0xFFF:
                    skew = 0
                elif skew > ssize:
                    skew = 0
                else:
                    raise ValueError

                data = mm[foff + skew:foff + ssize - skew]

                unpack_data = ''  # UPX 해제된 이미지

                if arc_engine_id[8:] == 'nrv2b':  # UPX 알고리즘 중 nrv2b 압축인가?
                    try:
                        ret_val, unpack_data = upx_inflate2b(
                            data, dsize, pe_ep, upx0, upx1, pe_img)
                    except OverflowError:
                        raise ValueError

                if unpack_data == '':  # 압축 해제 실패
                    raise ValueError

                if self.verbose:
                    kavutil.vprint('Decompress')
                    kavutil.vprint(None, 'Compressed Size', '%d' % len(data))
                    kavutil.vprint(None, 'Decompress Size',
                                   '%d' % len(unpack_data))
                    print

                data = unpack_data
            except IOError:
                pass
            except ValueError:
                pass

            if mm:
                mm.close()

            if fp:
                fp.close()

            return data

        return None
Exemple #17
0
    def parse(self):
        fileformat = {}
        mm = self.mm

        try:
            # EP
            e_entry = get_uint32(mm, 0x18, self.endian)

            # ELF 헤더 정보
            e_ident = ord(mm[7])
            e_machine = get_uint16(mm, 0x12, self.endian)

            e_phoff = get_uint32(mm, 0x1C, self.endian)
            e_shoff = get_uint32(mm, 0x20, self.endian)
            e_phnum = get_uint16(mm, 0x2C, self.endian)
            e_shnum = get_uint16(mm, 0x30, self.endian)
            e_shstrndx = get_uint16(mm, 0x32, self.endian)

            # 프로그램 헤더 정보 구하기
            for i in range(e_phnum):
                program_header = {}

                program_header['Type'] = get_uint32(mm,
                                                    e_phoff + (0x20 * i) + 0,
                                                    self.endian)
                program_header['Flag'] = get_uint32(
                    mm, e_phoff + (0x20 * i) + 0x18, self.endian)
                program_header['RVA'] = get_uint32(mm,
                                                   e_phoff + (0x20 * i) + 0x8,
                                                   self.endian)
                program_header['Offset'] = get_uint32(
                    mm, e_phoff + (0x20 * i) + 0x4, self.endian)
                program_header['Size'] = get_uint32(
                    mm, e_phoff + (0x20 * i) + 0x10, self.endian)

                self.program_headers.append(program_header)

            fileformat['ProgramHeaders'] = self.program_headers

            # 섹션 이름이 저장된 테이블
            name_table_off = get_uint32(mm,
                                        e_shoff + (0x28 * e_shstrndx) + 0x10,
                                        self.endian)
            name_table_size = get_uint32(mm,
                                         e_shoff + (0x28 * e_shstrndx) + 0x14,
                                         self.endian)
            name_table = mm[name_table_off:name_table_off + name_table_size]
            # print name_table.split('\x00')
            # print hex(name_table_off), hex(name_table_size)

            # 섹션 정보 구하기
            for i in range(e_shnum):
                section = {}

                name_off = get_uint32(mm, e_shoff + (0x28 * i), self.endian)
                section['Name'] = name_table[name_off:].split('\x00', 1)[0]
                section['Type'] = get_uint32(mm, e_shoff + (0x28 * i) + 4,
                                             self.endian)
                section['Flag'] = get_uint32(mm, e_shoff + (0x28 * i) + 8,
                                             self.endian)
                section['RVA'] = get_uint32(mm, e_shoff + (0x28 * i) + 0xC,
                                            self.endian)
                section['Offset'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x10,
                                               self.endian)
                section['Size'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x14,
                                             self.endian)

                self.sections.append(section)

            fileformat['Sections'] = self.sections
            fileformat['EntryPoint'] = e_entry

            # EntryPoint의 파일에서의 위치 구하기
            ep_raw, sec_idx = self.rva_to_off(e_entry)
            fileformat['EntryPointRaw'] = ep_raw  # EP의 Raw 위치
            fileformat['EntryPoint_in_Section'] = sec_idx  # EP가 포함된 섹션

            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'elf.kmd')
                kavutil.vprint(None, 'File name',
                               os.path.split(self.filename)[-1])

                print
                kavutil.vprint('ELF32')

                if e_ident in self.ident:
                    msg1 = self.ident[e_ident]
                else:
                    msg1 = 'Unknown'

                if e_machine in self.machine:
                    msg2 = self.machine[e_machine]
                else:
                    msg2 = 'Unknown'

                kavutil.vprint(None, 'Identifies', '%s (%s)' % (msg1, msg2))

                kavutil.vprint(None, 'Entry Point', '0x%08X' % e_entry)
                kavutil.vprint(None, 'Entry Point (Raw)', '0x%08X' % ep_raw)
                kavutil.vprint(None, 'Program Header Off', '0x%08X' % e_phoff)
                kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum)
                kavutil.vprint(None, 'Section Header Off', '0x%08X' % e_shoff)
                kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum)

                if e_phnum:
                    print
                    kavutil.vprint('Program Header')
                    print '    %-8s %-8s %-8s %-8s %-8s' % (
                        'Type', 'Flag', 'RVA', 'Offset', 'Size')
                    print '    ' + ('-' * 44)

                    for p in self.program_headers:
                        print '    %08X %08X %08X %08X %08X' % (
                            p['Type'], p['Flag'], p['RVA'], p['Offset'],
                            p['Size'])

                if e_shnum:
                    print
                    kavutil.vprint('Section Header')
                    print '    %-15s %-8s %-8s %-8s %-8s %-8s' % (
                        'Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size')
                    print '    ' + ('-' * (44 + 16))

                    for p in self.sections:
                        print '    %-15s %08X %08X %08X %08X %08X' % (
                            p['Name'], p['Type'], p['Flag'], p['RVA'],
                            p['Offset'], p['Size'])

                print
                kavutil.vprint('Entry Point (Raw)')
                print
                kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80)
                print
        except (ValueError, struct.error) as e:
            pass

        return fileformat
Exemple #18
0
def analysis_ole10native(mm, verbose=False):
    fileformat = {}

    try:
        size = kavutil.get_uint32(mm, 0)

        if mm[4:6] == '\x02\x00':
            if len(mm) == size + 4:
                fileformat['size'] = len(mm)  # 포맷 주요 정보 저장

                label = mm[6:6 + MAX_PATH].split('\x00', 1)[0]
                fileformat['label'] = label

                off = 6 + len(label) + 1
                fname = mm[off:off + MAX_PATH].split('\x00', 1)[0]

                off += len(fname) + 1
                off += 2  # flag

                unknown_size = ord(mm[off])
                off += 1 + unknown_size + 2

                command = mm[off:off + MAX_PATH].split('\x00', 1)[0]
                off += len(command) + 1

                data_size = kavutil.get_uint32(mm, off)

                fileformat['data_off'] = off + 4
                fileformat['data_size'] = data_size

                if len(mm) < off + data_size:  # 오류
                    raise ValueError

                if verbose:
                    print
                    kavutil.vprint('Ole10Native Stream')
                    kavutil.vprint(None, 'Size', '0x%08X' % size)
                    kavutil.vprint(None, 'Label', label)
                    kavutil.vprint(None, 'File Name', fname)
                    kavutil.vprint(None, 'Command Line', command)
                    kavutil.vprint(None, 'Data Offset', '0x%08X' % (off + 4))
                    kavutil.vprint(None, 'Data Size', '0x%08X' % data_size)

                    print
                    kavutil.vprint('Data Dump')
                    print
                    kavutil.HexDump().Buffer(mm[:], off + 4, 0x80)
                    print

                return fileformat
    except ValueError:
        pass
    except struct.error:
        pass

    return None
Exemple #19
0
    def parse(self):
        fileformat = {}
        mm = self.mm

        try:
            # EP
            e_entry = get_uint32(mm, 0x18, self.endian)

            # ELF 헤더 정보
            e_ident = ord(mm[7])
            e_machine = get_uint16(mm, 0x12, self.endian)

            e_phoff = get_uint32(mm, 0x1C, self.endian)
            e_shoff = get_uint32(mm, 0x20, self.endian)
            e_phnum = get_uint16(mm, 0x2C, self.endian)
            e_shnum = get_uint16(mm, 0x30, self.endian)
            e_shstrndx = get_uint16(mm, 0x32, self.endian)

            # 프로그램 헤더 정보 구하기
            for i in range(e_phnum):
                program_header = {}

                program_header['Type'] = get_uint32(mm, e_phoff + (0x20 * i) + 0, self.endian)
                program_header['Flag'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x18, self.endian)
                program_header['RVA'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x8, self.endian)
                program_header['Offset'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x4, self.endian)
                program_header['Size'] = get_uint32(mm, e_phoff + (0x20 * i) + 0x10, self.endian)

                self.program_headers.append(program_header)

            fileformat['ProgramHeaders'] = self.program_headers

            # 섹션 이름이 저장된 테이블
            name_table_off = get_uint32(mm, e_shoff + (0x28 * e_shstrndx) + 0x10, self.endian)
            name_table_size = get_uint32(mm, e_shoff + (0x28 * e_shstrndx) + 0x14, self.endian)
            name_table = mm[name_table_off:name_table_off+name_table_size]
            # print name_table.split('\x00')
            # print hex(name_table_off), hex(name_table_size)

            # 섹션 정보 구하기
            for i in range(e_shnum):
                section = {}

                name_off = get_uint32(mm, e_shoff + (0x28 * i), self.endian)
                section['Name'] = name_table[name_off:].split('\x00', 1)[0]
                section['Type'] = get_uint32(mm, e_shoff + (0x28 * i) + 4, self.endian)
                section['Flag'] = get_uint32(mm, e_shoff + (0x28 * i) + 8, self.endian)
                section['RVA'] = get_uint32(mm, e_shoff + (0x28 * i) + 0xC, self.endian)
                section['Offset'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x10, self.endian)
                section['Size'] = get_uint32(mm, e_shoff + (0x28 * i) + 0x14, self.endian)

                self.sections.append(section)

            fileformat['Sections'] = self.sections
            fileformat['EntryPoint'] = e_entry

            # EntryPoint의 파일에서의 위치 구하기
            ep_raw, sec_idx = self.rva_to_off(e_entry)
            fileformat['EntryPointRaw'] = ep_raw  # EP의 Raw 위치
            fileformat['EntryPoint_in_Section'] = sec_idx  # EP가 포함된 섹션

            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'elf.kmd')
                kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1])

                print
                kavutil.vprint('ELF32')

                if e_ident in self.ident:
                    msg1 = self.ident[e_ident]
                else:
                    msg1 = 'Unknown'

                if e_machine in self.machine:
                    msg2 = self.machine[e_machine]
                else:
                    msg2 = 'Unknown'

                kavutil.vprint(None, 'Identifies', '%s (%s)' % (msg1, msg2))

                kavutil.vprint(None, 'Entry Point', '0x%08X' % e_entry)
                kavutil.vprint(None, 'Entry Point (Raw)', '0x%08X' % ep_raw)
                kavutil.vprint(None, 'Program Header Off', '0x%08X' % e_phoff)
                kavutil.vprint(None, 'Program Header Num', '0x%04X' % e_phnum)
                kavutil.vprint(None, 'Section Header Off', '0x%08X' % e_shoff)
                kavutil.vprint(None, 'Section Header Num', '0x%04X' % e_shnum)

                if e_phnum:
                    print
                    kavutil.vprint('Program Header')
                    print '    %-8s %-8s %-8s %-8s %-8s' % ('Type', 'Flag', 'RVA', 'Offset', 'Size')
                    print '    ' + ('-' * 44)

                    for p in self.program_headers:
                        print '    %08X %08X %08X %08X %08X' % (p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size'])

                if e_shnum:
                    print
                    kavutil.vprint('Section Header')
                    print '    %-15s %-8s %-8s %-8s %-8s %-8s' % ('Name', 'Type', 'Flag', 'RVA', 'Offset', 'Size')
                    print '    ' + ('-' * (44 + 16))

                    for p in self.sections:
                        print '    %-15s %08X %08X %08X %08X %08X' % (p['Name'], p['Type'], p['Flag'], p['RVA'], p['Offset'], p['Size'])

                print
                kavutil.vprint('Entry Point (Raw)')
                print
                kavutil.HexDump().Buffer(mm[:], ep_raw, 0x80)
                print
        except (ValueError, struct.error) as e:
            pass

        return fileformat
Exemple #20
0
    def parse(self):
        self.fp = open(self.filename, 'rb')
        fsize = os.path.getsize(self.filename)
        if fsize == 0:
            return False

        self.mm = mmap.mmap(self.fp.fileno(), 0, access=mmap.ACCESS_READ)

        flag = kavutil.get_uint32(self.mm, 0)
        head_size = kavutil.get_uint32(self.mm, 0x14)
        comp_size = kavutil.get_uint32(self.mm, 0x18)

        data, case_type = self.get_data()  # NSIS의 모든 데이터를 가진다.
        self.body_data = data
        self.case_type = case_type

        if self.verbose:
            print '-' * 79
            kavutil.vprint('Engine')
            kavutil.vprint(None, 'Engine', 'nsis.kmd')
            kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1])

            print
            kavutil.vprint('NSIS')
            kavutil.vprint(None, 'Flag', '%d' % flag)
            kavutil.vprint(None, 'Uncompress Case', '%d' % case_type)

            print
            kavutil.vprint('Uncompress Data')
            print
            kavutil.HexDump().Buffer(data, 0, 0x80)

            s = self.nsis_header.namelist_ex()
            if len(s):
                print
                kavutil.vprint('File Extract')
                print
                for t in s:
                    (foff, fname, ftime, extract_type) = t
                    print "%08X | %-45s | %s" % (foff, fname, ftime if ftime != '' else 'N/A')

        return True
Exemple #21
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
Exemple #22
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
Exemple #23
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        mm = filehandle
        o = None

        try:
            # 미리 분석된 파일 포맷중에 OLE 포맷이 있는가?
            if 'ff_ole' in fileformat:
                o = ole.OleFile(filename)
                ole_lists = o.listdir()

                for pps_name in ole_lists:
                    if pps_name.lower().find('/vba/dir') != -1:  # 오피스 97 매크로 존재 여부
                        pics = o.openstream(pps_name)
                        data = pics.read()
                        ret, decom_data = decompress(data)  # dir 스트림 압축 해제
                        if ret:
                            vba_modules = analysis_dir_stream(decom_data)

                            t = pps_name.split('/')

                            for vba in vba_modules:
                                t[-1] = vba[0]
                                t_pps_name = '/'.join(t)

                                t_pics = o.openstream(t_pps_name)  # 매크로가 존재하는 스트림 열기
                                t_data = t_pics.read()
                                t_ret, buf = decompress(t_data[vba[1]:])  # 매크로 소스코드 획득 완료
                                buf = buf.replace('\r\n', '\n')

                                if t_ret:
                                    if self.verbose:
                                        # 매크로 소스코드 출력
                                        kavutil.vprint('Macro Source')
                                        kavutil.vprint(None, 'PPS', '%s' % t_pps_name)
                                        print buf

                                    buf = self.p_vba_cmt.sub('', buf)  # 주석문 제거
                                    buf = buf.lower()  # 영어 소문자로 통일

                                    key_words = self.p_vba_word.findall(buf)

                                    vba_keyword_crc32 = set()
                                    for i in range(len(key_words)-1):
                                        word = key_words[i] + key_words[i+1]
                                        c = zlib.crc32(word) & 0xffffffffL
                                        vba_keyword_crc32.add(c)

                                    # 테스트
                                    if self.verbose:
                                        max_len = len(key_words[0])

                                        t_word = []
                                        for i in range(len(key_words)-1):
                                            word = key_words[i] + key_words[i+1]
                                            c = zlib.crc32(word) & 0xffffffffL
                                            t_word.append([c, key_words[i], key_words[i+1]])

                                            if len(key_words[i+1]) > max_len:
                                                max_len = len(key_words[i+1])

                                        t_l = '+-' + ('-' * 8) + '-+-' + ('-' * max_len) + '-+-' + ('-' * max_len) + '-+'
                                        print t_l
                                        msg = '| %%-8s | %%-%ds | %%-%ds |' % (max_len, max_len)
                                        print msg % ('CRC32', 'Keyword #1', 'Keyword #2')
                                        print t_l

                                        msg = '| %%08X | %%-%ds | %%-%ds |' % (max_len, max_len)
                                        for n in t_word:
                                            print msg % (n[0], n[1], n[2])

                                        print t_l

                                    # Heuristic 검사
                                    for macro_crc in self.word97_macro_crcs:
                                        if macro_crc.issubset(vba_keyword_crc32):
                                            return True, 'Virus.MSWord.Generic', MALWARE_ID_WORD97, kernel.SUSPECT

        except IOError:
            pass
        except ole.Error:
            pass

        if o:
            o.close()

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.INFECTED
Exemple #24
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

            # 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
Exemple #25
0
    def scan(self, filehandle, filename, fileformat, filename_ex):  # 악성코드 검사
        zfile = None
        mm = filehandle

        try:
            if 'ff_eps' in fileformat:
                if self.verbose:
                    print '-' * 79
                    kavutil.vprint('Engine')
                    kavutil.vprint(None, 'Engine', 'eps.kmd')
                    kavutil.vprint(None, 'File name', os.path.split(filename)[-1])
                    print

                scan_ptns = []
                eps_keywords = fileformat['ff_eps']

                # Keyword 추출
                if self.verbose:
                    kavutil.vprint('EPS Keyword')
                    for i, name in enumerate(eps_keywords):
                        kavutil.vprint(None, 'Keyword #%d' % (i+1), name)
                    print

                if 'string' in eps_keywords:
                    scan_ptns.append(self.p_hex1)

                if 'hexstring' in eps_keywords or 'readhexstring' in eps_keywords:
                    scan_ptns.append(self.p_hex2)

                for i, ptn in enumerate(scan_ptns):
                    # Hex 문자열이 존재하는가?
                    t_hex = ptn.findall(mm)

                    if self.verbose and len(t_hex) > 0:
                        kavutil.vprint('HEX #%d' % (i+1))
                        for i, x in enumerate(t_hex):
                            kavutil.vprint(None, 'Hex String #%d' % (i+1), x)
                        print

                    # 화이트 리스트 제거
                    s_hex = ''.join(t_hex)
                    p = re.compile(r'\s|<|>')
                    t = p.sub('', s_hex)

                    if len(t) > 10 * 1024:  # 10K 이상인가?
                        return True, 'Trojan.EPS.Generic', 0, kernel.INFECTED
        except IOError:
            pass

        # 악성코드를 발견하지 못했음을 리턴한다.
        return False, '', -1, kernel.NOT_FOUND
Exemple #26
0
def analysis_ole10native(mm, verbose=False):
    fileformat = {}

    try:
        if mm[:2] == '\x02\x00':
            size = len(mm)
            fileformat['size'] = size  # 포맷 주요 정보 저장

            label = mm[2:2 + MAX_PATH].split('\x00', 1)[0]
            fileformat['label'] = label

            off = 2 + len(label) + 1
            fname = mm[off:off + MAX_PATH].split('\x00', 1)[0]

            off += len(fname) + 1
            off += 2  # flag

            unknown_size = ord(mm[off])
            off += 1 + unknown_size + 2

            command = mm[off:off + MAX_PATH].split('\x00', 1)[0]
            off += len(command) + 1

            data_size = kavutil.get_uint32(mm, off)

            fileformat['data_off'] = off + 4
            fileformat['data_size'] = data_size

            if len(mm) < off + data_size:  # 오류
                raise ValueError

            if verbose:
                print
                kavutil.vprint('Ole10Native Stream')
                kavutil.vprint(None, 'Size', '0x%08X' % size)
                kavutil.vprint(None, 'Label', label)
                kavutil.vprint(None, 'File Name', fname)
                kavutil.vprint(None, 'Command Line', command)
                kavutil.vprint(None, 'Data Offset', '0x%08X' % (off + 4))
                kavutil.vprint(None, 'Data Size', '0x%08X' % data_size)

                print
                kavutil.vprint('Data Dump')
                print
                kavutil.HexDump().Buffer(mm[:], off + 4, 0x80)
                print

            return fileformat
    except ValueError:
        pass
    except struct.error:
        pass

    return None
Exemple #27
0
    def parse(self):
        self.temp_name = tempfile.mktemp(prefix='knsf')

        # NSIS 위치 읽기
        fp = open(self.filename, 'rb')
        fp.seek(self.start_offset)
        data = fp.read()
        fp.close()

        open(self.temp_name, 'wb').write(data)

        self.fp = open(self.temp_name, 'rb')
        fsize = os.path.getsize(self.temp_name)
        if fsize == 0:
            return False

        self.mm = mmap.mmap(self.fp.fileno(), 0, access=mmap.ACCESS_READ)

        flag = kavutil.get_uint32(self.mm, 0)
        head_size = kavutil.get_uint32(self.mm, 0x14)
        comp_size = kavutil.get_uint32(self.mm, 0x18)

        data, case_type = self.get_data()  # NSIS의 모든 데이터를 가진다.
        self.body_data = data
        self.case_type = case_type

        if self.verbose:
            print '-' * 79
            kavutil.vprint('Engine')
            kavutil.vprint(None, 'Engine', 'nsis.kmd')
            kavutil.vprint(None, 'File name', os.path.split(self.filename)[-1])

            print
            kavutil.vprint('NSIS')
            kavutil.vprint(None, 'Flag', '%d' % flag)
            kavutil.vprint(None, 'Uncompress Case', '%d' % case_type)

            print
            kavutil.vprint('Uncompress Data')
            print
            kavutil.HexDump().Buffer(data, 0, 0x80)

            s = self.nsis_header.namelist_ex()
            if len(s):
                print
                kavutil.vprint('File Extract')
                print
                for t in s:
                    (foff, fname, ftime, extract_type) = t
                    print "%08X | %-45s | %s" % (foff, fname, ftime
                                                 if ftime != '' else 'N/A')

        return True