프로젝트

[Forensic] 파이썬(Python)으로 파일 속 숨겨진 파일 찾기 (스테가노그래피)

e_yejun 2020. 12. 24. 00:40

 

심심해서 혼자 놀다가(2)..

 

저번에 심심해서 간단하게 스테가노그래피로 파일을 숨겼었다.

그러다 파일 시그니처를 이용해서 숨긴 파일들을 찾을 수 있을 것이라고 생각했다.

 

HxD 에디터가 없다는 가정 하에,

파일에 대한 Hex Dump 값부터 파이썬으로 나타내야 겠다고 생각했다.

 

이 부분은 stackoverflow 코드를 많이 참고했고,

그 Hex Dump를 나타내는 코드를 단계별로 변형시켰다.

 

간단한 테스트를 위해 몇몇 확장자(PNG, JPEG, GIF, ZIP)의 시그니처를 이용했고,

차후 여러 시그니처가 추가되서 길어질 코드를 대비하여 시그니처 파일을 분리했다.

 

 

 

<signature.py>

file_signature = ['ff d8 ff e0',
                  'ff d8 ff e8',
                  '89 50 4e 47 0d 0a 1a 0a',
                  '50 4b 03 04',
                  '47 49 46 38 37 61',
                  '47 49 46 38 39 61',
                  '25 50 44 46 2d 31 2e'    
                  ]

file_header_footer = {'ff d8 ff e0':'ff d9',
                      'ff d8 ff e8':'ff d9',
                      '89 50 4e 47 0d 0a 1a 0a':'49 45 4e 44 ae 42 60 82',
                      '50 4b 03 04':'50 4b 05 06',
                      '47 49 46 38 37 61':'00 3b',
                      '47 49 46 38 39 61':'00 3b',
                      '25 50 44 46 2d 31 2e':'25 25 45 4f 46'  
                      }

file_extension = {'ff d8 ff e0':'jpeg', 
                  'ff d8 ff e8':'jpeg',
                  '89 50 4e 47 0d 0a 1a 0a':'png',
                  '50 4b 03 04':'zip',
                  '47 49 46 38 37 61':'gif',
                  '47 49 46 38 39 61':'gif',
                  '25 50 44 46 2d 31 2e':'pdf'
                    }

 

 

<hiddenfile_find.py>

import itertools
import argparse
import sys
import os 
from math import ceil 
from signature import *


def hex_group_formatter(iterable):
    chunks = [iter(iterable)] * 4
    return '   '.join(
        ' '.join(format(x, '0>2x') for x in chunk)
        for chunk in itertools.zip_longest(*chunks, fillvalue=0))

def hex_viewer(filename, chunk_size=16):
    template = ' {:<53}'
    with open(filename, 'rb') as stream:
        for chunk_count in itertools.count(0):
            chunk = stream.read(chunk_size)
            if not chunk:
                return
            yield template.format(
                hex_group_formatter(chunk)
				)

def file_out(string, header_signature):
	global out_file_cnt, unit
	out_file_cnt += 1
	out_file_name = 'file_out_' + str(out_file_cnt) + '.' + file_extension[header_signature]
	f = open(out_file_name,'wb+')   
	f.write(bytes.fromhex(string))
	f.close()
	out_file_size = os.path.getsize(out_file_name)
	print('[*] Out_file :', out_file_name,'  \t','Size :', size_return(out_file_size))

	
def size_return(bytes):
	size_result = str(bytes) + 'Byte'
	if (bytes > 1024):
		size_result = str(int(ceil(bytes/1024))) + 'KB'
	elif (bytes > 1024*1024):	
		size_result = str(int(ceil(bytes/(1024*1024)))) + 'MB'
	elif (bytes > 1024*1024*1024):	
		size_result = str(ceil(bytes/(1024*1024*1024))) + 'GB'
	elif (bytes > 1024*1024*1024*1024):	
		size_result = str(int(ceil(bytes/(1024*1024*1024*1024)))) + 'TB'
	return size_result
	
def usage():
	print("syntax: ./hiddenfile_find <file>")

	
if __name__ == '__main__':
	if(len(sys.argv) != 2):
		usage()
		exit()
	parser = argparse.ArgumentParser(description='Hexadeciaml viewer.')
	parser.add_argument('file', nargs='?', default=sys.argv[1], help='the file to process')
	args = parser.parse_args()
	
	file_size = os.path.getsize(sys.argv[1])

	print('\n[*] Input_file :', sys.argv[1],'\t','Size :', size_return(file_size),'\n')
	
	cnt = -1
	out_file_cnt = 0
	out_file_flag = 0
	string = ''

	for line in hex_viewer(args.file):
		string += line.replace("   ", " ")

	#print(hex(len(string)))
	#print(string[6373626-30:6373626])

	while (cnt < len(file_signature)-1):
		cnt += 1
		if (string.find(file_signature[cnt]) != -1):      
			file_index_start = string.index(file_signature[cnt])
			header_signature = string[file_index_start:file_index_start+len(file_signature[cnt])]
			footer_signature = file_header_footer[header_signature]
			out_file_flag = 1

			if(string[file_index_start:].find(footer_signature)!= -1):
				file_index_end = string[file_index_start:].index(footer_signature)+ file_index_start + len(footer_signature)
			else:
				out_file_flag = 0
				continue 
		
		#print(file_index_start)
		#print(file_index_end)
		#print(string[167280-20:167280])
		

		if (out_file_flag == 1):
			out_file_flag = 0

			new_file = string[file_index_start:file_index_end]
			#print(new_file)

			# 파일 추출
			file_out(new_file, header_signature)
			
			# 추출 파일 삭제
			next_index = file_index_end + 1
			string = string[:file_index_start] + string[next_index:]
			
			#print(string)
			cnt = -1
		
	#print(string)

 

명령 프롬프트로 해당 Python 파일경로에 가서 

 

python hiddenfile_find.py [filename]

 

형식으로 실행하면 시그니처를 비교하면서 파일을 분리해줄 것이다.

 

평범한 고양이 사진에서 중요한 파일.txt가 담긴 압축파일이 추출된 것을 확인할 수 있다.

 

 

 

 

 

친구의 피드백

+ ) 파일 시그니처별 헤더나 특성도 이용해보라고 한다.

++ ) 핸드폰으로 찍은 사진 어딘가에 위치좌표도 찾을 수 있다고 한다.

 

나중에 더 많이 심심해지면 찾아봐야지.

 

 

steganography_.zip
0.10MB

수정일 : 2020.12.27.(Sun)

 

 

 

 

 

reference

Python Hex Viewercodereview.stackexchange.com/questions/147225/python-hex-viewer