python

Email parser 제작기

yssy431 2020. 7. 22. 23:44

예전에 대량의 이메일 안의 악성코드들을 분석하게 되면서 일일이 폴더에 메일 정보정리와 악성코드들을 저장하다가 python으로 작업한 내용

이런식의 eml파일이 수백건이 들어왔었다.. 보낸사람,제목 받는사람 등등등 여러 정보들을 수집해서 정리해야 했고 파일들을 일일 폴더내에 저장해야 되서 자동 폴더 생성과 eml parser를 따로 따로 제작하게 되었다. 

** 스피어 피싱의 일종으로 pc정보 수집하는 악성코드였던걸로 기억한다.

 

<eml parser code>

#-*- coding:utf-8 -*-
from email.parser import Parser
from email import policy
from email.parser import BytesParser
import os
import email
from email.message import EmailMessage
from email.header import decode_header
import ctypes
import re

PATH_Dir = './target' #해당폴더에 원하는 eml파일이나 폴더 넣기 eml파일만 잇어야함

# 요월들을 매핑하여 date를 변환하는 함수
def convert_date(date):
    total = []
    
    con_date = date.split(' ')
    
    Month_list = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']
    
    for i,month in enumerate(Month_list):        
        if con_date[2] == month:
            
            Con_month = str(i+1)   
            temp = f"{con_date[3]}-{Con_month}-{con_date[1]} {con_date[4]}"
            return temp        
    
    
#정보를 텍스트로 쓰는 함수
def Result_report(result):
    with open('Status_Report.txt','a',encoding='utf-8') as f:
        f.writelines(f"{result}\n")

#html내용들을 모조리 삭제하는 함수
def HtmltoText(data):
    data = re.sub(r'&nbsp;','',data)
    data = re.sub(r'</.*?>','\n',data)
    data = re.sub(r'<.*?>', '', data)
    return data
     
   

#email내의 정보들을 추출하는 함수
def extract_info(target_eml):
    with open(target_eml, 'rb') as fp:
        info = []
        msg = BytesParser(policy=policy.default).parse(fp)
       
        EML_RECEIVE = str(msg['To'])   #수신자
        EML_SENDER = str(msg['From'])
        EML_SUBJECT = str(msg['Subject'])
        EML_DATE = str(msg['Date'])
        if msg['Date'] is not None:
            EML_DATE = convert_date(EML_DATE)
        info.append(f"메일 제목 : {EML_SUBJECT}\n")
        info.append(f"날짜  :   {EML_DATE}\n")
        info.append(f"수신자  :   {EML_RECEIVE}\n")
        info.append(f"발신자  :   {EML_SENDER}\n")
       
        if msg['X-Original-SENDERIP'] is not None:
            EML_SEND_IP = str(msg['X-Original-SENDERIP'])
            info.append(f"X-Original-SendIP  :   {EML_SEND_IP}\n")           

        if msg['X-Originating-IP'] is not None:
            EML_SEND_IP2 = str(msg['X-Originating-IP'])
            info.append(f"X-Originating-IP  :   {EML_SEND_IP2}\n")           
                     
        
        if msg['X-Original-SENDERCOUNTRY'] is not None:
            EML_SEND_COUNTRY = str(msg['X-Original-SENDERCOUNTRY'])
            info.append(f"X-Original-SendCOUNTRY  :   {EML_SEND_COUNTRY}\n")   
           
        try:
            for part in msg.walk():                            # walk visits message
                type = part.get_content_type()
                if type == 'text/html':
                    EML_BODY = str(msg.get_body(preferencelist=('html')).get_content())                    
                    EML_BODY = HtmltoText(EML_BODY)
                elif type == 'text/plain':
                    EML_BODY = str(msg.get_body(preferencelist=('plain')).get_content())
                    
        except Exception as Error:
            print(Error)
            pass
        
        info.append(f"이메일 내용  :   \n{EML_BODY}") # Body
        
    return info


def get_part_filename(msg: EmailMessage):
    try:
        filename =  msg.get_filename()
    
        
        if decode_header(filename)[0][1] is not None:
            filename = decode_header(filename)[0][0].decode(decode_header(filename)[0][1])
            
        return filename    
    except:
        return 'File Error'   

#eml 파일내의 파일들을 추출하여 저장
def extract_attachments(Path,target_eml):
    
    try:
        msg = email.message_from_file(open(target_eml,encoding='utf-8'))
    except Exception as detail:
        print(detail)       
    attachments=msg.get_payload()    
    fnam_list = []
    
    
    if msg.is_multipart() is True:
        
        for attachment in attachments[1:]:
            if get_part_filename(attachment) == 'File Error':
                return 'File Error'
            else:
                fnam = get_part_filename(attachment)
                
                fnam_list.append(fnam)
                attach_file = f"{Path}\{fnam}"
                
                with open(attach_file, 'wb') as f:
                    f.write(attachment.get_payload(decode=True))
                    Result_report(f"sucess!, extract attachment : {fnam}")
    elif msg.is_multipart() is False:
        return 'No File'       
    else:
        return 'File Error'

    return fnam_list


def Mbox(title, text, style):
    return ctypes.windll.user32.MessageBoxW(0, text, title, style)




def main():
    
    for root, dirs, files in os.walk(PATH_Dir):
        for file in files:
            list_info = []
            list_Second = []            
            if '_info.txt' not in file:
                target = f"{root}\{file}"
                fnm_txt = f"{root}\{file}_info.txt"            
                list_Second = extract_info(target)
                list_Second = [x for x in list_Second if x]
                list_info.append(f"eml 파일명 : {file}\n")
                try:
                    fnm_name = extract_attachments(root,target)
                    if fnm_name == 'No File':
                        list_info.append(f"{file}   :   첨부파일 없음\n")
                        Result_report(f"{file}  : 첨부파일없음")
                    elif fnm_name == 'File Error':
                        list_info.append(f"첨부 파일 : 파일 형식 에러로 수동 추출 필요\n")   
                        Result_report(f"{file}  :   파일 형식 에러")
                    else:
                        fnm_name = [x for x in fnm_name if x]   #eml 첨부파일명들 가져온 후 list 내 None 삭제
                        for x in fnm_name:
                            #Attach_File_PATH = f"{root}\{x}"
                            list_info.append(f"첨부 파일명 : {x} \n") # 첨부파일 MD5값   :   {getHash(Attach_File_PATH)}

                        
                except Exception as err:
                    Result_report(f"{root}에서 문제 발견 : {err} ")                
                    pass               
             
                with open(fnm_txt, 'w',encoding='utf-8') as f:                                         
                    f.writelines(list_info)
                    f.writelines(list_Second)
                    Result_report(f"Sucess!, create info file : {file}_info.txt")
                    Result_report("---------------------------------------")
            else:
                Result_report(f"중복파일 발견 : {fnm_txt}")
               
                
        


if __name__ == "__main__":
    main()
    Mbox("완료","작업완료",0)
    

해당 python script내에 target이란 폴더안에 eml파일들을 넣고 폴더생성 스크립트 실행 후 eml_parser를 실행하게 되면 .txt파일에 파일 정보들과 파일들을 추출하여 저장하게 된다

 

 

초창기 열심히 python을 공부하며 만들었을 때라 코드들이 깔끔하지 않다. 다시 쓸일이 없을 것 같기에 수정 작업을 하진 않았다. 요즘 코딩할 때에는 조금 더 파이썬스럽게 짜도록 노력 중이다.