chrome cookies cookie 解密 写入(80+版本)

一,历史变迁

80之前,解密:win32crypt.CryptUnprotectData(encrypted_value_bytes,None,None,None,0)[1],老文N多,自行搜索。

80开始,改了:https://github.com/chromium/chromium/blob/master/components/os_crypt/os_crypt_win.cc

AESGCM加密cookie明文

def EncryptString(key,plaintext):
    plainbytes=plaintext.encode('utf-8')
    nonce=os.urandom(12)
    aesgcm=AESGCM(key)
    cipherbytes=aesgcm.encrypt(nonce,plainbytes,None)
    data=b'v10'+nonce+cipherbytes
    #也有v11的,反正就前3字节,无影响
    return data

AESGCM的key是这么生成的:(1)随机32字节DPAPI加密(2)5字节b’DPAPI’头(3)base64编码

def generate_a_new_key():
    key=os.urandom(32)
    encrypted_key=win32crypt.CryptProtectData(key,None,None,None,None,0)
    encrypted_key_with_header=b'DPAPI'+encrypted_key
    base64_encrypted_key=base64.b64encode(encrypted_key_with_header)
    return base64_encrypted_key

二,读取解密

因此,解密就是:(1)读取数据库里的密文(字节)(2)AESGCM解密。两个路径:

Cookies文件(sqlite3 db,储存网站的cookies)
在这里插入图片描述
Local State文件(json,储存各种,key也在其中)在这里插入图片描述
python读取解密

# -*- coding=utf-8 -*-
import os
import json
import base64
import sqlite3
import win32crypt
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

#读取chrome保存在json文件中的key(str)
def GetString(LocalState):
    with open(LocalState,'r',encoding='utf-8') as f:
        s=json.load(f)['os_crypt']['encrypted_key']
    return s

#base64解码,DPAPI解密,得到真实的AESGCM key(bytes)
def pull_the_key(base64_encrypted_key):
    encrypted_key_with_header=base64.b64decode(base64_encrypted_key)
    encrypted_key=encrypted_key_with_header[5:]
    key=win32crypt.CryptUnprotectData(encrypted_key,None,None,None,0)[1]
    return key

#AESGCM解密
def DecryptString(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

if __name__ == '__main__':

    UserDataDir=os.environ['LOCALAPPDATA']+r'\Google\Chrome\User Data'
    LocalStateFilePath=UserDataDir+r'\Local State'
    CookiesFilePath=UserDataDir+r'\Default\Cookies'
    #反正就是上面图片中的两个文件名的路径
    #默认路径可能随着版本有所变化,找一找

    con=sqlite3.connect(CookiesFilePath)
    #con.text_factory = bytes
    res=con.execute('select host_key,name,encrypted_value from cookies').fetchall()
    con.close()
    #此处encrypted_value在sqlite中声明的是BLOB,官方sqlite库应该读进来就是bytes。
    #评论有反应utf-8 decode错误的,显然把自动类型转化成了TEXT,多整了一次decode()
    #最新sqlite dll没这问题,还支持json,,,还在用3.7左右python的建议更新一波
    
    key=pull_the_key(GetString(LocalStateFilePath))
    for i in res:
    	print(i[0],i[1],DecryptString(key,i[2])

(这个更新一波,使用sqlites3官网的最新版本,毫无问题,一亿条记录,测试验证,,,)
在这里插入图片描述

三,构造回写

在这里插入图片描述(chrome 93 cookies sqlite db)

能少就少,写入10个必须字段就够了。说法比较天花乱坠的似乎就是这个三个’时间戳‘:creation_utc,expires_utc,last_access_utc,

百度了一下(其实百度不到的,全是营销号,知道,贴吧,,,github,stack,google了一下),好像这个说法,比较准确:

windows上,chrome采用的是:Windows file time,这个东东和日常unix时间戳两个区别:

(1)起点。1601 年1 月1 日 午夜12点(utc) vs 1970年1月1日午夜12点(utc)(2)精度。 ‘微妙’ vs ‘秒’

(https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tofiletimeutc?view=net-5.0)

def ToFileTimeUtc(isostr=''):
    from datetime import datetime,timedelta,timezone
    if isostr:
        l=[int(i) for i in isostr.split(' ')[0].split('-')]+[int(i) for i in isostr.split(' ')[-1].split(':')]
        end=datetime(*l,tzinfo=timezone.utc)
    else:
        end=datetime.now(timezone.utc)
    start=datetime(1601,1,1,tzinfo=timezone.utc)
    return int((end-start)/timedelta(microseconds=1))

def FromFileTimeUtc(microseconds,local=False):
    from datetime import datetime,timedelta,timezone
    d=datetime(1601,1,1,tzinfo=timezone.utc)+timedelta(microseconds=microseconds)
    if local:
        return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(d.timestamp()))
    else:
        return time.strftime('%Y-%m-%d %H:%M:%S',time.gmtime(d.timestamp()))

print(ToFileTimeUtc('2099-01-01 00:00:00'))
print(FromFileTimeUtc(ToFileTimeUtc()))

def one_cookie_for_chrome_sqlite(DOMAIN,NAME,VALUE):
    return dict(
    creation_utc=ToFileTimeUtc(),
    host_key=DOMAIN,
    name=NAME,
    value='',#现在使用了下面的encrypted_value了,对应VALUE
    path='/',
    expires_utc=ToFileTimeUtc('2099-01-01 00:00:00'),#随便写未来时间,服务器自有判断,不会以此为准.别写过去,浏览器给删了
    is_secure=0,
    is_httponly=0,
    last_access_utc=ToFileTimeUtc(),#显然最后访问时间,应该大于等于创建时间
    encrypted_value=EncryptString(key,VALUE)#上面的加密函数
    ).values()

四,其他杂项

chrome两个默认相关路径,随着版本有所变动,直接新建桌面快捷方式采用–user-data-dir启动参数:

"C:\Program Files\Google\Chrome\Application\chrome.exe" --user-data-dir="C:\mychrome"

这个mychrome文件夹结构,还是符合传统的。

2021-09-05更新

猜你喜欢

转载自blog.csdn.net/m0_46146791/article/details/104686060