## 개요 포렌식 분석을 할때 제일 먼저 하는 작업은 무엇일까? 미시적인 관점에서 바라보았을 때는 데이터 보존 및 영장발부 같은 세부적인 과정이 있겠지만, 직관적으로 떠오르는 과정은 증거물 수집 과정의 이미징이 아닐까 싶다. 이미징은 증거물의 무결성을 보장하기 위해 원본 데이터와 동일한 사본을 만드는 행위이다. 원본 데이터를 분석하는 일은 적어도 멀쩡하게 사고가 박힌 분석관이라면 하지 않는다. 그만큼 무결성은 중요하기 때문이다. 그렇다면 사본은 어떻게 만들까? `Ctrl-C` `Ctrl-V` 를 통해 특정 드라이브의 데이터를 복사하면 될까? 어림없다. 파일 복사와 관련된 실험 글인 ([[파일 복사 시 시간 변화 실험]]) 을 참고해 보면 파일에 관련된 시간 값이 복사와 동시에 변경되는 것을 볼 수 있다. 그럼 말짱 도루묵이 되겠다. 아무튼 이런 이유 때문에 우린 Low-level 에서 파일이 아닌, 디스크 이미지 자체 혹은 파일시스템 전체를 복제하게 된다. 이때 복제를 하더라도 추후에 조사 단계에서 데이터를 가공(processing)할 수 있는 특수한 파일 포맷이 필요하다. 수집 도구별로 다양한 증거 파일 양식을 제공하지만 가장 잘 알려진 파일 양식으로는 단연코 `E01`, `dd` 두 종류를 들어볼 수 있겠다. ## DD 파일 ### 정의 & 특징 적당한 말이 생각나지 않는다. DD 파일 양식은 우리가 가장 흔히 볼 수 있는 파일 양식이다. 바로 raw 양식이다. Raw 양식은 날것 그대로라는 단어 뜻에서 미루어볼 수 있듯 아무 추가적인 데이터 가공 없이 원본 데이터를 그대로 복사해온 것을 의미한다. DD파일은 원본 데이터를 복사했기 때문에 원본 데이터와 사이즈가 동일하다. 너무나도 당연한 소리라 좀 당황스러울 수도 있지만 이게 포인트다. 한번이라도 이미징을 해봤거나, 본인 PC에서 연습삼아 본인 디스크를 이미징해 본 사람은 느껴봤겠지만 아무 생각 없이 본인 컴퓨터를 출력 경로로 지정해서 이미징을 시도하면 용량이 부족하다고 알림이 뜨는 상황을 겪어봤을 것이다. (나만 겪어본거 아니지?) 당연하게도, 컴퓨터 디스크 용량만큼의 복사본을 원본 디스크 안에 저장할 수는 없다. 때문에 다른 증거 파일 포맷들은 데이터를 복제할 때 압축률을 지정할 수 있도록 설정되어 있는 것이다. ## E01 파일 ### 정의 & 특징 E01 파일이다. Encase Image File format의 약어로, 증거 보관용 파일을 의미한다. Encase 소프트웨어가 출시되면서 널리 사용되는 경우이다. Encase가 법적 공방에서 공식적인 증거 능력을 지닌 소프트웨어로 인정되었기 때문에 한동안 포렌식 업계에서는 (특히 미국 지역) Encase 붐이 일었었다. 지금은 잦은 담당 회사의 변경으로 인해 예전만큼의 입지를 가지지는 못하지만 여전히 Encase의 시장 점유율은 어마어마하다. 다시 본론으로 돌아오자면 Encase 에서 주로 사용하는 E01파일은 파일 구조에 맞게 증거물을 가공된 형태로 저장한다는 특징이 있다. 다른 증거 파일 양식도 동일하지만 가장 대표적인 파일 양식이기에 소개하게 되었다. 사실 E01 파일은 그 이름이 부정확하다. 정확히는 E0#N 파일이 맞을 것이다. 여느 압축 파일과 마찬가지로 E01 파일은 분할 압축을 지원하고 있다. 디지털 포렌식 수집의 특성 상 용량이 큰 파일들을 다루게 될 확률이 높기 때문이다. 따라서 증거물 수집 결과가 분할 압축되는 경우 확장자 양상은 E01, E02 … 형태로 이어진다. 물론 여러 파일은 서로 연결되어 있기 때문에, E01 파일만 입력으로 주면 나머지를 통합 인식하도록 되어 있을 것이다. (도구가 E01 형식을 지원하는 경우에만 그렇다) E01 파일 내에는 무결성 검증을 위해 존재하는 파일의 해시값, 다양한 압축률에 따라 압축되어 가공된 데이터가 존재한다. 여타 다른 글처럼 E01파일의 구조를 분석할 것 같으면 좋겠지만, 구조를 파악하는 것보다는 어떻게 활용해야 할 지 고민하는게 더욱 생산적이기 때문에 구조 자체는 가볍게 훑어 보고 넘어갈 것이다. ### 구조 #### Case Info 디저털 포렌식 도구들을 다루어 보면 사건 담당자 이름, 케이스 번호, 사건 유형을 비롯한 정보들을 작성하게 한다. 이는 E01 파일의 헤더 부분에 들어가는 Case Information을 작성하기 위함인데, 앞서 말한 것과 같이 이 영역에는 다음 정보들을 확인할 수 있다. - 사건 조사관 이름 - 케이스 이름 - 증거물 세부 설명 - 날짜 - 소프트웨어 버전 (증거 분석 도구) - 운영체제 정보 #### Hash 증거물 보관 파일에 있어서 가장 중요한 건 [[무결성]]이 아닐까 싶다. 무결성을 확보함으로써 해당 증거가 위,변조되거나 의도적으로 훼손되지 않았음을 입증할 수 있을 것이다. E01파일에는 두 종류의 Hash가 사용된다. CRC와 MD5이다. CRC는 데이터의 오류를 검증하기 위한 해시값인데 E01파일 안에서 32KB의 데이터마다 그 값을 검증하도록 설계되어 있다. 따라서 전체적인 구조를 본다면 E01파일은 데이터 블록과 CRC 체크썸 값이 하나의 쌍을 이뤄 반복적으로 등장하는 구조이다. 또 파일의 마지막 부분에서 등장하는 해시는 MD5 해시인데, 해당 값은 전체 영역의 데이터가 정확하게 위치해 있는지를 점검하는 용도이다. > [!question] 제 해시값이 이상해요 > > 해시값을 구해 보았는데, 원본 데이터의 해시 값과, E01파일의 해시 값이 달라서 당황한 사람들도 있을 것이다. > > E01내에 삽입되는 MD5 해시값은 CRC 해시 값을 제외한 원본 데이터에 대한 해시값이기 떄문에 E01 파일 자체의 해시를 구해 놓고 오해하면 안되겠다. #### Data Block 해시 부분에서 언급했듯, 전체 데이터는 32KB단위로 분할되어 저장된다. ### 분석 방법 보통은 각각의 디지털 포렌식 분석 도구를 통해 raw 이미지나 E01 이미지를 분석하게 된다. 이번 절을 작성하는 이유는 도구 사용법을 익히지 못한 사람들을 위함이 아니라, 직접 도구를 개발하고 싶은 사람들을 위한 것이다. 보통 간단한 도구나 스크립트를 작성할 때, 직접 파일을 추출해서 도구의 입력값으로 주는 경우가 많다. 간단하게 사용할 코드인 경우 그렇게 해도 큰 문제점은 없다. 다만 입력값을 생성하기 위한 노력은 분석관이 집적 해야하므로, 그 분석의 품질은 개별 분석관 마다 상이하게 나타날 것이다. 따라서 디지털 포렌식 도구 개발자는 가장 사용자 상호작이 적은 데이터를 입력값으로 받음으로써 분석의 품질을 일관성 있게 유지할 수 있을 것이다. C, Python. C++ 등 다양한 언어가 존재하지만 오늘 다뤄볼 언어는 Python이다. 스크립트로 작성하기 가볍기 때문이고, 다양한 라이브러리가 존재하기 때문이다. 주로 E01 파일을 읽고 그 구조를 탐색하기 위해 사용하는 라이브러리는 `pyewf` 와 `pytsk3` 이다. 각각 다음 명령어를 통해 설치 가능하다. ```bash pip install libewf-python pip install pytsk3 ``` 예제 코드와 함께 가볍게 보도록 하자. 활용은 각자의 몫이겠다. ### Sample ```python class ewf_Img_Info(pytsk3.Img_Info): def __init__(self, ewf_handle): self._ewf_handle = ewf_handle super(ewf_Img_Info, self).__init__(url="", type=pytsk3.TSK_IMG_TYPE_EXTERNAL) def close(self): self._ewf_handle.close() def read(self, offset, size): self._ewf_handle.seek(offset) return self._ewf_handle.read(size) def get_size(self): return self._ewf_handle.get_media_size() ``` 기본적인 E01파일을 읽는 클래스다. ```Python class E01_handler: def __init__(self,imgpath): self.img = imgpath self.fsobj,self.raw_handle = self.read_imagefile(imgpath,self.getfileType(imgpath)) def getfileType(self,filepath): if filepath.split(".")[-1] == 'E01': return "E01" else : return "raw" def read_imagefile(self,imgpath,imgtype): if imgtype == "E01": filenames = pyewf.glob(imgpath) fshandle = pyewf.handle() fshandle.open(filenames) img_Info = ewf_Img_Info(fshandle) else: img_Info = pytsk3.Img_Info(imgpath) try:#MULTIPARTITION IMAGE partitionTable = pytsk3.Volume_Info(img_Info) for partition in partitionTable: if b'Basic data partition' in partition.desc: fileSystemObject = pytsk3.FS_Info(img_Info, offset = (partition.start * 512)) except IOError:#SINGLE PARTITION IMAGE fileSystemObject = pytsk3.FS_Info(img_Info, offset = 0) return fileSystemObject,img_Info def readFile(self,filepath): f = self.fsobj.open(filepath) offset=0 size=f.info.meta.size data = b"" while offset<size: max_size=min(1024*1024,size-offset) buf = f.read_random(0,max_size) if not buf: break data += buf offset+=len(buf) return data def listdir(self,filepath): filelist = self.fsobj.open(filepath).as_directory() res = [] for file_ in filelist: if file_.info.name.name in [b'.',b'..']: continue res.append(file_.info.name.name) return res ``` 우선 이미지 파일을 읽는 함수인 `read_imagefile` 을 만들어 보았는데, 생각보다 복잡하지 않다. 파일 유형을 확인한 다음, `pytsk3` 를 이용해서 파티션 테이블을 읽어온다. 읽어온 파티션을 파일시스템 오브젝트로써 활용하면 되겠다. 이 오브젝트는 실질적으로 경로를 통해 파일을 접근하게 할 수 있도록 해준다. 파일시스템 오브젝트를 활용하여 일반적으로 활용의 초석이 되는 디렉토리 리스팅 함수와, 파일의 데이터를 읽는 함수를 만들어 보았다. 유사한 활용법을 적용해서 Raw 형식의 이미지도 다룰 수 있다. 이정도만 해도 특정 아티팩트를 분석하거나, 프로그램의 데이터를 수집하는 프로그램 정도는 만들 수 있게 될 것이다. ## 결론 오늘은 증거 파일들에 대해서 알아보았다. 두가지 유형을 알아보았는데, 우선 E01 파일과 Raw 파일이 어떤 유형의 파일인지 알아보았다. 가장 많이 접하게 되는 두가지 파일 유형일 것이다. 가볍게 그 구조도 알아보면서 CRC 와 MD5 해시를 활용하여 데이터를 검사하기 때문에 우리가 이 파일을 믿을 수 있다는 것 역시 검증해 보았다. 또 이번 글에서는 단순히 도구를 사용해서 분석하는 게 아니라, 직접 파이썬 프로그래밍을 통해 E01파일이나 Raw 파일을 직접 분석할 수 있다는 것도 설명했는데, 이 코드를 통해서 많은 사람들이 파일을 증거물로부터 extract한 다음 그 파일을 스스로 전처리하고, 이런 복잡한 과정 없이 하나의 도구에서 모든 가공 행위를 할 수 있으면 좋겠다.