
본 글은 연구목적으로 작성된 글이며 불법적 용도로 사용을 금합니다
[참고 논문] 윈도우 환경에서 카카오톡 데이터 복호화 및 아티팩트 분석 연구
1. 들어가는 말
이전 글에서는 카카오톡 edb파일을 복호화 하는 방법에 대해 알아보았습니다. 많은 분들이 글을 읽으시고 하드코딩된 바이트 배열을 알아내는 방법에 대해서 많은 질문을 주셨습니다만,,
그 부분은 공식적으로 게시할 수 없는 점을 죄송하게 생각합니다..(문의주신 분들 몇 분에 대해서는 이메일로 회신을 드렸습니다. 현재까지 두 분께서 성공하셨다고 회신을 주셨습니다)
이번 글에서는 카카오톡에 저장된 이미지 파일의 복호화에 대해서 알아보도록 하겠습니다.
2. 이미지 파일(.cng) 위치
이번에는 카카오톡 대화파일(.edb)이 아닌 이미지 파일 복호화에 대해서 간략하게 알아보도록 하겠습니다.
카카오톡 pc버전은 이미지 파일을 아래와 같은 경로에 .cng 파일로 저장해 둡니다.
1 2 |
C:\Users\사용자명\AppData\Local\Kakao\KakaoTalk\users{userDir}\chat_data\cli\thumbnail C:\Users\사용자명\AppData\Local\Kakao\KakaoTalk\users{userDir}\chat_data\cli\2025 |
경로명에서 알 수 있는것처럼 thumbnail 경로에는 썸내일형태의 이미지가 있고 그 원본 이미지는 연도별 디렉토리로 분리되어 저장되어있습니다.
3. 이미지 파일(.cng) 복호화
이미지 파일도 edb파일과 같은 방법으로 복호화가 가능합니다. 아래는 기존의 edb 파일 복호화 코드를 cng파일용으로 변환한 코드 전체입니다.
※ cng파일의 경우 파일명이 암호화가 되어있어(파일명 복호화 방법은 별도 설명예정) 아래 코드에서는 파일이 수정된 날짜를 파일명에 반영하여 복호화된 파일의 이름을 변경하여 저장하도록 하였습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
from Cryptodome.Cipher import AES from Cryptodome.Util.Padding import pad from Cryptodome.Util.Padding import unpad import binascii import hashlib import base64 import os from datetime import datetime def generate_pragma(uuid, modelName, serialNumber): # 데이터 결합 (|로 구분) data = f"{uuid}|{modelName}|{serialNumber}" # 128비트 키와 16바이트 IV 설정 key = bytes.fromhex('하드코딩된 바이트키') # 주어진 128비트 키 iv = bytes([0] * 16) # IV를 0으로 설정 (16바이트) # AES 암호화 객체 생성 cipher = AES.new(key, AES.MODE_CBC, iv) # 데이터 패딩 및 암호화 ciphertext = cipher.encrypt(pad(data.encode(), AES.block_size)) # 암호화된 데이터를 16진수(hex)로 인코딩 ciphertext_hex = binascii.hexlify(ciphertext).decode() # 중간값 출력: 암호화된 데이터 print(f"Encrypted data (hex): {ciphertext_hex}") # SHA-512 해시 생성 sha512_hash = hashlib.sha512(ciphertext).digest() # 중간값 출력: SHA-512 해시값 sha512_hash_hex = binascii.hexlify(sha512_hash).decode() # 16진수로 변환 print(f"SHA-512 hash of encrypted data (hex): {sha512_hash_hex}") # SHA-512 해시 결과를 Base64로 인코딩 sha512_base64 = base64.b64encode(sha512_hash).decode() # 최종 출력: Base64 인코딩된 SHA-512 해시값 print(f"SHA-512 hash of encrypted data (Base64): {sha512_base64}") # Base64 인코딩된 SHA-512 해시값 리턴 return sha512_base64 def generate_key_and_iv(pragma, userId): # Concatenate pragma and userId to generate key key = pragma + userId key_hash = hashlib.md5(key.encode()).digest() iv = hashlib.md5(base64.b64encode(key_hash)).digest() # MD5 of Base64-encoded key_hash return key_hash, iv def aes128_cbc_pkcs7_decrypt(encThumb, key, iv): # Initialize AES cipher in CBC mode cipher = AES.new(key, AES.MODE_CBC, iv) # Decrypt the encrypted data decrypted_data = cipher.decrypt(encThumb) # Unpad the data (PKCS#7 padding) try: decrypted_data = unpad(decrypted_data, AES.block_size) except ValueError as e: print("Error during unpadding:", e) return None return decrypted_data def decrypt_database(key, iv, encDB): decDB = b'' # 데이터베이스를 빈 바이트 문자열로 초기화 i = 0 while i < len(encDB): # Decrypt each 4096 bytes block using AES128 CBC without padding cipher = AES.new(key, AES.MODE_CBC, iv) decrypted_data = cipher.decrypt(encDB[i:i+4096]) # Unpad the decrypted data # decrypted_data = unpad(decrypted_data, AES.block_size) # Append the decrypted data to decDB decDB += decrypted_data i += 4096 return decDB def read_encrypted_data_from_file(input_filename): with open(input_filename, 'rb') as f: encDB = f.read() return encDB def save_to_file(decDB, output_filename): with open(output_filename, 'wb') as f: f.write(decDB) # Step 3: Decrypt all files in a directory def decrypt_files_in_directory(directory, pragma, userId): key, iv = generate_key_and_iv(pragma, userId) # Loop through all files in the directory for filename in os.listdir(directory): file_path = os.path.join(directory, filename) # Only process files (ignore subdirectories) if os.path.isfile(file_path): print(f"Decrypting file: {filename}") # Read encrypted file with open(file_path, 'rb') as file: enc_data = file.read() # Decrypt file contents decrypted_data = aes128_cbc_pkcs7_decrypt(enc_data, key, iv) if decrypted_data: # Get the original file's last modified time modified_time = os.path.getmtime(file_path) modified_time_str = datetime.fromtimestamp(modified_time).strftime('%Y%m%d_%H%M%S') # Save decrypted data to a new file with the original modified time decrypted_file_name = f"decrypt_{modified_time_str}_{os.path.splitext(filename)[0]}.jpg" decrypted_file_path = os.path.join(directory, decrypted_file_name) with open(decrypted_file_path, 'wb') as dec_file: dec_file.write(decrypted_data) print(f"File decrypted and saved as: {decrypted_file_name}") else: print(f"Failed to decrypt file: {filename}") # 함수 호출 예시 uuid = "레지스트리에서 확인" modelName = "레지스트리에서 확인" serialNumber = "레지스트리에서 확인" pragma = generate_pragma(uuid, modelName, serialNumber) print("Generated Pragma: ", pragma) userId = "찾는방법 3편글 참조" directory = "../chat_data/cli/thumbnail" # cng파일이 있는 전체 경로 decrypt_files_in_directory(directory, pragma, userId) |
이것은 훌륭하고 완벽하게 작동합니다. CNG가 어떤 채팅 파일과 함께 갔는지 어떻게 확인할 수 있나요?
암호화된 CNG파일명을 확인하는 방법은 카카오톡edb 복호화 1편 https://deer.cafe24.com/%ec%b9%b4%ec%b9%b4%ec%98%a4%ed%86%a1-pc-%eb%8c%80%ed%99%94%eb%82%b4%ec%9a%a9-edb-%eb%b3%b5%ed%98%b8%ed%99%94/ 에서 참고했던 논문의
59페이지(우측상단에 페이지 표시됨)의 Fig.14, 15, 16을 확인하시면 됩니다.
간단히 요약해 드리면,
1. 먼저 확인하고자 하는 EDB파일(대화기록 데이터 베이스 파일)을 복호화 후 attatchment 컬럼에서 이미지나 동영상의 토큰값 알아내기
※ 토큰값은 이미지는 k, 동영상 tk라는 파라미터로 저장됨
2. 논문내용을 보면 “하드 코딩된 바이트 배열에 대해 MD5 해싱을 수행
하면 key가 된다. key에 대해 Base64 인코딩 수 행 후 MD5 해싱을 수행하면 iv가 된다. 생성한
key, iv 쌍을 이용하여 token에 대해 AES 암호화수행 후 SHA1 해싱을 수행하면 암호화된 썸네일
파일명이 생성된다”라고 되어 있고 아래와 같이 알고리즘을 제공하고 있습니다.
1: key ← hardcoded byte array
2: key ← MD5(key)
3: iv ← MD5(Base64.encode(key))
4: encName ← AES128/CBC/PKCS#7_ENC(token.getBytes(), key, iv)
5: encName ← SHA1(encName)
6: return toHexString(encName)
3. 위 알고리즘을 챗지피티 등에 입력하여 파이썬 코드 등으로 변환하여
파일명 찾기 코드 작성