把加密值HEX[v10mC1^ĻI~\`ql>t^c+EO0bJKp1YRn˭F$O]一下得到7631306D43A786939231E0A4D6DC5E**BB497E5C60716CFEFDDB3E74A7ABE2E5F1BAF45EF5F163BC2BB**54F9D30624A4B708D310C168894FFEC189C8959526ECBAD46EF1D7FD224B6868FA64F83CD
然后我们用python解密一下
可看到了解密成功。下一篇用C++来实现自动化解密
几个注意点
Cookie位于User Data/Default下的Cookies文件 改名为Cookies.db即可用sqllite进行查询和查看
上一篇实现了python的简单解密。这一次我们来用C++实现自动化。在这之前 我们需要用到两个C++库
repaidjson
cryptopp
编译环境为VS2013.这两个库不多做介绍,rapidjson是腾讯的一个开源json解析库。发挥的作用不大,就是解析个json。另外就是cryptopp。嗯。。很牛逼。
解析下大致流程:
1:获取local state文件位置
2:获取加密的key(base64编码)
3:解析sqllite文件
4:DPAPI解密
5:ase-gcm解密
关于Aes-gcm 需要用到 KEY IV 以及被加密的字符串 梳理下这几个参数的流程:
KEY = local state = > os_crypt => Encrypted_key => Base64Decode(encrypted_key) => 去除首位5个字符 => DPAPI解密 IV = 被加密的字符串掐头去尾 chiper = 被加密的字符串去头
一般来说 安装的这些配置文件都在LOCAL_APPDATA下。可以使用SHGetSpecialFolderPath(NULL, szBuffer, CSIDL_LOCAL_APPDATA, FALSE);
来获取这个路径。然后starcat组合一下字符串得到路径 部分代码如下:
char szBuffer[MAX_PATH]; if (EncryptBaseKey == "") { string jsonstr; SHGetSpecialFolderPath(NULL, szBuffer, CSIDL_LOCAL_APPDATA, FALSE); strcat(szBuffer, "\\Google\\Chrome\\User Data\\Local State"); jsonstr = readfile(szBuffer); Document root; root.Parse(jsonstr.c_str()); Value& infoArray = root["os_crypt"]; EncryptBaseKey = infoArray["encrypted_key"].GetString(); } return EncryptBaseKey;
这里就获取了加密的秘钥。但是有一点。如果是非80版本 是不存在os_crypt的,这里使用的rapidjson就会抛出异常。但不影响。只需要在使用sqllite查询的时候 接管一下字符串,看看是不是包含v10或者v11即可。如果你使用的和我一样代码。请注意大小写V10和v10的区别。
string e_str = argv[i]; if (strstr(e_str.c_str(), "v10") != NULL || strstr(e_str.c_str(), "v11") != NULL) { string DecryptVaule=NewDecrypt(argv[i]); strcpy(enc_value_a, DecryptVaule.c_str()); } else{ DecryptPass(argv[i], enc_value, 2048); _snprintf_s(enc_value_a, sizeof(enc_value_a), _TRUNCATE, "%S", enc_value); }
紧接着就是对他进行base64解密。这里我用的是cryptopp 先放一下新版解密函数
std::string static NewDecrypt(CHAR *cryptData) { string EncryptValue = cryptData; string Encoded,Decoded; string key,iv,chiper; string recovered;//也就是解密的KEY WCHAR enc_value[2048]; char enc_value_a[2048]; ZeroMemory(enc_value, sizeof(enc_value)); ZeroMemory(enc_value_a, sizeof(enc_value_a)); //-----------------------初始化几个要用到加密字符串的变量----------------------------------// iv = EncryptValue; chiper = EncryptValue; //---------------------------------------------------------// StringSource((BYTE*)EncryptValue.c_str(), EncryptValue.size(), true, new HexEncoder( new StringSink(Encoded))); EncryptValue = Encoded; Encoded.clear(); //---------------------------------------------------------// key = GetEncryptKEY(); StringSource((BYTE*)key.c_str(), key.size(), true, new Base64Decoder( new StringSink(Decoded))); key = Decoded; key = key.substr(5);//去除首位5个字符 Decoded.clear(); DecryptPass((char*)key.c_str(), enc_value, 2048); _snprintf_s(enc_value_a, sizeof(enc_value_a), _TRUNCATE, "%S", enc_value); key = enc_value_a; StringSource((BYTE*)key.c_str(),key.size(), true, new HexEncoder( new StringSink(Encoded))); key = Encoded; Encoded.clear(); //KEY解密完毕 开始处理Nonce 也就是IV iv =iv.substr(3,12); StringSource((BYTE*)iv.c_str(), iv.size(), true, new HexEncoder( new StringSink(Encoded))); iv = Encoded; Encoded.clear(); //---------------------------------------------------------// //开始处理chiper if (chiper.size() < 30){ return "wu xiao zi fu chuan....."; } StringSource((BYTE*)chiper.c_str(), chiper.size(), true, new HexEncoder( new StringSink(Encoded))); chiper = Encoded; Encoded.clear(); chiper = chiper.substr(30);//因为是HEX 占了2个字节 //---------------------------------------------------------// //进行AES_GCM try { StringSource((BYTE*)iv.c_str(), iv.size(), true, new HexDecoder( new StringSink(Decoded) ) // HexEncoder ); // StringSource iv = Decoded; Decoded.clear(); StringSource((BYTE*)key.c_str(), key.size(), true, new HexDecoder( new StringSink(Decoded) ) // HexEncoder ); // StringSource key = Decoded; Decoded.clear(); StringSource((BYTE*)chiper.c_str(), chiper.size(), true, new HexDecoder( new StringSink(Decoded) ) // HexEncoder ); // StringSource chiper = Decoded; Decoded.clear(); cout << chiper << endl; GCM< AES >::Decryption d; d.SetKeyWithIV((BYTE*)key.c_str(), key.size(), (BYTE*)iv.c_str(), iv.size()); StringSource s(chiper, true, new AuthenticatedDecryptionFilter(d, new StringSink(recovered) ) // StreamTransformationFilter ); // StringSource cout << "recovered text: " << recovered << endl; } catch (const CryptoPP::Exception& e) { cerr << e.what() << endl; //exit(1); } return recovered; }
先base64解码一下