Google Drive for Windows client artifacts analysis - 2
※ 해당 글은 이종찬 연구원이 작성한 글입니다.
앞선 포스팅에서 정리한 실험 항목을 바탕으로 검증을 진행했다. 실험 전 구글 드라이브 서버에는 다음과 같은 구조로 파일 및 폴더를 설정했다. 이는 이전 포스팅에서 정리한 동기화 폴더 설정 : 구글 드라이브 서버 → 로컬 폴더와 관련 있다. 즉, 앞의 설정을 통해 동기화 시 서버 내의 파일 및 폴더가 설정된 로컬 폴더에 저장되는 구조이다.
# 구글 드라이브 서버 내 파일 및 폴더 구조 (구글 드라이브 서버 → 로컬 폴더)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | . (root directory) │ ├── A │ ├── a │ │ └── 가.txt │ └── 1.txt │ ├── B │ ├── b │ │ └── 나.txt │ └── 2.txt │ └── C ├── c │ └── 다.txt └── 3.txt |
마찬가지로 동기화 폴더 설정 : 로컬 폴더 → 구글 드라이브 서버를 확인하기 위해 동기화 할 로컬 폴더를 아래와 같이 설정했다.
# 로컬 폴더 구조 (로컬 폴더 → 구글 드라이브 서버)
1 2 3 4 | . (root directory) │ └── bck └── backup.txt |
구글 드라이브 서버 → 로컬 폴더는 기본 경로(%USERPROFILE%/Google 드라이브)로 설정했으며, 로컬 폴더 → 구글 드라이브 서버는 별도의 폴더(%USERPROFILE%/backup_folder)로 설정했다. 또한 저장매체 연결 흔적을 확인하기 위해 볼륨 이름이 “PLAINBIT”인 NTFS로 포맷 한 USB 메모리를 사용했다.
# 로그인 관련 흔적
설치 직후 레지스트리에는 클라이언트 버전과 설정 파일의 위치와 관련된 흔적이 다음의 경로에 남는다.
- NTUSER.DAT/Software/Google/Drive
이때 로그인을 진행하면 위의 레지스트리 키 하위에 다음과 같은 형태의 Value 가 생성된다.
위의 레지스트리 Value 중 로그인 정보와 관련 있는 것은 다음과 같다.
- "machine_{Some_String_1}" = dword:"{Some_String_2}"
- "OAuthToken_{Some_String_1}" = dword:"{Some_String_2}"
[Some_String_1] 은 운영체제가 다르더라도 같은 계정으로 로그인 했다면 레지스트리에 동일하게 생성되며, [Some_String_2] 는 서로 다른 운영체제에 같은 계정을 사용한 경우 앞에서 부터 일부만 같으며 그 이후는 다르다. 이 문자열을 활용하면 서로 다른 호스트에서 발견한 구글 드라이브 계정의 동일성을 비교할 수 있다.
특히 “OAuthToken_” 을 Prefix로 갖는 레지스트리 Value의 Data는 Base64로 인코딩 값이다. 이 값을 디코딩하면 16진수로 다음과 같은 형태를 확인할 수 있다.
위의 그림에서 음영 처리된 부분의 16진수 값(’01 00 00 00 D0 8C 9D DF 01 15 D1 11 8C 7A 00 C0 4F C2 97 EB’)은 Windows DPAPI 를 활용해 Encrypt 한 값이 가지는 시그니처이다.
Windows DPAPI란 Windows 운영체제 레벨에서 사용하는 대칭키 암호 방식으로, 사용자의 로그온 증명을 활용하기 때문에 일반적으로 Windows 운영체제에 로그인이 된 라이브 상태에서만 복호화를 수행할 수 있다.
위 레지스트리 Data를 실험 환경에서 DPAPI 로 복호화 하면(관련도구) 다음과 같이 OAuthToken 과 관련 있는 데이터를 확인할 수 있다. OAuthToken 값은 호스트가 다르더라도 계정이 같다면 같은 토큰값을 사용한다.
레지스트리에 남는 흔적은 결과적으로, 해당 PC에서는 구글 드라이브 클라이언트로 로그인한 사실을 알 수 있다. 또한 서로 다른 PC에 설치되어 있는 구글 드라이브 클라이언트가 같은 계정으로 로그인 되었다는 사실의 근거로 활용할 수 있다.
Google 로그인 계정과 관련된 직접적인 정보는 다음의 SQLite 파일에서 확인할 수 있다.
- %UserProfile%\AppData\Local\Google\Drive\global.db
해당 SQLite DB 파일에서 global_preference 테이블의 preference_value 컬럼에 다음과 같은 형태로 저장된다.
그밖에 다음 경로에 있는 SQLite 파일에도 계정 관련 흔적이 남는다.
- %UserProfile%\AppData\Local\Google\Drive\user_default\sync_config.db
sync_config.db 에는 data 테이블 하나만 존재한다. 이 테이블에서 계정 정보와 관련된 내용은 다음과 같다. entry_key 는 테이블의 컬럼명이다.
따라서 위의 두 SQLite DB 를 통해 구글 드라이브 클라이언트에 어떤 계정으로 로그인했는지 알 수 있다.
# 동기화 폴더 내 파일 및 폴더 관련 흔적
위에서 확인한 sync_config.db 의 data 테이블은 구글 드라이브 클라이언트가 활용하는 설정값들이 저장되어 있다. 이 설정 중에서 동기화 폴더와 관련된 흔적은 다음과 같다.
동기화 폴더 내 파일 및 폴더와 관련하여 더 상세한 흔적은 다음의 SQLite 파일에서 확인할 수 있다.
- %UserProfile%\AppData\Local\Google\Drive\user_default\snapshot.db
snapshot.db 는 cloud_entry, cloud_relations, local_entry, local_relations, mapping, pre_mapping, voloume_info 등의 테이블을 포함하고 있다.
cloud_entry, cloud_relations 테이블은 구글 클라우드 서버 내에 있는 파일 및 폴더 관련 정보를 저장한다. cloud_entry 테이블은 구글 드라이브 서버 내에 있는 파일 및 폴더 목록과 메타데이터를 저장하며, cloud_relations 테이블을 통해 서버 내에 저장되어 있는 파일 및 폴더의 경로 정보를 확인할 수 있다. 각 테이블의 컬럼 정보는 아래의 표를 참고하자.
local_entry, local_relations 테이블은 로컬로 동기화 된 항목들에 대한 정보를 저장하고 있다. local_entry 테이블은 로컬에 동기화 된 파일 및 폴더 목록과 메타데이터를 저장하며, local_relations 테이블을 통해 로컬로 동기화 된 파일 및 폴더의 경로 정보를 확인할 수 있다. 각 테이블의 컬럼 정보는 아래의 표를 참고하자.
mapping 테이블은 구글 드라이브 서버에 저장된 파일과 로컬 동기화 폴더에 저장된 파일간의 연결 정보를 저장한다. 즉, 테이블의 관계로 본다면 cloud_relation과 local_relation 테이블이 서로 연결된 형태이다. 자세한 테이블의 정보는 다음과 같다.
이상의 여러 테이블에 남는 흔적은 동기화 후 구글 드라이브 서버와 로컬 각각에 동기화 된 파일 및 폴더의 목록이므로, 서버로 부터 다운로드 받은 파일 및 폴더 혹은 서버로 업로드 된 파일 및 폴더의 정보를 알 수 있다.
또한 전체 경로 경로와 동기화 된 파일의 MD5 해시값도 확인할 수 있어 원본 파일이 없더라도 추후 확보 된다면 원본성을 비교할 수 있다. 하지만 로컬에서 업로드 된 파일인지 혹은 로컬로 다운로드 된 파일인지는 알 수 없다. 그리고 파일이 지워진 경우 테이블의 레코드에서도 삭제되기 때문에 흔적을 분석하는데 다소 한계가 존재한다.
# 로컬 볼륨 관련 흔적
한편 로컬 동기화 폴더가 속하는 볼륨에 대한 정보를 알 수 있다. snapshot.db 의 volume_info 테이블은 다음과 같은 정보를 저장한다.
volume_info 테이블의 정보는 동기화 폴더가 서로 다른 볼륨에 존재 할 경우 이를 구분하는 데에 활용할 수 있다. local_entry 테이블의 volume 컬럼에 남는 볼륨 시리얼 번호와 비교하면 가능하다.
# 이동식 저장매체 흔적
앞선 포스팅에서 구글 드라이브의 기능 중 이동식 저장 매체 백업 기능에 대해 확인했다. 이 기능은 옵션으로 켜고 끌 수 있는데, 위의 sync_config.db 의 data 테이블을 확인하면 다음과 같은 설정으로 켜고 끄는 것을 확인할 수 있다.
이동식 저장매체 연결 흔적에 대한 상세한 정보는 다음의 SQLite 파일을 통해 확인할 수 있다.
- %UserProfile%\AppData\Local\Google\Drive\user_default\device_db.db
device_db.db 는 device_files, device_upload_info, external_devices, pending_files 테이블이 존재한다. 이 중 흔적을 확인할 수 있는 것은 device_files 와 external_devices 두 테이블이다.
구글 드라이브 사용 중 이동식 저장매체를 연결하게 되면, 매체에 저장된 파일에 대해 백업 기능을 사용할지 묻는다. 이때 백업을 활성화하면 구글 드라이브 서버로 저장매체 내 파일 및 폴더가 업로드 된다. device_files 테이블은 저장매체 내 파일 및 폴더가 백업되는 경우 그 흔적을 확인할 수 있다.
device_files 테이블은 저장매체의 백업 기능을 활성화 해야만 흔적 확인이 가능하다. 이와 다르게 external_devices 테이블은 저장매체가 연결이 되기만 해도 그 흔적이 남는다. 테이블에 남는 자세한 흔적은 다음과 같다.
# 동기화 관련 흔적
동기화 관련 흔적은 구글 드라이브 서버와 로컬 내 폴더 간 동기화 시 업로드 및 다운로드가 수행된다. 이 내역을 로그로 저장한 파일이 sync_log.log 이다.
sync_log.log 로그 파일이 저장되는 경로는 다음과 같다.
- %UserProfile%\AppData\Local\Google\Drive\user_default\sync_log.log
위의 경로의 로그는 문자열 형태로 저장되며, 텍스트 에디터 등을 통해 확인해보면 아래와 같은 형태의 로그를 살펴 볼 수 있다.
아래의 실험은 이 파일에 남는 로그의 형태를 케이스 별로 파악하기 위해 여러 상황을 가정하고 진행하였다. 로그로 기록되는 내용은 실시간으로 확인하기 위해 tail -f 명령어를 사용하였다.
# 파일 업로드 관련 흔적
로컬에 파일이 생성되는 경우 다음과 같은 형태의 로그를 확인할 수 있다.
1. 파일시스템 내 변화 감지
1 2 3 4 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... tree_scanner.py ... Starting primary scan of xx paths. yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... tree_scanner.py ... Dirty: xx Scan: xx Cor: xx ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... aggregator.py ... Received change FSChange(Direction.UPLOAD, Acion.CREATE, ..., path='{생성된 파일의 경로}'), ...) |
2. worker – 동작 수행 시작
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker starting on [FSChange(Direction.UPLOAD, Acion.CREATE, ..., path='{생성된 파일이 위치한 폴더}', name='{생성된 파일이름}'), ...)] |
3. worker – 서버로 업로드 요청
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive request: InsertFile(... filename='{생성된 파일의 경로}'..., doc_id='{생성된 파일의 doc_id}') ... {업로드 계정} |
4. worker – 서버로 업로드 결과
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive Response: File(..., md5_checksum='{생성된 파일의 MD5 해쉬값}', ... , doc_id='{생성된 파일의 doc_id}', ...) |
5. worker – 동작 종료
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker successfully completed [FSChange(Direction.UPLOAD, Action.CREATE, ..., path='{생성된 파일이 위치한 폴더}', name='{생성된 파일이름}', ...) |
즉, 동작이 종료되는 시점인 다섯번째 형태의 로그가 남는다면, 로컬에서 생성된 파일이 구글 드라이브 서버로 업로드 된 흔적이라고 판단 가능하다.
# 로컬의 파일 열람 및 수정 후 저장하는 경우
로컬 파일을 열람하는 경우에는 별도의 로그를 남기지 않지만, 수정 후 저장하는 경우에는 로그를 생성한다. 로그의 형태와 흐름은 파일을 생성하는 경우와 거의 유사하며 주로 로그에서 정의하는 Action 항목이 Action.CREATE 에서 Action.MODIFY 로 바뀐다.
1. 파일시스템 내 변화 감지
1 2 3 4 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... tree_scanner.py ... Starting primary scan of xx paths. yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... tree_scanner.py ... Dirty: xx Scan: xx Cor: xx ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... aggregator.py ... Received change FSChange(Direction.UPLOAD, Acion.MODIFY, ..., path='{수정된 파일의 경로}'), ...) |
2. worker – 동작 수행 시작
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker starting on [FSChange(Direction.UPLOAD, Acion.MODIFY, ..., path='{수정된 파일이 위치한 폴더}', name='{수정된 파일이름}'), ...)] |
3. worker – 서버로 업로드 요청
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive request: UpdateFile(... filename='{수정된 파일의 경로}'..., doc_id='{수정된 파일의 doc_id}') ... {업로드 계정} |
4. worker – 서버로 업로드 결과
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive Response: ..., md5_checksum='{수정된 파일의 MD5 해쉬값}', ... , doc_id='{수정된 파일의 doc_id}', ... |
5. worker – 동작 종료
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker successfully completed [FSChange(Direction.UPLOAD, Action.MODIFY, ..., path='{수정된 파일이 위치한 폴더}', name='{수정된 파일이름}', ...) |
# 파일 다운로드 관련 흔적
파일 다운로드와 관련된 로그는 크게 드라이브 서버의 변화, 파일시스템에 반영 두 부분으로 나눌 수 있다.
먼저, 로컬에 존재하지 않는 파일이 서버에 생성되는 경우 다음과 같은 형태의 로그를 확인할 수 있다.
1. 서버 내 변화 감지 및 변화 요인 파악
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... cloud_watcher.py ... Getting changes; ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_batch.py ... drive - '{구글 드라이브 계정}' - BatchRequest with x inner requiests: ListChanges(..., tags=Reason.SYNC_PUSHED_CHANGES, ...) ... |
2. 서버로 변화된 항목 요청
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... discovery.py ... URL being requests: GET ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_batch.py ... Drive batch completed: ... |
3. 파일시스템 변화 감지
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... aggregator.py ... Received change FSChange(Direction.DOWNLOAD, Acion.CREATE, ..., doc_id='{파일의 doc_id}'), checksum={파일의 MD5 해시}, mapped={다운로드 후 파일이 위치할 경로}...) |
4. worker – 동작 수행 시작
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker starting on [FSChange(Direction.DOWNLOAD, Acion.CREATE, ..., path='{생성된 파일이 위치할 폴더}', name='{생성된 파일이름}'), ...)] |
5. worker – 서버로 다운로드 요청
1 2 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive request: DownloadBlob(... filepath='{로컬에 임시로 저장할 파일의 경로}'..., doc_id='{파일의 doc_id}') ... {다운로드 계정} yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... downloads.py ... Downloading {구글 API 서버 URL} to {로컬에 임시로 저장할 파일 경로} |
임시 저장 폴더는 구글드라이브 서버 → 로컬 폴더의 기본 경로(%USERPROFILE%/Google 드라이브) 의 .tmp.drivedownload 폴더이다.
6. worker – 서버로 부터 다운로드 결과
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive Response: ..., md5_checksum='{생성된 파일의 MD5 해쉬값}', ... , doc_id='{생성된 파일의 doc_id}', ... |
7. worker – 동작 종료
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker successfully completed [FSChange(Direction.DOWNLOAD, Action.CREATE, ..., path='{생성된 파일이 위치한 폴더}', name='{생성된 파일이름}', ...) |
다음으로 로컬에 존재하는 파일이 서버에서 수정 된 경우 다음과 같은 형태의 로그를 확인할 수 있다.
1. 서버 내 변화 감지 및 변화 요인 파악
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... cloud_watcher.py ... Getting changes; ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_batch.py ... drive - '{구글 드라이브 계정}' - BatchRequest with x inner requiests: ListChanges(..., tags=Reason.SYNC_PUSHED_CHANGES, ...) ... |
2. 서버로 변화된 항목 요청
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... discovery.py ... URL being requests: GET ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_batch.py ... Drive batch completed: ... |
3. 파일시스템 변화 감지
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... aggregator.py ... Received change FSChange(Direction.DOWNLOAD, Acion.MODIFY, ..., mapped={수정된 파일이 위치할 경로}, ..., doc_id='{파일의 doc_id}'), , ...) |
4. worker – 동작 수행 시작
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker starting on [FSChange(Direction.DOWNLOAD, Acion.MODIFY, ..., path='{수정된 파일이 위치할 폴더}', name='{수정된 파일이름}'), ...)] |
5. worker – 서버로 다운로드 요청
1 2 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive request: DownloadBlob(... filepath='{로컬에 임시로 저장할 파일의 경로}'..., doc_id='{파일의 doc_id}') ... {다운로드 계정} yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... downloads.py ... Worker statring on [FSChangeownloading {구글 API 서버 URL} to {로컬에 임시로 저장할 파일 경로}] |
6. worker – 서버로 부터 다운로드 결과
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive Response: ..., md5_checksum='{수정된 파일의 MD5 해쉬값}', ... , doc_id='{파일의 doc_id}', ... |
파일이 수정되더라도 처음에 부여받은 doc_id는 그대로 유지된다.
7. worker – 동작 종료
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker successfully completed [FSChange(Direction.DOWNLOAD, Action.MODIFY, ..., path='{수정된 파일이 위치한 폴더}', name='{수정된 파일이름}', ...) |
# 파일 삭제 관련 흔적
로컬에 존재하지 하는 파일이 서버에 삭제된 경우 다음과 같은 형태의 로그를 확인할 수 있다.
1. 서버 내 변화 감지 및 변화 요인 파악
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... cloud_watcher.py ... Getting changes; ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_batch.py ... drive - '{구글 드라이브 계정}' - BatchRequest with x inner requiests: ListChanges(..., tags=Reason.SYNC_PUSHED_CHANGES, ...) ... |
2. 서버로 변화된 항목 요청
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... discovery.py ... URL being requests: GET ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_batch.py ... Drive batch completed: ... |
3. 파일시스템 변화 감지
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... aggregator.py ... Received change FSChange(Direction.DOWNLOAD, Acion.DELETE, ..., mapped={삭제할 파일이 위치한 경로}, ..., doc_id='{삭제할 파일의 doc_id}'), ...) |
4. worker – 동작 수행 시작
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker starting on [FSChange(Direction.DOWNLOAD, Acion.DELETE, ..., mapped='{삭제할 파일이 위치한 폴더}', doc_id='{삭제할 파일의 doc_id}', ...)] |
5. worker – 파일 삭제
1 2 3 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive request: GetItem(tags=Reason.DELETE_OBJECT, ... , doc_id='{삭제할 파일의 doc_id}', ...) ... {구글 계정} ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... downloads.py ... Using path {로컬에 삭제 할 파일 경로} for download delete of local_id ... doc_id={삭제할 파일 경로} |
6. worker – 동작 종료
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker successfully completed [FSChange(Direction.DOWNLOAD, Action.DELETE, ..., mapped={삭제한 파일이 위치했던 경로}, ...) |
로컬에 존재하는 파일이 삭제된 경우 다음과 같은 형태의 로그를 확인할 수 있다.
1. 파일시스템 내 변화 감지
1 2 3 4 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... tree_scanner.py ... Starting primary scan of xx paths. yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... tree_scanner.py ... Dirty: xx Scan: xx Cor: xx ... ... yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... aggregator.py ... Received change FSChange(Direction.UPLOAD, Acion.DELETE, ..., path='{삭제할 파일이 위치한 폴더}', name='{삭제할 파일의 이름}' ...) |
2. worker – 동작 수행 시작
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker starting on [FSChange(Direction.UPLOAD, Acion.DELETE, ..., path='{삭제할 파일이 위치한 폴더}', name='{삭제할 파일의 이름}', ...)] |
3. worker – 파일 삭제
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... drive_request.py ... Drive request: TrashItem(..., tags=Reason.TRASH_OBJECT, ... , doc_id='{삭제할 파일의 doc_id}', ...) ... {구글 계정} |
4. worker – 동작 종료
1 | yyyy-MM-dd hh:mm:ss +(timezoone) INFO ... worker.py ... Worker successfully completed [FSChange(Direction.UPLOAD, Action.DELETE, ..., path='{삭제한 파일이 위치했던 경로}', name='{삭제한 파일의 이름}'...) |
# sync_log.log 분석 정리
로그 분석을 통해 동기화 기능은 worker 를 중심으로 운영되는 것을 알 수 있다. 즉, sync_log.log 는 worker 동작이 종료되는 것을 중점적으로 분석해야 한다. 특히 종료 시점에 남는 FSChange 항목을 정리하면 다음과 같다.
# 맺음글
본 포스팅에서 다룬 실험 결과와 같이, Windows 호스트 에서 구글 드라이브 클라이언트를 사용했다면 포렌식 분석가 관점에서 의미있는 흔적을 발견할 수 있다. 계정 로그인과 관련하여 로그인 토큰과 구글 계정에 대한 흔적이 남으며, 이를 통해 다른 시스템에서 같은 계정으로 로그인이 되었는지, 어떤 계정으로 로그인이 이루어졌는지 비교 가능하다.
또한 구글 드라이브 서버와 클라이언트에 동기화 된 파일 및 폴더에 대해 목록화할 수 있으며, 이는 동기화 로그와 연관 분석하여 클라이언트를 통해 업로드 및 다운로드 된 파일에 대해 확인할 수 있다. 이동식 저장매체의 경우 연결흔적이 남는 한편, 조건이 갖춰진 경우 저장매체 내 존재 했던 파일에 대한 목록 또한 확보할 수 있다. 분석가는 이를 종합적으로 포렌식 관점에서의 정보 유출 가능성을 고려해야 한다.
구글 드라이브는 위에서 밝힌 기능 이외에도 여러 계정 간 동시 수정, 계정 및 URL 공유 등의 기능을 활용 가능하므로 본 글에서 다루지 못한 케이스가 존재한다. 이후에는 이에 대한 지속적인 연구가 필요하다.
실험의 결과를 바탕으로 개발된 분석도구는 링크를 통해 공개 할 예정이다. 분석에 도움이 되길 바란다.