Forensics

[포렌식] 카카오톡 수정된 메시지 및 삭제된 메시지 분석 및 복구 (25.10.07)

pental 2025. 10. 7. 01:35

“지금 보낸 그 메시지, ‘수정’ 버튼 한 번이면 싹 바뀔 수 있다.”

최근 카카오톡의 대대적 업데이트 이후, 메시지 수정 기능이 새롭게 도입되면서 많은 이용자들이 기대와 우려 사이에 놓여 있다. 특히 이 기능이 “말 바꾸기” 또는 “증거 삭제”의 수단으로 악용될 가능성도 제기되며, 카카오톡이 가진 커뮤니케이션의 신뢰성에도 균열이 생길지 모른다는 목소리가 커지고 있다.

실제로 일부 이용자들은 “그럼 앞으로 카톡을 증거로 사용할 수 없겠네… 신뢰성 떨어진다” 라는 반응을 보이기도 했는데 이처럼 메시지 수정 기능은 단순한 편의성의 연장선이 아니라, 커뮤니케이션의 본질과 책임의 경계를 다시 묻게 만드는 변화다.

이 글에서는 카카오톡 업데이트의 핵심 변화와 더불어, 메시지 수정 기능이 초래할 수 있는 문제점들을 짚어보고자 한다.

먼저 최근 추가된 수정 기능에 대해서 시나리오를 하나 세워보았다.

먼저 A가 상대방(이하 B라고 칭한다)에게 "나 10만원만 한국은행 1234-5678-90 으로 보내주라" 라고 보낸 메시지이다. 이부분에서는 정상적으로 10만원을 빌려달라는 메시지가 정상적으로 보이게 된다. 

B는 A가 10만원을 보내달라는 메시지를 받고, 그 즉시 10만원을 송금한 것으로 확인된다. 하지만 이제 A가 이 문자 메시지를 변경하는 것이다.

물론 "수정됨" 이라는 문구와 함께, 메시지의 내용이 10만원에서 1만원으로 변경된 것을 확인 할 수 있으며, 이 부분에 대해서는 큰 문제가 발생할 수 있는 소지가 있다.

문제는 단순히 10만원 → 1만원이 아니다. 만약 과거에 “500만원을 빌려달라”는 메시지가 있었는데, 이후 “50만원”으로 변경된다면 어떨까?

먼저 금전거래 증거로 제출된 메시지가 법적 분쟁 상황에서 효력을 상실할 수 있다. 또한, “수정됨”이라는 표식이 있더라도 원문 내용이 확인되지 않는 이상, 상대방에게 불리하게 작용할 수 있다. 결과적으로 카카오톡 대화의 증거 신뢰성이 흔들리며, 분쟁 상황에서 악용될 소지가 커진다.

나는 이 부분에 초점을 두고 분석을 진행하였다. 분석은 iOS 환경을 이용하여 진행하였으며, 아래는 분석에 관한 내용이다.

분석 환경의 경우 Mac + Python 3.13.7 버전을 사용하였으며 B의 휴대전화를 사용하여 분석을 진행한다.

B의 카카오톡 버전은 25.8.4를 사용하고 있다.

먼저 아이폰 논리백업을 통해서 카카오톡 채팅 데이터베이스를 추출하였다. 기존 포스팅에서 언급한것 처럼 아래 논문을 사용하여, 복호화 작업을 진행하였다.

https://pental.tistory.com/538

 

[포렌식] 아이폰 카카오톡 복호화 분석 및 구현

본 글은 언제든지 비공개 되거나, 삭제될수 있음을 미리 알려드립니다. (뭐,, 카카오톡 본사에서 글 내려라 하지 않는 이상 없어지진 않지 않을까...?)모바일 메신저는 디지털 포렌식에서 핵심적

blog.system32.kr

논리 백업 파일에서 카카오톡 데이터베이스 추출 과정에 대해서는 생략한다. (자세한 과정은 이전 포스팅 참고)

이번 분석에서는 Message.sqlite 파일의 message 테이블을 활용하여, userid와 message 컬럼을 기준으로 단순 메시지 복호화를 진행하였다.

먼저 가장 크게 눈에 띄는 부분은 "나 10만원만 한국은행 1234-5678-90으로 보내주라"라고 A가 B에게 보냈지만, 실질적으로 B의 휴대전화에서 남는 기록은 "나 1만원만 한국은행 1234-5678-90으로 보내주라" 라고 수정된 메시지만 남게된다.

즉, 수정 이후에는 변경된 메시지 내용만 보이게 된다.

이때 데이터베이스에는 다음과 같은 로그가 남는다.

{"logId":3681151639662792706,"targetRevision":1,"hidden":true,"feedType":25}

여기서 targetRevision: 1 은 메시지가 수정되었음을 의미한다. 그리고 logId직전 메시지를 가리키는 지표 역할을 한다.

직전의 메시지를 나타내는 지표이다. 사용한 코드는 다음과 같다.

conn = sqlite3.connect("after")
cursor = conn.cursor()
cursor.execute("SELECT prevId, userid, message FROM message WHERE prevId = 3681151639662792706")
row = cursor.fetchall()
print(decrypt(row[0][1], row[0][2]))

그렇다면 수정된 메시지는 원래 내용을 확인할수 없는것인가? 답은 원본 메시지도 확인 할 수 있다는 것이다.

카카오톡에서는 위에서 언급한 가상의 시나리오 처럼 "수정" 기능을 악용하는 소지를 방지하기 위해 extrainfo 칼럼에 원본 메시지를 저장하고 있다.

{
  "scrapURL": "N/A",
  "cv": "1.0",
  "modifyHistory": [
    {
      "revision": 0,
      "message": "PsdqQvX+keRqNW0vIIklOi6/CUsKnpXQRmri78qnRBHiWM9pViqc/PJAWOKxDfZ2\r\n/PSZ5aM/bTTY/AX+Lb/h/A==",
      "encrypted": true
    }
  ],
  "revision": 1
}

위 내용에서 먼저 눈에 띄는것은 다른 메시지와는 다르게 revision값이 1로 변경되어 있다는 점이다.

다른 평범한 메시지의 경우 다음과 같은 extraInfo를 가지고 있다.

{"cv":"1.0","revision":0,"scrapURL":"N\/A"}
{"scrapURL":"N\/A","cv":"1.0"}
{"scrapURL":"N\/A","revision":0,"cv":"1.0","byHost":false}

위 modifyHistory 부분에서는 revision 키를 인덱스로 사용하여, 수정이 여러번 되어도 그 내용을 기록하는 형태를 가지고 있다. message 키에서는  \, \r, \r 등의 개행 문자 등은 처리하고 userid를 사용하여 복호화 하면 기존의 메시지를 확인 할 수 있다.

print(decrypt(123456789, "PsdqQvX+keRqNW0vIIklOi6/CUsKnpXQRmri78qnRBHiWM9pViqc/PJAWOKxDfZ2/PSZ5aM/bTTY/AX+Lb/h/A=="))

위에서 사용한 123456789는 가상의 userId이며, 실제 복호화에는 실제 userId를 사용해야한다.

그 결과 원본 메시지에서는 "나 10만원만 한국은행 1234-5678-90 으로 보내주라" 라는 메시지를 확인 할 수 있다.

즉, 카카오톡은 단순히 메시지를 덮어쓰는 방식이 아니라, extraInfo수정 이력(History)을 함께 저장하여 원본 추적이 가능하도록 설계되어 있다.

결론적으로, 위의 예시와 같이 메시지가 “수정”된 경우에도 B가 탈퇴하거나 대화방을 완전히 나가지 않는 이상, 혹은 특정 대화를 직접 삭제하지 않는 이상, 원본 메시지 확인이 가능하다는 점이다. 다시 말해, 설령 사용자가 발뺌을 하더라도 데이터베이스 상에는 안전장치가 마련되어 있는 셈이다.

다만 이러한 원본 추적 과정은 일반 사용자가 바로 확인할 수 있는 것이 아니며, 디지털 포렌식 분석이나 법적 증거 제출 절차를 거쳐야만 한다. 따라서 실제 분쟁 상황에서는 시간과 비용이 소요될 수 있다는 한계도 존재한다.


번외로, 삭제된 메시지가 실제로 데이터베이스에서는 어떻게 남는지 확인해보았다. (사실 이전 포스팅에서 다룬 내용이기도 하다.)

위 사진은 삭제하기 전 사진이다. (정상적으로 메시지가 존재하며, 일반 메시지처럼 복호화 가능하다.)

위 사진은 삭제한 후 사진이다. (화면상에는 “메시지가 삭제되었습니다.”라는 문구로 표시된다.)

그럼 이 메시지들은 데이터베이스에서 어떻게 처리되는지 확인해보자.

위에서 언급한 포스팅 내에 있는 논문에서도 언급 됐듯, type 칼럼이 16385로 변경되며, message원본값은 변경되지 않은 상태이다. 즉, type 16835인 경우 프론트단에서 "메시지가 삭제되었습니다."로 표시해주는것 같다는 추측이다.

위 사진과 같이 삭제된 메시지는 모두 보이게 되며, 단 로그로 "hidden":true가 추가된다. (삭제한 시점을 기반으로) 이 경우 type은 0이다.

위에서 따로 언급은 하지 않았지만, type 26의 경우 "답장" 기능에 대한 요청이다. 

conn = sqlite3.connect("after")
cursor = conn.cursor()
cursor.execute("SELECT * FROM message WHERE message = 'jXYeIo8wBkxZ7eGCRG3LmoAhjWDBg2qETWRHkyFJ4Pk='")
rows = cursor.fetchall()
print(rows)
pental@pentalui-MacBookAir kakaotalk-decryption % /opt/homebrew/bin/python3 /Users/pental/Desktop/kakaotalk-decryption/test.py
[(16, 0, None, 1, None, '', 3681152882208575489, None, None, None, 781457625, None, '{"revision":0,"cv":"1.0"}', 1759764825.827979, 3681152932582166529, 26, 1759762522, 781457625.824429, 'jXYeIo8wBkxZ7eGCRG3LmoAhjWDBg2qETWRHkyFJ4Pk=', None, 0, 384935297767633, None, None, None, None, None, 'L/+N0joqNZxbQulWgmdTGexNYOwlzWfQPTVUr6dtj8q9WmWHBGlMu8+H6MvVZeea\r\nISS/cr6EsPq481909nqa8NvEmuukEGVmPjnhQ28uN+JiRwn+JuurTvWRhEoj7FVi\r\n5FqlQZI8CTSJ27BwcMjPm1+x+fTxiD8ewK0ZYzHHpE08P7g1an2RCJ5bqo2VMbvE\r\nxvHiLYYoUqpcacPcFX9K5g==', 0, 123456789, 1, None)]

이때 message 테이블에서 확인한 주요 변화는 다음과 같다.

1. type 값 변경

  • 삭제된 메시지는 type 값이 16385로 바뀌며,
  • 메시지 원본 값은 그대로 남아 있다.
  • 즉, type = 16835인 경우 프론트단(클라이언트)에서만
  • “메시지가 삭제되었습니다.” 라는 문구를 표시한다고 추측할 수 있다.

2. hidden 플래그

  • 삭제된 메시지는 log에 "hidden": true 값이 추가된다.
  • 이 플래그는 삭제 시점을 기준으로 표시 여부를 제어하는 역할을 하는 것으로 보인다.
  • 이 경우 type 값은 0으로 기록된다.

3. 기타 type 값

  • type = 26 은 “답장(reply)” 기능을 나타낸다.

이번 분석을 통해 확인할 수 있었던 사실은 크게 두 가지다.

1. 메시지 수정 기능

  • 겉으로는 “수정됨”이라는 표시와 함께 변경된 내용만 보이지만,
  • 내부적으로는 extraInfo 컬럼과 modifyHistory를 통해 원본 메시지가 그대로 저장되고 있어 복구가 가능하다.
  • 다만, 일반 사용자가 직접 확인할 수는 없고 디지털 포렌식 분석 과정을 거쳐야만 원문을 확인할 수 있다.

2. 메시지 삭제 기능

  • 화면에서는 “메시지가 삭제되었습니다.”라는 문구가 표시되지만,
  • 데이터베이스에서는 type 값과 hidden 플래그로만 상태가 바뀌고, 원본 메시지는 여전히 존재한다.
  • 따라서 삭제된 메시지 역시 복호화를 통해 확인할 수 있다.

결론적으로, 카카오톡은 사용자 편의를 위해 메시지 수정·삭제 기능을 제공하지만, 데이터베이스 차원에서는 안전장치(원본 보존 기록) 를 두어 원본 메시지 추적이 가능하도록 설계되어 있다.

이는 “말 바꾸기”나 “증거 인멸”과 같은 악용 가능성을 일정 부분 방지하는 장치가 되지만, 실제 법적 증거로 활용하려면 전문가의 분석, 시간, 비용이 필요하다는 점에서 여전히 한계가 존재한다.


결국 카카오톡 대화는 편리한 소통 도구이자 동시에 법적·사회적 증거로서 중요한 가치를 가진다. 그렇기에 사용자는 수정·삭제 기능을 가볍게 생각하기보다, 책임성과 신뢰성을 전제로 한 커뮤니케이션이 필요하다고 생각된다.