|
#!/usr/bin/env python3 |
|
# -*- coding: utf-8 -*- |
|
|
|
""" ReadChromeCookies.py: chrome cookie读取工具 |
|
__email__ = "[email protected]" |
|
__date__ = "2022-04-20" |
|
__version__ = "1.0.0" |
|
""" |
|
|
|
import base64 |
|
import json |
|
import os |
|
import sqlite3 |
|
|
|
''' python 依赖库 |
|
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pywin32 |
|
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple cryptography |
|
''' |
|
from win32crypt import CryptUnprotectData |
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM |
|
|
|
''' Chrome Cookie 存放说明 |
|
1、chrome80以前的版本的加解密机制 |
|
chrome80以前的版本的加解密是直接通过DPAPI来进行加解密的: |
|
DPAPI是Windows系统级对数据进行加解密的一种接口,用户无需自实现加解密代码,DPAPI提供了经过验证的高质量加解密算法,提供了用户接口对密钥存储数据加解密,实现透明并提供较高的安全保证 |
|
DPAPI提供了两个用户态接口:CryptProtectData加密数据、CryptUnprotectData解密数据。 |
|
因此chrome80以前的版本可以直接调用CryptUnprotectData对加密数据进行解密。 |
|
2、chrome80以后版本的加解密机制 |
|
chrome80以后版本的加解密机制与上面的大不同,其具体步骤为: |
|
从环境变量HOMEPATH对应目录的/Google/Chrome/User Data/子目录下的Local State文件中读取读取一个值为os_crypt下的encrypted_key; |
|
注:Local State文件为chrome用于存储本地状态(包括浏览器的不少状态信息,插件的详细信息等)的json文件。 |
|
将encrypted_key用base64进行解密,然后去除前5个字符,再通过dpapi解密剩余字符的值保存为key; |
|
将加密数据截取3-14位保存为Nonce,15位开始后的其他数据保存为cipherbytes加密数据,然后使用key作为密钥通过asegcm进行解密。 |
|
''' |
|
|
|
|
|
def decrypt_string(key, data): |
|
nonce, cipherbytes = data[3:15], data[15:] |
|
aesgcm = AESGCM(key) |
|
plainbytes = aesgcm.decrypt(nonce, cipherbytes, None) |
|
plaintext = plainbytes.decode('utf-8') |
|
|
|
return plaintext |
|
|
|
|
|
def get_key(): |
|
local_state = os.environ['LOCALAPPDATA'] + r'\Google\Chrome\User Data\Local State' |
|
with open(local_state, 'r', encoding='utf-8') as f: |
|
base64_encrypted_key = json.load(f)['os_crypt']['encrypted_key'] |
|
|
|
encrypted_key_with_header = base64.b64decode(base64_encrypted_key) |
|
encrypted_key = encrypted_key_with_header[5:] |
|
key = CryptUnprotectData(encrypted_key, None, None, None, 0)[1] |
|
|
|
return key |
|
|
|
|
|
def get_cookies(host): |
|
cookie_path = os.environ['LOCALAPPDATA'] + r"\Google\Chrome\User Data\Default\Network\Cookies" |
|
if not os.path.exists(cookie_path): |
|
raise Exception('Cookies file not exist!') |
|
|
|
sql = f"select name,encrypted_value from cookies where host_key = '.{host}'" |
|
|
|
conn = sqlite3.connect(cookie_path) |
|
conn.text_factory = bytes |
|
res = conn.execute(sql).fetchall() |
|
conn.close() |
|
|
|
key = get_key() |
|
result = [] |
|
for row in res: |
|
result.append(f'{str(row[0], encoding="utf-8")}={decrypt_string(key, row[1])}') |
|
|
|
# return result |
|
return ';'.join(result) |
|
|
|
|
|
domain = input('Please input domain:') |
|
cookies = get_cookies(domain) |
|
if cookies: |
|
print(cookies) |
|
else: |
|
print('not found cookies') |