Традиционно, для работы с СУБД используются скриптовые языки типа: Python, SQL, Tcl, Perl и прочие. Это вполне оправдано, поскольку их синтаксис максимально приближен к человеческой речи, а огромный набор рычагов и предметно-ориентированных модулей превращает решение вполне серьёзных проблем, чуть-ли не в игру. Единственным недостатком скриптов является скорость выполнения ими задач, т.к. в отличии от компилируемых программ они работают через интерпретатор – т.е. сначала построчный анализ текста, перевод его в байт-код, и лишь потом исполнение.
Однако бывают ситуации, когда с базами нужно совершить элементарные действия, например не создавать её с нуля забивая данными, а тупо прочитать пару-тройку столбцов уже имеющейся в ней информации. Это могут быть кукисы в браузерах, пароли и прочая инфа личного характера. Именно в таких случаях преимущество ассма (да и любого компилируемого языка) становится очевидным. Чтобы полностью исключить криминал, мы потренируемся строго на своей машине, не совершая атак на удалённые сервера. Здесь идеальным вариантом будет разбор встраиваемой базы SQLite – на ней и остановимся. Материал получился обширным, поэтому я разделил его на три части:
Содержание часть(1):
Содержание часть(2):
Содержание часть(3):
5. Постскриптум.
-------------------------------------------------------
1. Общие сведения
Ещё в 80-х годах прошлого столетия "человек-разумный" придумал СУБД, или систему управления базами данных. В обозримом будущем, схема свои позиции сдавать не собирается, а потому представляет интерес на всех уровнях. Огромные корпорации доверяют базам конфиденциальную информацию, а кража этих баз вторыми лицами – худшее, что только может случиться с компанией.
Всё-бы ничего, однако достоянием общественности становятся и личные сведения о нас с вами, а это уже настораживает. Базы почтовых серверов и социальных сетей с завидной периодичностью утекают из (якобы) защищённых периметров и админы здесь только пожимают плечами. В результате ошибок переполнения буферов, всевозможных дыр в системе безопасности и прочих уязвимостей, вся эта конструкция держится на честном слове. По сути мы, как конечные пользователи, в войне хакеров с админами выступаем в роли сторонних наблюдателей, которые лёжа на своём диване способны лишь обсуждать/осуждать.
Но мир не без добрых людей. Некоторые энтузиасты по собственной инициативе и на бесплатной основе пытаются изменить его к лучшему. Так, в августе 2000-го, некто Ричард Хипп (северная Каролина, США) анонсировал СУБД под названием SQLite. Он точил её напильником долгих 4-года, чтобы привести в надлежащий вид и представить мировому сообществу как стабильный релиз SQLite3. На данный момент последней считается v3.35.5 от 19 апреля 2021-года. То-есть проект жив, и активно развивается.
В отличие от многих других систем управления базами данных типа: MySql, Oracle и прочих, SQLite не является клиент-серверной базой данных – это обычное хранилище, которое встраивается в клиентское приложение, ..например: веб-браузеры, аудио/видео проигрыватели, графические редакторы, мобильные телефоны и т.п. В результате, получаем достаточно мощную, компактную и простую СУБД, а как-говорится "где мало сложности – там мало ложности".
На данном этапе сразу определимся с инструментами, чтобы больше не возвращаться к ним.
Есть огромное кол-во редакторов SQLite, но лично мне приглянулся "Expert Personal". Продуманный его интерфейс позволяет без особого труда и в пару кликов создавать, просматривать и редактировать базы-данных, а бонусом – в установочном пакете сразу идёт и свежая библиотека sqlite3.dll. Дело в том, что полноценная поддержка SQLite включена только начиная с Win-10, так-что обладателям более старых систем ХР,7,8 придётся качать эту либу из репозитория автора. Получив редактор, мы убиваем сразу двух зайцев – вот линки:
Сайт разработчика "SQLite Expert Personal":
Исходники и библиотека от автора СУБД:
Описание функций sqlite3.dll:
Навороченный HEX-редактор "010 Editor":
2. Знакомство с базой SQLite3
SQLite имеет свой формат и обслуживается своей подсистемой. Передвижение запросов на выполнение той или иной операции назвали "транзакациями". Вся база-данных разбивается на страницы одинакового размера, где и хранится полезная нагрузка в виде двумерной матрицы строк и столбцов. Размер одной страницы "Page" варьируется в диапазоне от 512 до 65536 байт, а под максимальное кол-во страниц в одной базе отводится 32 бита = 4'294'967'294. При таких значениях, простой арифметикой можно получить допустимый размер базы-данных:
2.1.0. Режим[1] – Rollback, или "журнал отката" состояния
При таких гигантских объёмах в 1/4 петабайта, СУБД обязана гарантировать целостность своих данных, иначе в использовании баз просто теряется смысл. Поэтому, при операциях записи в таблицу, ядро SQLite сначала копирует содержимое модифицируемых страниц в т.н. "журнал отката", и только потом производит запись в основную базу. Журнал Rollback – это обычный дисковый файл, который всегда находится рядом с базой и имеет оригинальное имя, с добавлением суффикса
Отметим, что откат происходит прозрачно для пользователя, а вся ответственность ложится на неэкспортируемую служебную процедуру, которую запускает т.н. "триггер". В зависимости от конфигурации базы, триггеры могут вызываться как для каждой операции записи, так и один раз на глобальное изменение базы (в последнем случае его называют "табличным").
2.1.1. Режим[2] – WAL, или "журнал упреждающей записи" (Write-Ahead Logging)
Традиционный откат после неудачных попыток записи подразумевает сохранение резервных копий исходных страниц в отдельный файл, и восстановлении их в случае сбоя. В более новых версиях SQLite ввели ещё один режим под названием "упреждающая запись" WAL. Этот альтернативный режим представляет собой инверсный вариант обычного отката. Теперь, запись производится не напрямую в базу, а наоборот во-временный файл с суффиксом
Размер временного WAL-файла на диске как-правило 1000 страниц, а транзакацию сброса их в базу назвали "контрольной точкой". Таким образом, в традиционном откате имеем две примитивные операции "чтение/запись", а в усовершенствованном WAL добавляется ещё одна операция "сброс" (контрольная точка). Обновление исходной базы страницами WAL может происходить или по запросу пользователя, или-же автоматически, при переполнении временного файла.
2.1.2. VACUUM – дефрагментация базы-данных
Ещё одним немаловажным моментом является поддержание базы в компактном/сжатом состоянии. Для этих целей, в доспехах SQLite припрятан механизм под названием "Vacuum". Суть его в том, что если мы удаляем строки из базы, то информация фактически остаётся на своём месте, а соответствующая строка просто помечается свободной. В результате, в таблице появляются паразитные (вакуумные) строки, которые не несут абсолютно никакой полезной инфы, зато занимают пространство и размер базы.
Команда "VACUUM" очищает основную базу путём копирования её содержимого во временный файл, и перезагрузки исходной базы из этой копии. При этом механизм удаляет пустые страницы, выравнивает данные (делает их смежными) и назначает каждой строке новый порядковый номер RowID. Ядро отвергнет команду, если есть активная транзакция.
Кстати это типичная ситуация в базах "cookies" браузеров. Как-правило, время жизни кукисов определяет значение в столбце "expires_utc" (time counter), по истечении которого "правильный" кукис авто-уничтожается системой. В итоге, если посмотреть на такую базу в редакторе, она будет напоминать зубы хоккеиста, как в примере ниже:
2.1.3. Cache Page – кэширование страниц
Подсистема SQLite может иметь несколько страниц для кэша дискового ввода-вывода. Рассмотрим ситуацию, когда мы изменили несколько строк в таблице и дали команду на их сохранение. При этом, если транзакацию на запись ядро выполнит сразу, то это займёт много времени, и мы рискуем получить отклик через пару секунд. Запись на жёсткий диск довольно длительная операция, и лучше подкопить все модифицированные данные сначала в буферной памяти (а точнее в странице кэш), и сохранять их на диск в какой-нибудь момент бездействия. Такой алгоритм практикуют все версии операционных систем Windows при файловых операциях ввода-вывода, и подсистема SQLite не исключение, хотя на практике применяет редко.
2.1.4. Формат схемы базы-данных
В настоящее время определены 4 разновидности формата схемы:
2.1.5. Заголовок "Header" базы
Любая база-данных SQLite3 начинается с заголовка "Header", который занимает первые 100 байт (см. скрин 010-Editor выше). В нём указываются фундаментальные сведения о базе, её схема, кол-во и размер страниц, счётчик изменений таблицы и т.д.
Отличительной особенностью заголовка является прямой порядок байт, что придаёт ему нетрадиционную форму черепа. Например, числа в оперативной памяти ОЗУ наших компьютеров с процессорами х86/64 хранятся младшим байтом вперёд – такой порядок называют ещё "Little-Endial" и число
В таблице выше представлены поля заголовка, а для удобства их программного чтения, мы создадим одноименную структуру такого содержания:
2.2. Практика – чтение заголовка базы
Чтобы удовлетворить свой интерес, можно написать небольшой парсер заголовка базы-данных.
Если посмотреть на структуру хидера выше, то в самом его хвосте можно обнаружить поле "SqliteVerNum" с версией библиотеки sqlite3.dll того приложения, которое последним имела доступ к данной базе. Счётчик в предпоследнем поле считает эти изменения версий.
Идентификатор библиотеки указывается в виде 32-битного значения, и чтобы привести его в приятный для восприятия вид типа "v3.35.5", я написал отдельную процедуру. На первом этапе она делит значение поля на 1.000.000 (так мы получим версию 3), потом остаток на 1.000 (обновление, в данном случае 35) и всё-что останется – будет сборкой типа 5. Такой алго расшифровки данного поля рекомендует сам автор SQLite, Ричард Хипп.
На входе, программа ниже запрашивает имя файла базы-данных, поэтому нужно предварительно скопировать её от куда-нибудь. Как вариант, источниками могут послужить базы вашего интернет-браузера. Но у каждого он свой, так-что выкладывают лист возможных директорий для поиска.
Открыв папку и выбрав в ней очередной файл, нажмите в тотале комбинацию [Ctrl+Q] – если файл начинается с сигнатуры "SQLite format 3", значит это точно база. Вот исходник парсера её заголовка с некоторыми комментариями:
В следующей части рассмотрим функции библиотеки sqlite3.dll, способ работы с ними, типы запросов, ну и прочее в этом духе. В практической части попытаемся считать куки браузеров, что они представляют собой, и какого типа хранят информацию. В скрепку кладу инклуд "sqlite3.inc" и исполняемый файл приведённого выше кода. До скорого, пока!
Однако бывают ситуации, когда с базами нужно совершить элементарные действия, например не создавать её с нуля забивая данными, а тупо прочитать пару-тройку столбцов уже имеющейся в ней информации. Это могут быть кукисы в браузерах, пароли и прочая инфа личного характера. Именно в таких случаях преимущество ассма (да и любого компилируемого языка) становится очевидным. Чтобы полностью исключить криминал, мы потренируемся строго на своей машине, не совершая атак на удалённые сервера. Здесь идеальным вариантом будет разбор встраиваемой базы SQLite – на ней и остановимся. Материал получился обширным, поэтому я разделил его на три части:
Содержание часть(1):
1. Оффтоп..
2. Внутренний формат базы-данных SQLite;
• практика – чтение заголовка базы;
Содержание часть(2):
• практика – вытаскиваем "cookies" браузеров;
Содержание часть(3):
4. Функции DPAPI из библиотеки crypt32.dll;
• практика – принцип шифрования паролей Chrome;
5. Постскриптум.
-------------------------------------------------------
1. Общие сведения
Ещё в 80-х годах прошлого столетия "человек-разумный" придумал СУБД, или систему управления базами данных. В обозримом будущем, схема свои позиции сдавать не собирается, а потому представляет интерес на всех уровнях. Огромные корпорации доверяют базам конфиденциальную информацию, а кража этих баз вторыми лицами – худшее, что только может случиться с компанией.
Всё-бы ничего, однако достоянием общественности становятся и личные сведения о нас с вами, а это уже настораживает. Базы почтовых серверов и социальных сетей с завидной периодичностью утекают из (якобы) защищённых периметров и админы здесь только пожимают плечами. В результате ошибок переполнения буферов, всевозможных дыр в системе безопасности и прочих уязвимостей, вся эта конструкция держится на честном слове. По сути мы, как конечные пользователи, в войне хакеров с админами выступаем в роли сторонних наблюдателей, которые лёжа на своём диване способны лишь обсуждать/осуждать.
Но мир не без добрых людей. Некоторые энтузиасты по собственной инициативе и на бесплатной основе пытаются изменить его к лучшему. Так, в августе 2000-го, некто Ричард Хипп (северная Каролина, США) анонсировал СУБД под названием SQLite. Он точил её напильником долгих 4-года, чтобы привести в надлежащий вид и представить мировому сообществу как стабильный релиз SQLite3. На данный момент последней считается v3.35.5 от 19 апреля 2021-года. То-есть проект жив, и активно развивается.
В отличие от многих других систем управления базами данных типа: MySql, Oracle и прочих, SQLite не является клиент-серверной базой данных – это обычное хранилище, которое встраивается в клиентское приложение, ..например: веб-браузеры, аудио/видео проигрыватели, графические редакторы, мобильные телефоны и т.п. В результате, получаем достаточно мощную, компактную и простую СУБД, а как-говорится "где мало сложности – там мало ложности".
На данном этапе сразу определимся с инструментами, чтобы больше не возвращаться к ним.
Есть огромное кол-во редакторов SQLite, но лично мне приглянулся "Expert Personal". Продуманный его интерфейс позволяет без особого труда и в пару кликов создавать, просматривать и редактировать базы-данных, а бонусом – в установочном пакете сразу идёт и свежая библиотека sqlite3.dll. Дело в том, что полноценная поддержка SQLite включена только начиная с Win-10, так-что обладателям более старых систем ХР,7,8 придётся качать эту либу из репозитория автора. Получив редактор, мы убиваем сразу двух зайцев – вот линки:
Сайт разработчика "SQLite Expert Personal":
Ссылка скрыта от гостей
Исходники и библиотека от автора СУБД:
Ссылка скрыта от гостей
Описание функций sqlite3.dll:
Ссылка скрыта от гостей
Навороченный HEX-редактор "010 Editor":
Ссылка скрыта от гостей
2. Знакомство с базой SQLite3
SQLite имеет свой формат и обслуживается своей подсистемой. Передвижение запросов на выполнение той или иной операции назвали "транзакациями". Вся база-данных разбивается на страницы одинакового размера, где и хранится полезная нагрузка в виде двумерной матрицы строк и столбцов. Размер одной страницы "Page" варьируется в диапазоне от 512 до 65536 байт, а под максимальное кол-во страниц в одной базе отводится 32 бита = 4'294'967'294. При таких значениях, простой арифметикой можно получить допустимый размер базы-данных:
4'294'967'294 * 65'536 = 281'474'976'645'120
, или 281 терабайт.2.1.0. Режим[1] – Rollback, или "журнал отката" состояния
При таких гигантских объёмах в 1/4 петабайта, СУБД обязана гарантировать целостность своих данных, иначе в использовании баз просто теряется смысл. Поэтому, при операциях записи в таблицу, ядро SQLite сначала копирует содержимое модифицируемых страниц в т.н. "журнал отката", и только потом производит запись в основную базу. Журнал Rollback – это обычный дисковый файл, который всегда находится рядом с базой и имеет оригинальное имя, с добавлением суффикса
--journal
. Если транзакация на запись проходит успешно, то журнал удаляется, иначе ядро откатывает базу в прежнее состояние с сообщением об одной из следующих возможных ошибок:
Код:
SQLITE_OK = 0x00 ;// Успешный результат
SQLITE_ERROR = 0x01 ;// Ошибка или отсутствие базы данных
SQLITE_INTERNAL = 0x02 ;// Внутренняя логическая ошибка
SQLITE_PERM = 0x03 ;// В доступе отказано
SQLITE_ABORT = 0x04 ;// процедура обратного вызова запросила прерывание
SQLITE_BUSY = 0x05 ;// Файл базы данных заблокирован
SQLITE_LOCKED = 0x06 ;// Таблица в базе данных заблокирована
SQLITE_NOMEM = 0x07 ;// Ошибка malloc()
SQLITE_READONLY = 0x08 ;// Попытка записи в базу данных только для чтения
SQLITE_INTERRUPT = 0x09 ;// Операция завершена sqlite3_interrupt()
SQLITE_IOERR = 0x0A ;// Произошла ошибка дискового ввода-вывода
SQLITE_CORRUPT = 0x0B ;// Образ диска базы данных искажен
SQLITE_NOTFOUND = 0x0C ;// Неизвестный код операции в sqlite3_file_control()
SQLITE_FULL = 0x0D ;// Вставка не удалась, потому что база данных заполнена
SQLITE_CANTOPEN = 0x0E ;// Невозможно открыть файл базы данных
SQLITE_PROTOCOL = 0x0F ;// Ошибка протокола блокировки базы данных
SQLITE_EMPTY = 0x10 ;// База данных пуста
SQLITE_SCHEMA = 0x11 ;// Схема базы данных изменена
SQLITE_TOOBIG = 0x12 ;// Строка или BLOB превышает ограничение на размер
SQLITE_CONSTRAINT = 0x13 ;// Прерывание из-за нарушения ограничения
SQLITE_MISMATCH = 0x14 ;// Несоответствие типов данных
SQLITE_MISUSE = 0x15 ;// Некорректное использование библиотеки
SQLITE_NOLFS = 0x16 ;// Использует функции ОС, не поддерживаемые на хосте
SQLITE_AUTH = 0x17 ;// В авторизации отказано
SQLITE_FORMAT = 0x18 ;// Ошибка формата вспомогательной базы данных
SQLITE_RANGE = 0x19 ;// 2-й параметр sqlite3_bind вне допустимого диапазона
SQLITE_NOTADB = 0x1A ;// Открыт файл, не являющийся файлом базы данных
SQLITE_ROW = 0x64 ;// sqlite3_step() подготовил еще одну строку
SQLITE_DONE = 0x65 ;// sqlite3_step() завершил выполнение
Отметим, что откат происходит прозрачно для пользователя, а вся ответственность ложится на неэкспортируемую служебную процедуру, которую запускает т.н. "триггер". В зависимости от конфигурации базы, триггеры могут вызываться как для каждой операции записи, так и один раз на глобальное изменение базы (в последнем случае его называют "табличным").
2.1.1. Режим[2] – WAL, или "журнал упреждающей записи" (Write-Ahead Logging)
Традиционный откат после неудачных попыток записи подразумевает сохранение резервных копий исходных страниц в отдельный файл, и восстановлении их в случае сбоя. В более новых версиях SQLite ввели ещё один режим под названием "упреждающая запись" WAL. Этот альтернативный режим представляет собой инверсный вариант обычного отката. Теперь, запись производится не напрямую в базу, а наоборот во-временный файл с суффиксом
-–wal
. Это напоминает отложенную запись в кэш процессора WriteBack, не в пример сквозной записи в память WriteThrought.Размер временного WAL-файла на диске как-правило 1000 страниц, а транзакацию сброса их в базу назвали "контрольной точкой". Таким образом, в традиционном откате имеем две примитивные операции "чтение/запись", а в усовершенствованном WAL добавляется ещё одна операция "сброс" (контрольная точка). Обновление исходной базы страницами WAL может происходить или по запросу пользователя, или-же автоматически, при переполнении временного файла.
2.1.2. VACUUM – дефрагментация базы-данных
Ещё одним немаловажным моментом является поддержание базы в компактном/сжатом состоянии. Для этих целей, в доспехах SQLite припрятан механизм под названием "Vacuum". Суть его в том, что если мы удаляем строки из базы, то информация фактически остаётся на своём месте, а соответствующая строка просто помечается свободной. В результате, в таблице появляются паразитные (вакуумные) строки, которые не несут абсолютно никакой полезной инфы, зато занимают пространство и размер базы.
Команда "VACUUM" очищает основную базу путём копирования её содержимого во временный файл, и перезагрузки исходной базы из этой копии. При этом механизм удаляет пустые страницы, выравнивает данные (делает их смежными) и назначает каждой строке новый порядковый номер RowID. Ядро отвергнет команду, если есть активная транзакция.
Кстати это типичная ситуация в базах "cookies" браузеров. Как-правило, время жизни кукисов определяет значение в столбце "expires_utc" (time counter), по истечении которого "правильный" кукис авто-уничтожается системой. В итоге, если посмотреть на такую базу в редакторе, она будет напоминать зубы хоккеиста, как в примере ниже:
2.1.3. Cache Page – кэширование страниц
Подсистема SQLite может иметь несколько страниц для кэша дискового ввода-вывода. Рассмотрим ситуацию, когда мы изменили несколько строк в таблице и дали команду на их сохранение. При этом, если транзакацию на запись ядро выполнит сразу, то это займёт много времени, и мы рискуем получить отклик через пару секунд. Запись на жёсткий диск довольно длительная операция, и лучше подкопить все модифицированные данные сначала в буферной памяти (а точнее в странице кэш), и сохранять их на диск в какой-нибудь момент бездействия. Такой алгоритм практикуют все версии операционных систем Windows при файловых операциях ввода-вывода, и подсистема SQLite не исключение, хотя на практике применяет редко.
2.1.4. Формат схемы базы-данных
В настоящее время определены 4 разновидности формата схемы:
1. Legacy (проприетарный) – понимается всеми версиями SQLite, до v3.0.0 (18.06.2004).
2. Добавляет фишку, когда строки в одной таблице могут иметь различное кол-во столбцов (v3.1.3).
3. Незначительные усовершенствования формата(2).
4. Введено ключевое слово "DESC" в объявлениях индексов, которое позволяет сортировать таблицу или в порядке возрастания "ASC" (ascending), или убывания "DESC" (descending). Обратная сортировка не поддерживалась в схемах(1..3). Все современные базы-данных SQLite в дефолте используют формат(4).
2.1.5. Заголовок "Header" базы
Любая база-данных SQLite3 начинается с заголовка "Header", который занимает первые 100 байт (см. скрин 010-Editor выше). В нём указываются фундаментальные сведения о базе, её схема, кол-во и размер страниц, счётчик изменений таблицы и т.д.
Отличительной особенностью заголовка является прямой порядок байт, что придаёт ему нетрадиционную форму черепа. Например, числа в оперативной памяти ОЗУ наших компьютеров с процессорами х86/64 хранятся младшим байтом вперёд – такой порядок называют ещё "Little-Endial" и число
00112233h
будет представлено в ячейках памяти как 33.22.11.00
hex. В заголовке-же базы SQLite нужно воспринимать их в привычном нам виде слева-направо, т.е. "Big-Endian". Отметим, что для таких случаев в системе-команд процессоров Intel/AMD имеется специальная инструкция bswap
, которая отражает порядок байт в числе (Byte Swap).В таблице выше представлены поля заголовка, а для удобства их программного чтения, мы создадим одноименную структуру такого содержания:
C-подобный:
struct SQLITE_HEADER ;// <----- https://sqlite.org/fileformat2.html
Magic dq 0,0 ;// 16-байтная строка "SQLite format 3"
PageSize dw 0 ;// размер страницы в байтах
WriteWAL db 0 ;// способ обработки ошибок записи: 1 = откат, 2 = WAL
ReadWAL db 0 ;// способ обработки ошибок чтения: 1 = откат, 2 = WAL
PageReserved db 0 ;// всего резервных страниц
Reserved1 db 0,0,0 ;// устарело..
WriteCount dd 0 ;// кол-во изменений базы
TotalPage dd 0 ;// размер базы в страницах -1
FreePageOffset dd 0 ;// линк на первую свободную
TotalFreePage dd 0 ;// всего свободных
CookieFile dd 0 ;// счётчик изменений формата схемы
SchemeFormat dd 0 ;// формат схемы базы
CachePageSize dd 0 ;// размер страницы кэш для дискового в/в
VacuumRootPage dd 0 ;// первая страница вакуума
BaseCP dd 0 ;// кодировка: 1=UTF8, 2=UTF16_le, 3=UTF16_be (big-endian)
Reserved2 dd 0 ;//
IncVacuum dd 0 ;// инкрементный вакуум включён =1, или выключен =0
AppId dd 0 ;// ID создавшего базу приложения
Reserved3 db 20 dup(0)
SqliteVer dd 0 ;// счётчик версий
SqliteVerNum dd 0 ;// значение номера версии
ends
2.2. Практика – чтение заголовка базы
Чтобы удовлетворить свой интерес, можно написать небольшой парсер заголовка базы-данных.
Если посмотреть на структуру хидера выше, то в самом его хвосте можно обнаружить поле "SqliteVerNum" с версией библиотеки sqlite3.dll того приложения, которое последним имела доступ к данной базе. Счётчик в предпоследнем поле считает эти изменения версий.
Идентификатор библиотеки указывается в виде 32-битного значения, и чтобы привести его в приятный для восприятия вид типа "v3.35.5", я написал отдельную процедуру. На первом этапе она делит значение поля на 1.000.000 (так мы получим версию 3), потом остаток на 1.000 (обновление, в данном случае 35) и всё-что останется – будет сборкой типа 5. Такой алго расшифровки данного поля рекомендует сам автор SQLite, Ричард Хипп.
На входе, программа ниже запрашивает имя файла базы-данных, поэтому нужно предварительно скопировать её от куда-нибудь. Как вариант, источниками могут послужить базы вашего интернет-браузера. Но у каждого он свой, так-что выкладывают лист возможных директорий для поиска.
C-подобный:
# Path list for chromium_browsers
# =================================
[
(u'7Star', u'{LOCALAPPDATA}\7Star\7Star\User Data'),
(u'amigo', u'{LOCALAPPDATA}\Amigo\User Data'),
(u'brave', u'{LOCALAPPDATA}\BraveSoftware\Brave-Browser\User Data'),
(u'centbrowser', u'{LOCALAPPDATA}\CentBrowser\User Data'),
(u'chedot', u'{LOCALAPPDATA}\Chedot\User Data'),
(u'chrome canary', u'{LOCALAPPDATA}\Google\Chrome SxS\User Data'),
(u'chromium', u'{LOCALAPPDATA}\Chromium\User Data'),
(u'chromium edge', u'{LOCALAPPDATA}\Microsoft\Edge\User Data'),
(u'coccoc', u'{LOCALAPPDATA}\CocCoc\Browser\User Data'),
(u'comodo dragon', u'{LOCALAPPDATA}\Comodo\Dragon\User Data'),
(u'elements browser', u'{LOCALAPPDATA}\Elements Browser\User Data'),
(u'epic browser', u'{LOCALAPPDATA}\Epic Privacy Browser\User Data'),
(u'google chrome', u'{LOCALAPPDATA}\Google\Chrome\User Data'),
(u'kometa', u'{LOCALAPPDATA}\Kometa\User Data'),
(u'opera', u'{APPDATA}\Opera Software\Opera Stable'),
(u'orbitum', u'{LOCALAPPDATA}\Orbitum\User Data'),
(u'sputnik', u'{LOCALAPPDATA}\Sputnik\Sputnik\User Data'),
(u'torch', u'{LOCALAPPDATA}\Torch\User Data'),
(u'uran', u'{LOCALAPPDATA}\uCozMedia\Uran\User Data'),
(u'vivaldi', u'{LOCALAPPDATA}\Vivaldi\User Data'),
(u'yandexBrowser', u'{LOCALAPPDATA}\Yandex\YandexBrowser\User Data')
]
# Firefox_browsers = [
(u'firefox', u'{APPDATA}\Mozilla\Firefox'),
(u'blackHawk', u'{APPDATA}\NETGATE Technologies\BlackHawk'),
(u'cyberfox', u'{APPDATA}\8pecxstudios\Cyberfox'),
(u'comodo', u'{APPDATA}\Comodo\IceDragon'),
(u'k-Meleon', u'{APPDATA}\K-Meleon'),
(u'icecat', u'{APPDATA}\Mozilla\icecat'),
]
Открыв папку и выбрав в ней очередной файл, нажмите в тотале комбинацию [Ctrl+Q] – если файл начинается с сигнатуры "SQLite format 3", значит это точно база. Вот исходник парсера её заголовка с некоторыми комментариями:
C-подобный:
format pe console
include 'win32ax.inc'
include 'equates\sqlite3.inc'
entry start
;//------------
.data
fName rb 128
buff db 0
;//------------
.code
start: invoke SetConsoleTitle,<'*** SQLite3 Header info ***',0>
;//----- Запрашиваем имя файла
cinvoke printf,<10,' File name............: ',0>
cinvoke scanf,<'%s',0>,fName
;//----- Пробуем открыть его
invoke _lopen,fName,0
or eax,eax ;// ошибка?
jns @next
cinvoke printf,<10,' ERROR! File not found.',0>
jmp @exit
@next: push eax
invoke _lread,eax,buff,100 ;// читаем заголовок из базы в буфер
pop eax
invoke _lclose,eax ;// закрыть файл базы
;//----- Проверим на принадлежность заголовка к SQLite
call @f
db 'SQLite format 3' ;// сигнатура,
@@: pop edi ;// ..в регистре EDI
mov esi,buff ;// где искать
mov ecx,15 ;// длина строки
repe cmpsb ;// сравнить!
jecxz @ok
cinvoke printf,<10,' ERROR! This is not SQLite3 database.',0>
jmp @exit
;//----- Заголовок корректный - выводим инфу..
@ok: cinvoke printf,<' Ok! Magic string.....: %s',10,10,0>,buff ;//<---- сигнатура заголовка
cinvoke printf,<10,' Data base info ***',0>
mov esi,buff
mov eax,[esi+SQLITE_HEADER.SqliteVerNum]
bswap eax
call GetSqlVersion
cinvoke printf,<10,' Version...........: %d.%d.%d',0>,eax,ebx,ecx
mov esi,buff
mov eax,[esi+SQLITE_HEADER.BaseCP]
bswap eax
shl eax,3
mov ebx,[esi+SQLITE_HEADER.SchemeFormat]
bswap ebx
mov ecx,[esi+SQLITE_HEADER.WriteCount]
bswap ecx
mov edx,[esi+SQLITE_HEADER.AppId]
bswap edx
cinvoke printf,<10,' Text code-page....: UTF-%d',\
10,' Schema format.....: %d',\
10,' Modified counter..: %d times',\
10,' Application ID....: %d',10,0>,eax,ebx,ecx,edx
;//--------------
cinvoke printf,<10,' Pages structure ***',0>
mov esi,buff
movzx ebp,[esi+SQLITE_HEADER.PageSize]
rol bp,8
push ebp
mov ebx,[esi+SQLITE_HEADER.TotalPage]
bswap ebx
mov ecx,[esi+SQLITE_HEADER.TotalFreePage]
bswap ecx
pop eax
mul ebx
mov edx,[esi+SQLITE_HEADER.FreePageOffset]
bswap edx
cinvoke printf,<10,' Page size.........: %d byte',\
10,' Total pages.......: %d',\
10,' Database size.....: %d byte',\
10,' Free page offset..: %d',\
10,' Total free pages..: %d',10,0>,ebp,ebx,eax,edx,ecx
;//--------------
cinvoke printf,<10,' Extended info *****',0>
mov esi,buff
mov eax,[esi+SQLITE_HEADER.CookieFile]
bswap eax
mov ebx,[esi+SQLITE_HEADER.CachePageSize]
bswap ebx
movzx ecx,[esi+SQLITE_HEADER.WriteWAL]
bswap ebx
movzx edx,[esi+SQLITE_HEADER.ReadWAL]
bswap ebx
cinvoke printf,<10,' Schema modified...: %d times',\
10,' Cache page size...: %d byte',\
10,' Write error mode..: %d (1 = Rollback, 2 = WAL)',\
10,' Read error mode..: %d (1 = Rollback, 2 = WAL)',0>,\
eax,ebx,ecx,edx
mov esi,buff
mov eax,[esi+SQLITE_HEADER.IncVacuum]
bswap eax
mov ebx,[esi+SQLITE_HEADER.VacuumRootPage]
bswap ebx
cinvoke printf,<10,' Increment vacuum..: %d',\
10,' Vacuum page offset: %d',0>,eax,ebx
@exit: cinvoke getch
cinvoke exit,0
;//------------
GetSqlVersion:
xor edx,edx
mov ebx,1000000
div ebx
push eax
xchg eax,edx
mov ebx,1000
xor edx,edx
div ebx
xchg ecx,edx
xchg ebx,eax
pop eax
ret
;//------------
section '.idata' import data readable
library kernel32,'kernel32.dll',msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',scanf,'scanf',getch,'_getch',exit,'exit'
include 'api\kernel32.inc'
В следующей части рассмотрим функции библиотеки sqlite3.dll, способ работы с ними, типы запросов, ну и прочее в этом духе. В практической части попытаемся считать куки браузеров, что они представляют собой, и какого типа хранят информацию. В скрепку кладу инклуд "sqlite3.inc" и исполняемый файл приведённого выше кода. До скорого, пока!
Вложения
Последнее редактирование: