Ejemplo n.º 1
0
    def __EGG_Header__(self, data):
        try:
            # magic = struct.unpack('<L', data[0:4])[0]
            magic = kavutil.get_uint32(data, 0)
            if magic != 0x41474745:
                raise SystemError

            # version = struct.unpack('<H', data[4:6])[0]
            version = kavutil.get_uint16(data, 4)
            if version != 0x0100:
                raise SystemError

            # header_id = struct.unpack('<L', data[6:10])[0]
            header_id = kavutil.get_uint32(data, 6)
            if header_id == 0:
                raise SystemError

            # reserved = struct.unpack('<L', data[10:14])[0]
            reserved = kavutil.get_uint32(data, 10)
            if reserved != 0:
                raise SystemError

            return 0
        except SystemError:
            pass

        return -1
Ejemplo n.º 2
0
    def unarc(self, arc_engine_id, arc_name, fname_in_arc):
        if arc_engine_id == 'arc_icon':
            mm = self.__get_handle(arc_name)
            num = kavutil.get_uint16(mm, 4)

            p = p_name.search(fname_in_arc)
            if p:
                fw = int(p.groups()[0])
                fh = int(p.groups()[1])
                # fc = int(p.groups()[2])

                for i in range(num):
                    off = 6 + (16 * i)
                    w = ord(mm[off])
                    h = ord(mm[off + 1])
                    # c = kavutil.get_uint16(mm, off+6)

                    if w == fw and h == fh:  # and c == fc:
                        img_size = kavutil.get_uint32(mm, off + 8)
                        img_off = kavutil.get_uint32(mm, off + 12)
                        data = mm[img_off:img_off + img_size]

                        return data

        return None
Ejemplo n.º 3
0
    def __EGG_Header__(self, data):
        try:
            # magic = struct.unpack('<L', data[0:4])[0]
            magic = kavutil.get_uint32(data, 0)
            if magic != 0x41474745:
                raise SystemError

            # version = struct.unpack('<H', data[4:6])[0]
            version = kavutil.get_uint16(data, 4)
            if version != 0x0100:
                raise SystemError

            # header_id = struct.unpack('<L', data[6:10])[0]
            header_id = kavutil.get_uint32(data, 6)
            if header_id == 0:
                raise SystemError

            # reserved = struct.unpack('<L', data[10:14])[0]
            reserved = kavutil.get_uint32(data, 10)
            if reserved != 0:
                raise SystemError

            return 0
        except SystemError:
            pass

        return -1
Ejemplo n.º 4
0
    def __EGG_Dummy_Header_Size__(self, data):
        try:
            # dummy__size = struct.unpack('<H', data[5:7])[0]
            dummy__size = kavutil.get_uint16(data, 5)
            return 7 + dummy__size  # (5 + 2 + dummy__size)
        except:
            pass

        return -1
Ejemplo n.º 5
0
    def __EGG_Dummy_Header_Size__(self, data):
        try:
            # dummy__size = struct.unpack('<H', data[5:7])[0]
            dummy__size = kavutil.get_uint16(data, 5)
            return 7 + dummy__size  # (5 + 2 + dummy__size)
        except:
            pass

        return -1
Ejemplo n.º 6
0
    def format(self, filehandle, filename, filename_ex):
        ret = {}

        mm = filehandle
        if mm[0:4] == '\x00\x00\x01\x00':  # 헤더 체크
            ret['ff_icon'] = kavutil.get_uint16(mm, 4)
            return ret

        return None
Ejemplo n.º 7
0
    def __Alz_LocalFileHeader__(self, data):
        try:
            fname_size = kavutil.get_uint16(data, 4)
            file_desc = ord(data[11])
            compress__method__m = ord(data[13])

            size = 19
            if file_desc & 0x10:
                compress__size = ord(data[size])
                uncompress__size = ord(data[size + 1])
                size += (1 * 2)  # 파일 크기가 2개 옴(압축전, 압축 후)
            elif file_desc & 0x20:
                compress__size = kavutil.get_uint16(data, size)
                uncompress__size = kavutil.get_uint16(data, size + 2)
                size += (2 * 2)
            elif file_desc & 0x40:
                compress__size = kavutil.get_uint32(data, size)
                uncompress__size = kavutil.get_uint32(data, size + 4)
                size += (4 * 2)
            elif file_desc & 0x80:
                compress__size = kavutil.get_uint64(data, size)
                uncompress__size = kavutil.get_uint64(data, size + 8)
                size += (8 * 2)
            else:
                raise SystemError

            fname = data[size:size + fname_size]
            size += fname_size  # 파일 이름

            if file_desc & 1:
                size += 12  # Encrypt Block

            compressed__data = data[size:size + compress__size]

            return compressed__data, compress__method__m, size + compress__size, fname
        except IndexError:
            pass

        return None, -1
Ejemplo n.º 8
0
    def __EGG_Filename_Header__(self, data):
        size = -1
        fname = None

        try:
            # fname_size = struct.unpack('<H', data[5:7])[0]
            fname_size = kavutil.get_uint16(data, 5)
            fname = data[7:7 + fname_size]
            size = 7 + fname_size
        except:
            pass

        return size, fname
Ejemplo n.º 9
0
    def __Alz_LocalFileHeader__(self, data):
        try:
            fname_size = kavutil.get_uint16(data, 4)
            file_desc = ord(data[11])
            compress__method__m = ord(data[13])

            size = 19
            if file_desc & 0x10:
                compress__size = ord(data[size])
                uncompress__size = ord(data[size + 1])
                size += (1 * 2)  # 파일 크기가 2개 옴(압축전, 압축 후)
            elif file_desc & 0x20:
                compress__size = kavutil.get_uint16(data, size)
                uncompress__size = kavutil.get_uint16(data, size+2)
                size += (2 * 2)
            elif file_desc & 0x40:
                compress__size = kavutil.get_uint32(data, size)
                uncompress__size = kavutil.get_uint32(data, size+4)
                size += (4 * 2)
            elif file_desc & 0x80:
                compress__size = kavutil.get_uint64(data, size)
                uncompress__size = kavutil.get_uint64(data, size+8)
                size += (8 * 2)
            else:
                raise SystemError

            fname = data[size:size + fname_size]
            size += fname_size  # 파일 이름

            if file_desc & 1:
                size += 12  # Encrypt Block

            compressed__data = data[size:size + compress__size]

            return compressed__data, compress__method__m, size+compress__size, fname
        except IndexError:
            pass

        return None, -1
Ejemplo n.º 10
0
    def __EGG_Filename_Header__(self, data):
        size = -1
        fname = None

        try:
            # fname_size = struct.unpack('<H', data[5:7])[0]
            fname_size = kavutil.get_uint16(data, 5)
            fname = data[7:7+fname_size]
            size = 7 + fname_size
        except:
            pass

        fsencoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
        return size, fname.decode('utf-8').encode(fsencoding)
Ejemplo n.º 11
0
    def __EGG_Filename_Header__(self, data):
        size = -1
        fname = None

        try:
            # fname_size = struct.unpack('<H', data[5:7])[0]
            fname_size = kavutil.get_uint16(data, 5)
            fname = data[7:7 + fname_size]
            size = 7 + fname_size
        except:
            pass

        fsencoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
        return size, fname.decode('utf-8').encode(fsencoding)
Ejemplo n.º 12
0
    def arclist(self, filename, fileformat):
        file_scan_list = []  # 검사 대상 정보를 모두 가짐

        # 미리 분석된 파일 포맷중에 ICON 포맷이 있는가?
        if 'ff_icon' in fileformat:
            num = fileformat['ff_icon']
            mm = self.__get_handle(filename)

            for i in range(num):
                off = 6 + (16 * i)
                w = ord(mm[off])
                h = ord(mm[off + 1])
                c = kavutil.get_uint16(mm, off + 6)

                # name = '%dx%d %d bit' % (w, h, c)
                name = '%dx%d' % (w, h)
                file_scan_list.append(['arc_icon', name])

        return file_scan_list
Ejemplo n.º 13
0
def checkpe(dst, dsize, pehdr):
    try:
        if kavutil.get_uint32(dst, pehdr) != 0x4550:
            raise SystemError

        valign = kavutil.get_uint32(dst, pehdr + 0x38)
        if not valign:
            raise SystemError

        sectcnt = kavutil.get_uint16(dst, pehdr + 6)
        if not sectcnt:
            raise SystemError

        sections_pos = pehdr + 0xF8

        if (sections_pos + (sectcnt * 0x28)) > dsize:
            raise SystemError
    except:
        sections_pos = 0
        valign = 0
        sectcnt = 0
        pass

    return sections_pos, valign, sectcnt
Ejemplo n.º 14
0
def checkpe(dst, dsize, pehdr):
    try:
        if kavutil.get_uint32(dst, pehdr) != 0x4550:
            raise SystemError

        valign = kavutil.get_uint32(dst, pehdr + 0x38)
        if not valign:
            raise SystemError

        sectcnt = kavutil.get_uint16(dst, pehdr + 6)
        if not sectcnt:
            raise SystemError

        sections_pos = pehdr + 0xF8

        if (sections_pos + (sectcnt * 0x28)) > dsize:
            raise SystemError
    except:
        sections_pos = 0
        valign = 0
        sectcnt = 0
        pass

    return sections_pos, valign, sectcnt
Ejemplo n.º 15
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.º 16
0
    def __scan_asn1(self, filehandle, filename, fileformat, filename_ex):
        mm = filehandle

        ff = fileformat['ff_pe']

        cert_off = ff['pe'].get('CERTIFICATE_Offset', 0)
        cert_size = ff['pe'].get('CERTIFICATE_Size', 0)

        if cert_off != 0 and cert_size != 0:
            if self.verbose:
                print '-' * 79
                kavutil.vprint('Engine')
                kavutil.vprint(None, 'Engine', 'adware.kmd')

            # 인증서 추출
            cert_data = mm[cert_off:cert_off + cert_size]
            asn1 = ASN1()
            asn1.set_data(cert_data[8:])
            try:
                r = asn1.parse()

                # Signed Data 이면서 버전 정보가 1인가?
                if r[0][0] == '2A 86 48 86 F7 0D 01 07 02' and r[0][1][0][
                        0] == '01':
                    signeddata = r[0][1][0]
                    certificates = signeddata[3]

                    signerinfo = r[0][1][0][-1]
                    issuer_and_serialnumber = signerinfo[0][1]
                    issuer_serial = issuer_and_serialnumber[1]

                    for cert in certificates:
                        if cert[0][1] == issuer_serial:  # 동일한 일련번호 찾기
                            for x in cert[0][5]:
                                if x[0][0] == '55 04 03':  # Common Name
                                    signer_name = x[0][1]
                                    break
                            else:
                                continue  # no break encountered
                            break
                    else:
                        raise IndexError

                    # 일련번호의 길이가 제각각이라 md5 고정길이로 만듬
                    fmd5 = cryptolib.md5(issuer_serial)
                    fsize = kavutil.get_uint16(fmd5.decode('hex'), 0)

                    if self.verbose:
                        kavutil.vprint('Signer')
                        kavutil.vprint(None, 'Name', signer_name)
                        kavutil.vprint(None, 'Serial Number', issuer_serial)

                        msg = '%d:%s:  # %s, %s\n' % (fsize, fmd5, signer_name,
                                                      cryptolib.sha256(mm))
                        open('adware.mdb', 'at').write(msg)

                    if fsize and kavutil.handle_pattern_md5.match_size(
                            'adware', fsize):
                        vname = kavutil.handle_pattern_md5.scan(
                            'adware', fsize, fmd5)
                        if vname:
                            pos = ff['pe'].get('EntryPointRaw', 0)
                            if mm[pos:pos + 4] == '\xff\x25\x00\x20':
                                pf = 'MSIL'
                            else:
                                pf = 'Win32'

                            vname = kavutil.normal_vname(vname, pf)
                            return True, vname, 0, kernel.INFECTED
            except IndexError:
                pass

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

            if mm[0:8] != '\x4c\x00\x00\x00\x01\x14\x02\x00':  # LNK 헤더 체크
                raise ValueError

            flag = kavutil.get_uint32(mm, 0x14)

            off = 0x4c
            if flag & 0x0001 == 0x0001:  # HasLinkTargetIDList
                clid_mycom = '14001F50E04FD020EA3A6910A2D808002B30309D'.decode(
                    'hex')
                if mm[off + 2:off + 2 + 0x14] != clid_mycom:  # MyComputer
                    raise ValueError

                off += 2
                while True:
                    size = kavutil.get_uint16(mm, off)
                    if size == 0:
                        off += 2
                        break
                    if ord(mm[off + 2]) == 0x32:
                        if mm[off + 0xe:off + 0xe + 7].lower() != 'cmd.exe':
                            raise ValueError

                    off += size

            if flag & 0x0002 == 0x0002:  # HasLinkInfo
                off += kavutil.get_uint16(mm, off)

            if flag & 0x0004 == 0x0004:  # HasName
                size = kavutil.get_uint16(mm, off)
                off += (2 + (size * 2))

            if flag & 0x0008 == 0x0008:  # HasRelativePath
                size = kavutil.get_uint16(mm, off)
                cmd_path = mm[off + 2:off + 2 + (size * 2):2].lower()

                # print cmd_path

                if cmd_path.find('cmd.exe') == -1:
                    raise ValueError
                off += (2 + (size * 2))

            if flag & 0x0010 == 0x0010:  # HasWorkingDir
                size = kavutil.get_uint16(mm, off)
                off += (2 + (size * 2))

            if flag & 0x0020 == 0x0020:  # HasArguments
                size = kavutil.get_uint16(mm, off)
                cmd_arg = mm[off + 2:off + 2 + (size * 2):2].lower()
                cmd_arg = cmd_arg.replace('^', '')

                # print cmd_arg

                # 악성코드 패턴을 비교한다.
                if self.p_http.search(cmd_arg):
                    return True, 'Trojan.LNK.Agent.gen', 0, kernel.INFECTED
        except (IOError, ValueError):
            pass

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