Ejemplo n.º 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
Ejemplo n.º 2
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
Ejemplo n.º 3
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
Ejemplo n.º 4
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
Ejemplo n.º 5
0
Archivo: pe.py Proyecto: jaepil/kicomav
    def parse(self):
        mm = self.mm

        pe_format = {
            'PE_Position': 0,
            'EntryPoint': 0,
            'SectionNumber': 0,
            'Sections': None,
            'EntryPointRaw': 0,
            'FileAlignment': 0
        }

        try:
            if mm[0:2] != 'MZ':  # MZ로 시작하나?
                raise ValueError

            # PE 표식자 위치 알아내기
            pe_pos = kavutil.get_uint32(mm, 0x3C)

            # PE 인가?
            if mm[pe_pos:pe_pos + 4] != 'PE\x00\x00':
                raise ValueError

            pe_format['PE_Position'] = pe_pos

            # Optional Header의 Magic ID?
            if mm[pe_pos + 0x18:pe_pos + 0x18 + 2] != '\x0B\x01':
                raise ValueError

            # Entry Point 구하기
            pe_ep = kavutil.get_uint32(mm, pe_pos + 0x28)
            pe_format['EntryPoint'] = pe_ep

            # Image Base 구하기
            pe_img = kavutil.get_uint32(mm, pe_pos + 0x34)
            pe_format['ImageBase'] = pe_img

            # File Alignment 구하기
            self.pe_file_align = kavutil.get_uint32(mm, pe_pos + 0x3C)
            pe_format['FileAlignment'] = self.pe_file_align

            # Section 개수 구하기
            section_num = kavutil.get_uint16(mm, pe_pos + 0x6)
            pe_format['SectionNumber'] = section_num

            # Optional Header 크기 구하기
            opthdr_size = kavutil.get_uint16(mm, pe_pos + 0x14)
            pe_format['OptionalHederSize'] = opthdr_size

            # t섹션 시작 위치
            section_pos = pe_pos + 0x18 + opthdr_size

            # 모든 섹션 정보 추출
            for i in range(section_num):
                section = {}

                s = section_pos + (0x28 * i)

                section['Name'] = mm[s:s + 8].replace('\x00', '')
                section['VirtualSize'] = kavutil.get_uint32(mm, s + 8)
                section['RVA'] = kavutil.get_uint32(mm, s + 12)
                section['SizeRawData'] = kavutil.get_uint32(mm, s + 16)
                section['PointerRawData'] = kavutil.get_uint32(mm, s + 20)
                section['Characteristics'] = kavutil.get_uint32(mm, s + 36)

                self.sections.append(section)

            pe_format['Sections'] = self.sections

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

            # 리소스 분석
            rsrc_rva = kavutil.get_uint32(mm, pe_pos + 0x88)  # 리소스 위치(RVA)
            rsrc_size = kavutil.get_uint32(mm, pe_pos + 0x8C)  # 리소스 크기

            if rsrc_rva:  # 리소스가 존재한가?
                try:
                    rsrc_off, _ = self.rva_to_off(rsrc_rva)  # 리소스 위치 변환

                    # Type 체크
                    num_type_name = kavutil.get_uint16(mm, rsrc_off + 0xC)
                    num_type_id = kavutil.get_uint16(mm, rsrc_off + 0xE)

                    for i in range(num_type_name + num_type_id):
                        type_id = kavutil.get_uint32(mm,
                                                     rsrc_off + 0x10 + (i * 8))
                        name_id_off = kavutil.get_uint32(
                            mm, rsrc_off + 0x14 + (i * 8))

                        # Type이 사용자가 정의한 이름 or RCDATA?
                        if type_id & 0x80000000 == 0x80000000 or type_id == 0xA:
                            if type_id & 0x80000000 == 0x80000000:
                                # 사용자가 정의한 이름 추출
                                string_off = (type_id & 0x7FFFFFFF) + rsrc_off
                                len_name = kavutil.get_uint16(mm, string_off)
                                rsrc_type_name = mm[string_off + 2:string_off +
                                                    2 + (len_name * 2):2]
                            else:
                                rsrc_type_name = 'RCDATA'

                            # Name ID
                            name_id_off = (name_id_off & 0x7FFFFFFF) + rsrc_off
                            num_name_id_name = kavutil.get_uint16(
                                mm, name_id_off + 0xC)
                            num_name_id_id = kavutil.get_uint16(
                                mm, name_id_off + 0xE)

                            for j in range(num_name_id_name + num_name_id_id):
                                name_id_id = kavutil.get_uint32(
                                    mm, name_id_off + 0x10 + (j * 8))
                                language_off = kavutil.get_uint32(
                                    mm, name_id_off + 0x14 + (j * 8))

                                # 리소스 영역의 최종 이름 생성
                                if name_id_id & 0x80000000 == 0x80000000:
                                    string_off = (name_id_id
                                                  & 0x7FFFFFFF) + rsrc_off
                                    len_name = kavutil.get_uint16(
                                        mm, string_off)
                                    rsrc_name_id_name = mm[string_off +
                                                           2:string_off + 2 +
                                                           (len_name * 2):2]
                                    string_name = rsrc_type_name + '/' + rsrc_name_id_name
                                else:
                                    string_name = rsrc_type_name + '/' + hex(
                                        name_id_id).upper()[2:]

                                # Language
                                language_off = (language_off
                                                & 0x7FFFFFFF) + rsrc_off
                                num_language_name = kavutil.get_uint16(
                                    mm, language_off + 0xC)
                                num_language_id = kavutil.get_uint16(
                                    mm, language_off + 0xE)

                                for k in range(num_language_name +
                                               num_language_id):
                                    # language_id = kavutil.get_uint32(mm, language_off + 0x10 + (k * 8))
                                    data_entry_off = kavutil.get_uint32(
                                        mm, language_off + 0x14 + (k * 8))

                                    data_entry_off = (data_entry_off
                                                      & 0x7FFFFFFF) + rsrc_off

                                    data_rva = kavutil.get_uint32(
                                        mm, data_entry_off)
                                    data_off, _ = self.rva_to_off(data_rva)
                                    data_size = kavutil.get_uint32(
                                        mm, data_entry_off + 4)

                                    if data_size > 8192:  # 최소 8K 이상인 리소스만 데이터로 추출
                                        if 'Resource_UserData' in pe_format:
                                            pe_format['Resource_UserData'][
                                                string_name] = (data_off,
                                                                data_size)
                                        else:
                                            pe_format['Resource_UserData'] = {
                                                string_name:
                                                (data_off, data_size)
                                            }
                except struct.error:
                    pass

                # if 'Resource_UserData' in pe_format:
                #     print pe_format['Resource_UserData']

            # Import API 분석
            imp_rva = kavutil.get_uint32(mm,
                                         pe_pos + 0x80)  # Import API 위치(RVA)
            imp_size = kavutil.get_uint32(mm, pe_pos + 0x84)  # Import API 크기

            if imp_rva:  # Import API 존재
                imp_api = {}

                # print 'IMP : %08X' % imp_rva
                imp_off = self.rva_to_off(imp_rva)[0]
                # print hex(imp_off), imp_size
                imp_data = mm[imp_off:imp_off + imp_size]
                for i in range(imp_size / 0x14):  # DLL 정보 크기가 0x14
                    try:
                        dll_rva = kavutil.get_uint32(imp_data,
                                                     (i * 0x14) + 0xC)
                        api_rva = kavutil.get_uint32(imp_data, (i * 0x14))
                        bo = 2
                        if api_rva == 0:
                            api_rva = kavutil.get_uint32(
                                imp_data, (i * 0x14) + 0x10)
                            bo = 0

                        # print hex(api_rva)
                        if dll_rva == 0:  # DLL 정보가 없음
                            break

                        t_off = self.rva_to_off(dll_rva)[0]
                        dll_name = p_str.search(mm[t_off:t_off + 0x20]).group()
                        # print '[+]', dll_name
                        imp_api[dll_name] = []

                        t_off = self.rva_to_off(api_rva)[0]
                        while True:
                            try:
                                api_name_rva = kavutil.get_uint32(mm, t_off)
                            except struct.error:
                                break

                            if api_name_rva & 0x80000000 == 0x80000000:  # Odinal API
                                t_off += 4
                                continue

                            if api_name_rva == 0:
                                break

                            t = self.rva_to_off(api_name_rva)[0]
                            # print hex(t_off), hex(t)
                            api_name = p_str.search(mm[t + bo:t + bo +
                                                       0x20]).group()
                            # print '   ', api_name
                            imp_api[dll_name].append(api_name)
                            t_off += 4
                    except struct.error:
                        pass

                pe_format['Import_API'] = imp_api

            # 디지털 인증서 분석
            cert_off = kavutil.get_uint32(mm, pe_pos +
                                          0x98)  # 디지털 인증서 위치(유일하게 RVA가 아닌 오프셋)
            cert_size = kavutil.get_uint32(mm, pe_pos + 0x9C)  # 디지털 인증서 크기

            if cert_off:  # 디지털 인증서 존재
                if cert_off + cert_size <= len(mm[:]):  # UPack의 경우 이상한 값이 셋팅 됨
                    pe_format['CERTIFICATE_Offset'] = cert_off
                    pe_format['CERTIFICATE_Size'] = cert_size

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

                print
                kavutil.vprint('PE')
                kavutil.vprint(None, 'EntryPoint',
                               '%08X' % pe_format['EntryPoint'])
                kavutil.vprint(None, 'EntryPoint (Section)',
                               '%d' % pe_format['EntryPoint_in_Section'])

                # 섹션 보기
                if section_num:
                    print
                    kavutil.vprint('Section Header')
                    print '    %-8s %-8s %-8s %-8s %-8s %-8s' % (
                        'Name', 'VOFF', 'VSIZE', 'FOFF', 'FSIZE', 'EXEC')
                    print '    ' + ('-' * (9 * 6 - 1))

                    for s in self.sections:
                        print '    %-8s %08X %08X %08X %08X %-05s' % (
                            s['Name'], s['RVA'], s['VirtualSize'],
                            s['PointerRawData'], s['SizeRawData'],
                            s['Characteristics'] & 0x20000000 == 0x20000000)

                if section_num:
                    print
                    kavutil.vprint('Section MD5')
                    print '    %-8s %-8s %-32s' % ('Name', 'FSIZE', 'MD5')
                    print '    ' + ('-' * ((9 * 2 - 1) + 32))

                    for s in self.sections:
                        if s['Characteristics'] & 0x20000000 == 0x20000000:
                            off = s['PointerRawData']
                            size = s['SizeRawData']
                            fmd5 = cryptolib.md5(mm[off:off + size])
                            print '    %-8s %8d %s' % (s['Name'], size, fmd5)

                print
                kavutil.vprint('Entry Point (Raw)')
                print
                kavutil.HexDump().Buffer(mm[:], pe_format['EntryPointRaw'],
                                         0x80)
                print

        except ValueError:
            return None

        return pe_format
Ejemplo n.º 6
0
    def parse(self):
        mm = self.mm

        pe_format = {'PE_Position': 0, 'EntryPoint': 0, 'SectionNumber': 0,
                     'Sections': None, 'EntryPointRaw': 0, 'FileAlignment': 0}

        try:
            if mm[0:2] != 'MZ':  # MZ로 시작하나?
                raise ValueError

            dos_header = DOS_HEADER()
            ctypes.memmove(ctypes.addressof(dos_header), mm[0:], ctypes.sizeof(dos_header))

            # PE 표식자 위치 알아내기
            pe_pos = dos_header.e_lfanew

            # PE 인가?
            if mm[pe_pos:pe_pos + 4] != 'PE\x00\x00':
                raise ValueError

            pe_format['PE_Position'] = pe_pos

            # File Header 읽기
            file_header = FILE_HEADER()
            file_header_size = ctypes.sizeof(file_header)  # file_header_size : 0x14
            ctypes.memmove(ctypes.addressof(file_header), mm[pe_pos + 4:], file_header_size)

            # Optional Header 읽기
            optional_header = OPTIONAL_HEADER()
            optional_header_size = ctypes.sizeof(optional_header)
            ctypes.memmove(ctypes.addressof(optional_header), mm[pe_pos + 4 + file_header_size:], optional_header_size)

            # Optional Header의 Magic ID?
            if optional_header.Magic != 0x10b:
                raise ValueError

            # Entry Point 구하기
            pe_ep = optional_header.AddressOfEntryPoint
            pe_format['EntryPoint'] = pe_ep

            # Image Base 구하기
            pe_img = optional_header.ImageBase
            pe_format['ImageBase'] = pe_img

            # File Alignment 구하기
            self.pe_file_align = optional_header.FileAlignment
            pe_format['FileAlignment'] = self.pe_file_align

            # Section 개수 구하기
            section_num = file_header.NumberOfSections
            pe_format['SectionNumber'] = section_num

            # Optional Header 크기 구하기
            opthdr_size = file_header.SizeOfOptionalHeader
            pe_format['OptionalHederSize'] = opthdr_size

            # Data Directory 읽기
            data_directory_size = ctypes.sizeof(DATA_DIRECTORY())  # data_directory_size : 8
            num_data_directory = (opthdr_size - optional_header_size) / data_directory_size
            off_data_directory = pe_pos + 4 + file_header_size + optional_header_size

            for i in range(num_data_directory):
                dx = DATA_DIRECTORY()
                ctypes.memmove(ctypes.addressof(dx),
                               mm[off_data_directory + (i * data_directory_size):],
                               data_directory_size)

                self.data_directories.append(dx)

            # 섹션 시작 위치
            section_pos = pe_pos + 4 + file_header_size + opthdr_size

            # 모든 섹션 정보 추출
            for i in range(section_num):
                section = {}

                section_header = SECTION_HEADER()
                section_header_size = ctypes.sizeof(section_header)  # section_header_size : 0x28

                s = section_pos + (section_header_size * i)
                ctypes.memmove(ctypes.addressof(section_header), mm[s:], section_header_size)

                sec_name = ctypes.cast(section_header.Name, ctypes.c_char_p)
                section['Name'] = sec_name.value.replace('\x00', '')
                section['VirtualSize'] = section_header.Misc_VirtualSize
                section['RVA'] = section_header.VirtualAddress
                section['SizeRawData'] = section_header.SizeOfRawData
                section['PointerRawData'] = section_header.PointerToRawData
                section['Characteristics'] = section_header.Characteristics

                self.sections.append(section)

            pe_format['Sections'] = self.sections

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

            # 리소스 분석
            try:
                rsrc_rva = self.data_directories[image_directory_entry.RESOURCE].VirtualAddress  # 리소스 위치(RVA)
                rsrc_size = self.data_directories[image_directory_entry.RESOURCE].Size  # 리소스 크기
            except IndexError:
                rsrc_rva = 0
                rsrc_size = 0

            if rsrc_rva:  # 리소스가 존재한가?
                try:
                    rsrc_off, rsrc_idx = self.rva_to_off(rsrc_rva)  # 리소스 위치 변환

                    if rsrc_off > self.filesize:
                        raise ValueError

                    t_size = self.sections[rsrc_idx]['SizeRawData']
                    if not (len(mm[rsrc_off:rsrc_off + rsrc_size]) == rsrc_size or \
                        len(mm[rsrc_off:rsrc_off + t_size]) == t_size):  # 충분한 리소스가 존재하지 않음
                        raise ValueError

                    # Type 체크
                    num_type_name = kavutil.get_uint16(mm, rsrc_off+0xC)
                    num_type_id = kavutil.get_uint16(mm, rsrc_off + 0xE)

                    for i in range(num_type_name + num_type_id):
                        type_id = kavutil.get_uint32(mm, rsrc_off + 0x10 + (i*8))
                        name_id_off = kavutil.get_uint32(mm, rsrc_off + 0x14 + (i * 8))

                        # Type이 사용자가 정의한 이름 or RCDATA?
                        if type_id & 0x80000000 == 0x80000000 or type_id == 0xA or type_id == 0:
                            if type_id & 0x80000000 == 0x80000000:
                                # 사용자가 정의한 이름 추출
                                string_off = (type_id & 0x7FFFFFFF) + rsrc_off
                                len_name = kavutil.get_uint16(mm, string_off)
                                rsrc_type_name = mm[string_off + 2:string_off + 2 + (len_name * 2):2]
                            elif type_id == 0xA:
                                rsrc_type_name = 'RCDATA'
                            else:
                                rsrc_type_name = '%d' % type_id

                            # Name ID
                            name_id_off = (name_id_off & 0x7FFFFFFF) + rsrc_off
                            if name_id_off > self.filesize:
                                raise ValueError

                            num_name_id_name = kavutil.get_uint16(mm, name_id_off + 0xC)
                            num_name_id_id = kavutil.get_uint16(mm, name_id_off + 0xE)

                            for j in range(num_name_id_name + num_name_id_id):
                                name_id_id = kavutil.get_uint32(mm, name_id_off + 0x10 + (j * 8))
                                language_off = kavutil.get_uint32(mm, name_id_off + 0x14 + (j * 8))

                                # 리소스 영역의 최종 이름 생성
                                if name_id_id & 0x80000000 == 0x80000000:
                                    string_off = (name_id_id & 0x7FFFFFFF) + rsrc_off
                                    if string_off > self.filesize:
                                        raise ValueError

                                    len_name = kavutil.get_uint16(mm, string_off)
                                    rsrc_name_id_name = mm[string_off + 2:string_off + 2 + (len_name * 2):2]
                                    string_name = rsrc_type_name + '/' + rsrc_name_id_name
                                else:
                                    string_name = rsrc_type_name + '/' + hex(name_id_id).upper()[2:]

                                # Language
                                language_off = (language_off & 0x7FFFFFFF) + rsrc_off
                                if language_off > self.filesize:
                                    raise ValueError

                                num_language_name = kavutil.get_uint16(mm, language_off + 0xC)
                                num_language_id = kavutil.get_uint16(mm, language_off + 0xE)

                                for k in range(num_language_name + num_language_id):
                                    # language_id = kavutil.get_uint32(mm, language_off + 0x10 + (k * 8))
                                    data_entry_off = kavutil.get_uint32(mm, language_off + 0x14 + (k * 8))

                                    data_entry_off = (data_entry_off & 0x7FFFFFFF) + rsrc_off

                                    data_rva = kavutil.get_uint32(mm, data_entry_off)
                                    data_off, _ = self.rva_to_off(data_rva)
                                    if data_off > self.filesize:
                                        continue

                                    data_size = kavutil.get_uint32(mm, data_entry_off + 4)
                                    if data_size > self.filesize:
                                        continue

                                    if data_size > 8192:  # 최소 8K 이상인 리소스만 데이터로 추출
                                        if 'Resource_UserData' in pe_format:
                                            pe_format['Resource_UserData'][string_name] = (data_off, data_size)
                                        else:
                                            pe_format['Resource_UserData'] = {string_name: (data_off, data_size)}
                except (struct.error, ValueError) as e:
                    pass

                # if 'Resource_UserData' in pe_format:
                #     print pe_format['Resource_UserData']

            # Import API 분석
            try:
                imp_rva = self.data_directories[image_directory_entry.IMPORT].VirtualAddress  # Import API 위치(RVA)
                imp_size = self.data_directories[image_directory_entry.IMPORT].Size  # Import API 크기
            except IndexError:
                imp_rva = 0
                imp_size = 0

            if imp_rva:  # Import API 존재
                imp_api = {}

                # print 'IMP : %08X' % imp_rva
                imp_off = self.rva_to_off(imp_rva)[0]
                # print hex(imp_off), imp_size
                imp_data = mm[imp_off:imp_off+imp_size]
                if len(imp_data) == imp_size:
                    for i in range(imp_size / 0x14):  # DLL 정보 크기가 0x14
                        try:
                            dll_rva = kavutil.get_uint32(imp_data, (i*0x14)+0xC)
                            api_rva = kavutil.get_uint32(imp_data, (i * 0x14))
                            bo = 2
                            if api_rva == 0:
                                api_rva = kavutil.get_uint32(imp_data, (i*0x14)+0x10)
                                bo = 0

                            # print hex(api_rva)
                            if dll_rva == 0:  # DLL 정보가 없음
                                break

                            t_off = self.rva_to_off(dll_rva)[0]
                            dll_name = p_str.search(mm[t_off:t_off+0x20]).group()
                            # print '[+]', dll_name
                            imp_api[dll_name] = []

                            t_off = self.rva_to_off(api_rva)[0]
                            while True:
                                try:
                                    api_name_rva = kavutil.get_uint32(mm, t_off)
                                except struct.error:
                                    break

                                if api_name_rva & 0x80000000 == 0x80000000:  # Odinal API
                                        t_off += 4
                                        continue

                                if api_name_rva == 0:
                                    break

                                t = self.rva_to_off(api_name_rva)[0]
                                # print hex(t_off), hex(t)
                                api_name = p_str.search(mm[t+bo:t+bo+0x20]).group()
                                # print '   ', api_name
                                imp_api[dll_name].append(api_name)
                                t_off += 4
                        except struct.error:
                            pass
                # end if

                pe_format['Import_API'] = imp_api

            # 디지털 인증서 분석
            try:
                cert_off = self.data_directories[image_directory_entry.SECURITY].VirtualAddress  # 유일하게 RVA가 아닌 오프셋
                cert_size = self.data_directories[image_directory_entry.SECURITY].Size  # 디지털 인증서 크기
            except IndexError:
                cert_off = 0
                cert_size = 0

            if cert_off:  # 디지털 인증서 존재
                if cert_off + cert_size <= len(mm[:]):  # UPack의 경우 이상한 값이 셋팅 됨
                    pe_format['CERTIFICATE_Offset'] = cert_off
                    pe_format['CERTIFICATE_Size'] = cert_size

            # Debug 정보 분석
            try:
                debug_rva = self.data_directories[image_directory_entry.DEBUG].VirtualAddress  # RVA
                debug_size = self.data_directories[image_directory_entry.DEBUG].Size  # 크기
                if debug_size < 0x1C:
                    raise ValueError
            except (IndexError, ValueError) as e:
                debug_rva = 0
                debug_size = 0

            if debug_rva:  # Debug 정보 존재
                t = self.rva_to_off(debug_rva)[0]
                debug_off = kavutil.get_uint32(mm, t + 0x18)
                debug_size = kavutil.get_uint32(mm, t + 0x10)

                debug_data = mm[debug_off:debug_off + debug_size]

                if debug_data[:4] == 'RSDS':
                    pe_format['PDB_Name'] = debug_data[0x18:]
                else:
                    pe_format['PDB_Name'] = 'Not support Type : %s' % debug_data[:4]

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

                print
                kavutil.vprint('PE')
                kavutil.vprint(None, 'EntryPoint', '%08X' % pe_format['EntryPoint'])
                kavutil.vprint(None, 'EntryPoint (Section)', '%d' % pe_format['EntryPoint_in_Section'])

                # 섹션 보기
                if section_num:
                    print
                    kavutil.vprint('Section Header')
                    print '    %-8s %-8s %-8s %-8s %-8s %-8s' % ('Name', 'VOFF', 'VSIZE', 'FOFF', 'FSIZE', 'EXEC')
                    print '    ' + ('-' * (9*6 - 1))

                    for s in self.sections:
                        print '    %-8s %08X %08X %08X %08X %-05s' % (s['Name'], s['RVA'], s['VirtualSize'],
                                                                     s['PointerRawData'], s['SizeRawData'],
                                                                     s['Characteristics'] & 0x20000000 == 0x20000000)

                if section_num:
                    print
                    kavutil.vprint('Section MD5')
                    print '    %-8s %-8s %-32s' % ('Name', 'FSIZE', 'MD5')
                    print '    ' + ('-' * ((9 * 2 - 1)+32))

                    for s in self.sections:
                        # if s['Characteristics'] & 0x20000000 == 0x20000000:
                        off = s['PointerRawData']
                        size = s['SizeRawData']
                        fmd5 = cryptolib.md5(mm[off:off+size]) if size else '-'
                        print '    %-8s %8d %s' % (s['Name'], size, fmd5)

                print
                kavutil.vprint('Entry Point (Raw)')
                print
                kavutil.HexDump().Buffer(mm[:], pe_format['EntryPointRaw'], 0x80)
                print
                if 'PDB_Name' in pe_format:
                    kavutil.vprint('PDB Information')
                    kavutil.vprint(None, 'Name', '%s' % repr(pe_format['PDB_Name']))
                    print repr(pe_format['PDB_Name'])
                    print

        except (ValueError, struct.error) as e:
            return None

        return pe_format
Ejemplo n.º 7
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