Рассмотрев в предыдущей части формат и основные возможности подсистемы SQLite, перейдём к операциям с данными, которые осуществляются посредством вызова методов из библиотеки sqlite3.dll. Самая последняя версия 3.35.05 этой либы выдаёт на экспорт всего 329 функций, предоставляя нам широкий выбор действий. Некоторые из них могут иметь переменное число параметров, и автор не стал делать на них акцент. Он просто оформил все функции с соглашением о вызове "cdecl" (декларация языка С++), а не стандартным "stdcall". Это означает, что на выходе, ответственность за очистку аргументов функции в стеке полностью возложена на нас, для чего ассемблер FASM имеет макросы cinvoke и ccall (последний используется для вызовов по указателю). Экскурсии по часто используемым функциям и посвящена данная часть статьи.
Содержание:
---------------------------------------
Одним из недостатков компилятора FASM (по сравнению с тем-же масмом) является отсутствие в базовом его пакете большинства заголовочных файлов с описанием структур. Томас Грыштар ограничился лишь основными библиотеками типа User/Shell/Kernel32.dll, зато предусмотрел простую возможность добавления сторонних инклуд, по мере их необходимости. В частности, это относится к перечислению импорта из статически подключаемых библиотек при компиляции проектов. Применительно к указанным выше DLL, освобождают нас от этой рутины файлы из папки FASM\INCLUDE\API, в которых перечислены все функции экспорта каждой из DLL. Теперь, просто подключив их к своему исходному коду, нам не нужно импортировать функции явно – компилятор сам позаботится об этом.
Чтобы добавить красок в работу с базами-данных SQLite, я (придерживаясь рекомендаций автора fasm) создал точно такой-же инклуд импорта, только для библиотеки sqlite3.dll. Результат настолько воодушевил, что не поленился собрать аналогичный инклуд сразу и для консольной либы msvcrt.dll – оба этих файла можно будет найти в скрепке, в подвале статьи. В итоге, служебная часть исходника остаётся за его периметром во-внешних инклудах, что повышает читабельность кода.
1. Основные функции библиотеки sqlite3.dll
Функции SQLite позволяют выполнять следующий набор операций:
Из этого списка, нашим интересам удовлетворяет только пункт(3), поскольку мы планируем вытягивать из баз-данных кукисы и пароли интернет-браузеров. Если рассматривать возможности программирования всех операций, то основной посыл статьи уйдёт на пятый план, так-что лучше остановимся на одном. По сути, поняв общий принцип формирования запросов, без особого труда можно будет выполнять любые операции – тут главное разобраться, что такое запрос и кто его выполняет.
1.1. sqlite3_open_v2(), sqlite3_close()
База – это файл данных. Согласно общепринятому алгоритму работы с файлами, для начала базу нужно открыть функцией sqlite3_open_v2(). Во-второй этой версии, в прототип были добавлены два дополнительных параметра: flags и zVfs. Последний означает Virtual-File-System (vfs) и нам не нужен. Зато флаг даёт возможность не только открывать базу, но и создавать её. Конкретное действие определяется перечисленными ниже константами:
Данная функция открытия базы проделывает огромный объём работы, подготавливая контент и окружение для всех последующих функций sqlite3.dll. Она копирует содержимое базы в оперативную память ОЗУ, выстраивает локальную таблицу указателей на инфо-ячейки таблицы и многое другое. Если open_v2() предоставляет программные ресурсы, то родственная ей функция sqlite3_close() наоборот освобождает их. Однако в её вызове нет необходимости, если далее закрывается сама программа, т.к. ExitProcess() на выходе в любом случае проделывает аналогичную работу, освобождая глобальные ресурсы процесса на более низком уровне.
1.2. Операторы запросов SQLite
Значит базу открыли, и теперь нужно произвести с ней какие-либо действия. Для этого, мы должны послать ядру соответствующий запрос, который состоит как-минимум из двух операторов: SELECT и FROM (рассматриваем чтение). Об этом, прямым текстом сообщает и название языка программирования "Structured Query Language", или язык структурированных запросов. Исторически, операторы любой СУБД делятся на 4 типа, и SQLite здесь не исключение:
Операторы определения данных (Data Definition Language, DDL):
Операторы манипуляции данными (Data Manipulation Language, DML):
Операторы определения доступа к данным (Data Control Language, DCL):
Операторы управления транзакциями (Transaction Control Language, TCL):
Как видим, для обычного чтения данных используется оператор SELECT, которому передаются ещё несколько уточняющих запрос аргументов – это имена столбцов в таблице (т.е. что именно интересует), имя таблицы через оператор FROM (т.е.где искать, поскольку таблиц в одной базе может быть несколько), и если нужно условие, посредством оператора WHERE. Вот пара простых примеров оформления запросов:
Для начала нам этого хватит, а с диалектом более сложных запросов мы ознакомимся в конце этой статьи. Несколько линков по теме:
Оператор SELECT:
Основные запросы SQL, которые должен знать каждый программист:
1.3. prepare() и finalize() – подготовка оператора запроса
На следующем этапе, подготовленный запрос в виде текстовой строки необходимо скомпилировать в байт-код, чем занимается синтаксический анализатор функции sqlite3_prepare_v2(). Переварив строку, эта функция модифицирует её в соответствующий формат и помещает полученный бинарник в память, а нам возвращает лишь дескриптор на него. В документации, этот дескриптор называют "STMT", что означает Prepared-Statement-Object (готовый объект заявления).
В последующих операциях чтения, мы должны будем передавать этот объект всем функциям-исполнения конкретно данного запроса. Если-же захотим сменить запрос на другой (с иными операторами), то сначала нужно аннулировать предыдущий функцией sqlite3_finalize(), и только потом оформлять новый, обратно функцией prepare_v2(). Вот её прототип:
В базовой версии этой функции необходимо было всегда финализировать запросы, перед тем-как оформлять новые. Но в усовершенствованной версии(2) необходимость в этом отпала, т.к. автор посчитал данное действо само-собой разумеющимся, и зашил его внутрь исполняющих запрос функций. Теперь, если запрос отрабатывает до конца, то сбрасывать его не нужно. Однако если мы хотим прервать запрос на половине исполнения (например планировали чтение всех строк базы, а потом решили остановиться на 10-ой), то вызов sqlite3_finalize() в этом случае обязателен. Данный нюанс способен изрядно попортить нервы, поэтому не сбрасывайте его со-счетов. По большому счёту, в финализации отработанных запросов нет ничего страшного, поэтому можно действовать по усмотрению.
1.4. step() и exec() – исполнение запроса
Непосредственным исполнением предписанных в запросах операций занимаются две функции – это sqlite3_step() и sqlite3_exec(). Первая немного предпочтительней, поскольку позволяет более тонко контролировать процесс исполнения, хотя для чтения каждой из строк таблицы её нужно вызывать в цикле. Это означает, что на каждом шаге Step, функция просто перемещает указатель на следующую строку, и если это не последняя, то возвращает в регистре EAX константу SQLITE_ROW=64h (есть ещё строки), иначе SQLITE_DONE=65h (выполнено и достигли конца таблицы).
Что делать дальше с этой строкой определяют уже
Прототипы у всех этих методов одинаковые – в первом аргументе передаём дескриптор скомпилированного функцией sqlite3_prepare_v2() запроса, а во-втором – индекс столбца для чтения (он привязан к последовательности в запросе, а не к порядковому номеру столбца в глобальной таблице). Здесь уместным будет замечание, что столбцы в таблицах любой базы-данных нумеруются начиная с нуля, а строки с единицы. Метод sqlite3_column_type() может возвращать одну из перечисленных ниже констант:
Как видим, SQLite не имеет отдельного класса для хранения даты/времени – они определяются в виде значений INTEGER, FLOAT или TEXT. При этом предпочтительный вариант именно TEXT, поскольку при помощи операторов ASC/DESC позволяет сортировать строки по дате. В остальных вариантах, эта возможность не поддерживается. Вот как они представляются в ячейках таблицы. Здесь можно ознакомиться с деталями:
Вторая функция исполнения запросов sqlite3_exec() присваивает себе право проделывать всю работу без нашего с вами участия. Её можно рассматривать как авто-Step, без применения циклов. Интерфейс представляет собой оболочку "три-в-одном", внутри которой вызываются сразу три рассмотренные выше функции: prepare(), step() и finalize(). Это сокращает исходный код приложения, зато лишает нас возможности контролировать процесс. Прототип данной функции лежит на официальном сайте по
2.0. Практика – собираем информацию о базе-данных
Теперь посмотрим, как выглядит всё это хозяйство на практике. В примере я сброшу на консоль общую информацию о базе SQLite, в которой хранятся кукисы браузера Chrome. Чтобы не мешать работе браузера, сначала нужно будет сформировать путь до его кукисов, и скопировать их в свою директорию. Функция из shell32.dll SHGetFolderPathA() с ключом CSIDL_LOCAL_APPDATA возвратит нам папку юзера
Так, не открывая базу в стороннем редакторе, мы получили имена столбцов и если это шелл-код, он может сформировать строку запроса прямо на-лету. Ясно, что структура таблицы кукисов известна всем, но если мы столкнёмся с какой-нибудь базой на удалённом узле, то "слепое" вычисление имени столбцов (и типов данных в них) может сыграть нам на руку. К примеру обнаружив поле BLOB (Binary-Long-Object, массив двоичных данных) можно сделать вывод, что перед нами зашифрованное содержимое, и это может быть пароль или другая конфиденциальная инфа.
2.1. Практика – чтение "cookies" браузеров
Теперь чуть усложним задачу, и попробуем изъять из этой базы все кукисы. Читать будем обозначенные на скрине выше поля, но сначала дадим короткое определение, что такое вообще "cookie", какие они бывают, и зачем нужны.
-----------------------
Кукисы – это текстовые файлы у нас на компьютерах, в которых хранится инфа о наших предыдущих действиях на сайтах. Когда мы совершаем какое-то действие (например, вводим пароли входа в аккаунт), сервер сбрасывает эту информацию в куки и отправляет браузеру вместе со страницей. Теперь, когда мы следующий раз заходим на тот-же сайт или страницу, браузер отправляет куки обратно. Они бывают временными и постоянными – в браузерах Хром, время их жизни определяет значение в столбце "expires_utc". Постоянные куки остаются на компьютере, когда мы закрываем вкладку сайта, а временные удаляются.
По сути куки не опасны – это обычный текст. Они не могут запускать процессы и взаимодействовать с ОС как-бы то нибыло. Но некоторые подозрительные личности в маске джокера могут попытаться украсть их, чтобы отследить наши действия в сети, или зайти в аккаунт без авторизации. Именно это и представляет потенциальную угрозу в хранение кукисов. Кроме входов в аккаунты они умеют запоминать:
Согласно общепринятым правилам, серверы могут высылать кукисы строго предопределённого типа, которые можно распознать по их именам:
Ну и теперь немного о самом коде..
Поскольку значения всех столбцов таблицы нам не интересны (см.скрин выше), то в строке запроса перечисляем только нужные из них. То-есть запрос будет такого вида:
Кстати макс.значение индекса столбцов для методов функции sqlite3_step() в этом случае будет =1 (отсчёт с нуля). На запрос такого рода получим всего по два значения из каждой строки – это имя хоста и кукиса. Раз-уж разборки с паролем мы оставили для сл.части статьи, то прицепом к именам можно вывести хотя-бы время создания/окончания действия кукиса. Значит добавим к этому запросу ещё два столбца – creation_utc и expires_utc. Но здесь буйком всплывает проблема преобразования значения INTEGER в строку даты/времени.
Одной из примечательных особенностей языка SQL является возможность оформлять вложенные запросы – т.е. в основной запрос помещаем дочерний под-запрос. Немного попыхтев при его обработке, ядро выдаст результаты обоих, и остаётся вывести их на консоль в подобающем виде. В данном случае, для преобразования времени мы воспользуемся этой фишкой и вложим в запрос целую функцию SQLite для работы с датами strftime(). Она чем-то напоминает printf() из msvcrt.dll и ожидает в аргументе спецификаторы типа %s. В конечном итоге, оформленный по этим правилам строка запроса будет выглядеть так, и мы получим время в текстовом виде:
В остальном – всё довольно прозрачно. Значит делаем Step и проверяем его выхлоп на SQLITE_ROW, что означает наличие следующих строк в таблице. Теперь, внутри цикла зовём метод sqlite3_column_text() и в регистре EAX получаем указатель на данные в текстовом виде, текущего столбца и строки. Вызываем этот-же метод для всех столбцов, которые перечислены в запросе. При этом не забываем каждый раз добавлять к индексу 1. Можно предусмотреть и переменную для подсчёта обработанных строк – это будет счётчиком кукисов в базе. Вот пример такого алго:
Обратите внимание на время жизни последнего кукиса с достопочтенного сайта wasm.in. Актуальность его заканчивается далеком в прошлом 1601-год (время отсчёта Unix-систем). Это потому, что данный кукис вечный и в его столбце expires_utc лежит значение нуль. По идее, такие ошибки нужно обрабатывать, что было делать мне лень.
На этом ставлю точку.
В скрепке можно будет найти два экзешника, и три инклуда: SqliteAPI, MsvcrtAPI и sqlite3.inc с описанием констант. Всем удачи, пока!
Содержание:
1. Основные функции библиотеки sqlite3.dll;
• операторы и оформление запросов;
2. Практика – чтение структуры базы-данных ;
3. Практика – собираем "cookies" браузеров.
---------------------------------------
Одним из недостатков компилятора FASM (по сравнению с тем-же масмом) является отсутствие в базовом его пакете большинства заголовочных файлов с описанием структур. Томас Грыштар ограничился лишь основными библиотеками типа User/Shell/Kernel32.dll, зато предусмотрел простую возможность добавления сторонних инклуд, по мере их необходимости. В частности, это относится к перечислению импорта из статически подключаемых библиотек при компиляции проектов. Применительно к указанным выше DLL, освобождают нас от этой рутины файлы из папки FASM\INCLUDE\API, в которых перечислены все функции экспорта каждой из DLL. Теперь, просто подключив их к своему исходному коду, нам не нужно импортировать функции явно – компилятор сам позаботится об этом.
Чтобы добавить красок в работу с базами-данных SQLite, я (придерживаясь рекомендаций автора fasm) создал точно такой-же инклуд импорта, только для библиотеки sqlite3.dll. Результат настолько воодушевил, что не поленился собрать аналогичный инклуд сразу и для консольной либы msvcrt.dll – оба этих файла можно будет найти в скрепке, в подвале статьи. В итоге, служебная часть исходника остаётся за его периметром во-внешних инклудах, что повышает читабельность кода.
Код:
File : sqlite3.dll
Version : 3.35.5
Size : 1071715 byte
Type : PE
Base Of Code : 00001000, Code Size: 000ABC00
Base Of Data : 000AD000, Data Size: 000CA400
Image Base : 61E00000
Entry Point : 61E01400
File sections:
Name | VirtAddr | VirtSize | Offset | PhysSize | Flags | Code
----------+----------+----------+----------+----------+----------+------
.text | 61E01000 | 000ABAF0 | 00000600 | 000ABC00 | 60500060 | Yes
.data | 61EAD000 | 000022DC | 000AC200 | 00002400 | C0600040 |
.rdata | 61EB0000 | 00013AB0 | 000AE600 | 00013C00 | 40600040 |
.bss | 61EC4000 | 00000828 | 00000000 | 00000000 | C0600080 |
.edata | 61EC5000 | 0000292B | 000C2200 | 00002A00 | 40300040 |
.idata | 61EC8000 | 00000CD0 | 000C4C00 | 00000E00 | C0300040 |
.CRT | 61EC9000 | 0000002C | 000C5A00 | 00000200 | C0300040 |
.tls | 61ECA000 | 00000020 | 000C5C00 | 00000200 | C0300040 |
.rsrc | 61ECB000 | 000004A8 | 000C5E00 | 00000600 | C0300040 |
.reloc | 61ECC000 | 00003A28 | 000C6400 | 00003C00 | 42300040 |
/4 | 61ED0000 | 00000538 | 000CA000 | 00000600 | 42400040 |
/19 | 61ED1000 | 0000C852 | 000CA600 | 0000CA00 | 42100040 |
/31 | 61EDE000 | 0000275D | 000D7000 | 00002800 | 42100040 |
/45 | 61EE1000 | 00002D9A | 000D9800 | 00002E00 | 42100040 |
/57 | 61EE4000 | 00000B5C | 000DC600 | 00000C00 | 42300040 |
/70 | 61EE5000 | 00000323 | 000DD200 | 00000400 | 42100040 |
/81 | 61EE6000 | 00003A73 | 000DD600 | 00003C00 | 42100040 |
/92 | 61EEA000 | 00000350 | 000E1200 | 00000400 | 42100040 |
Number of Exported Functions = 0329 (decimal)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Addr:61E16307 Ord: 1 (0001h) Name: sqlite3_aggregate_context
Addr:61E034E5 Ord: 2 (0002h) Name: sqlite3_aggregate_count
Addr:61EA373D Ord: 3 (0003h) Name: sqlite3_auto_extension
Addr:61E530BD Ord: 4 (0004h) Name: sqlite3_backup_finish
Addr:61E52C23 Ord: 5 (0005h) Name: sqlite3_backup_init
Addr:61E03043 Ord: 6 (0006h) Name: sqlite3_backup_pagecount
Addr:61E03038 Ord: 7 (0007h) Name: sqlite3_backup_remaining
Addr:61E50B80 Ord: 8 (0008h) Name: sqlite3_backup_step
Addr:61E25476 Ord: 9 (0009h) Name: sqlite3_bind_blob
Addr:61E2549D Ord: 10 (000Ah) Name: sqlite3_bind_blob64
Addr:61E25176 Ord: 11 (000Bh) Name: sqlite3_bind_double
Addr:61E25216 Ord: 12 (000Ch) Name: sqlite3_bind_int
Addr:61E251C7 Ord: 13 (000Dh) Name: sqlite3_bind_int64
Addr:61E2523C Ord: 14 (000Eh) Name: sqlite3_bind_null
Addr:61E03523 Ord: 15 (000Fh) Name: sqlite3_bind_parameter_count
Addr:61E1A0B4 Ord: 16 (0010h) Name: sqlite3_bind_parameter_index
Addr:61E03535 Ord: 17 (0011h) Name: sqlite3_bind_parameter_name
Addr:61E2526D Ord: 18 (0012h) Name: sqlite3_bind_pointer
Addr:61E254E4 Ord: 19 (0013h) Name: sqlite3_bind_text
Addr:61E25578 Ord: 20 (0014h) Name: sqlite3_bind_text16
Addr:61E2550B Ord: 21 (0015h) Name: sqlite3_bind_text64
Addr:61E2559F Ord: 22 (0016h) Name: sqlite3_bind_value
Addr:61E252EA Ord: 23 (0017h) Name: sqlite3_bind_zeroblob
Addr:61E25357 Ord: 24 (0018h) Name: sqlite3_bind_zeroblob64
Addr:61E03605 Ord: 25 (0019h) Name: sqlite3_blob_bytes
Addr:61E543A9 Ord: 26 (001Ah) Name: sqlite3_blob_close
Addr:61E8F3FE Ord: 27 (001Bh) Name: sqlite3_blob_open
Addr:61E56167 Ord: 28 (001Ch) Name: sqlite3_blob_read
Addr:61E8FB94 Ord: 29 (001Dh) Name: sqlite3_blob_reopen
Addr:61E56EC9 Ord: 30 (001Eh) Name: sqlite3_blob_write
Addr:61E056F9 Ord: 31 (001Fh) Name: sqlite3_busy_handler
Addr:61E0DE4E Ord: 32 (0020h) Name: sqlite3_busy_timeout
Addr:61E041C5 Ord: 33 (0021h) Name: sqlite3_cancel_auto_extension
Addr:61E055BB Ord: 34 (0022h) Name: sqlite3_changes
Addr:61E0AFAD Ord: 35 (0023h) Name: sqlite3_clear_bindings
Addr:61E532B7 Ord: 36 (0024h) Name: sqlite3_close
Addr:61E532C5 Ord: 37 (0025h) Name: sqlite3_close_v2
Addr:61E05A02 Ord: 38 (0026h) Name: sqlite3_collation_needed
Addr:61E05A46 Ord: 39 (0027h) Name: sqlite3_collation_needed16
Addr:61E21569 Ord: 40 (0028h) Name: sqlite3_column_blob
Addr:61E212F9 Ord: 41 (0029h) Name: sqlite3_column_bytes
Addr:61E213CD Ord: 42 (002Ah) Name: sqlite3_column_bytes16
Addr:61E034F3 Ord: 43 (002Bh) Name: sqlite3_column_count
Addr:61E224D3 Ord: 44 (002Ch) Name: sqlite3_column_database_name
Addr:61E224EB Ord: 45 (002Dh) Name: sqlite3_column_database_name16
Addr:61E224A0 Ord: 46 (002Eh) Name: sqlite3_column_decltype
Addr:61E224B8 Ord: 47 (002Fh) Name: sqlite3_column_decltype16
Addr:61E2BC85 Ord: 48 (0030h) Name: sqlite3_column_double
Addr:61E11245 Ord: 49 (0031h) Name: sqlite3_column_int
Addr:61E11271 Ord: 50 (0032h) Name: sqlite3_column_int64
Addr:61E2246D Ord: 51 (0033h) Name: sqlite3_column_name
Addr:61E22485 Ord: 52 (0034h) Name: sqlite3_column_name16
Addr:61E22539 Ord: 53 (0035h) Name: sqlite3_column_origin_name
Addr:61E22551 Ord: 54 (0036h) Name: sqlite3_column_origin_name16
Addr:61E22506 Ord: 55 (0037h) Name: sqlite3_column_table_name
Addr:61E2251E Ord: 56 (0038h) Name: sqlite3_column_table_name16
Addr:61E216A2 Ord: 57 (0039h) Name: sqlite3_column_text
Addr:61E2256C Ord: 58 (003Ah) Name: sqlite3_column_text16
Addr:61E11315 Ord: 59 (003Bh) Name: sqlite3_column_type
Addr:61E1129A Ord: 60 (003Ch) Name: sqlite3_column_value
Addr:61E058B2 Ord: 61 (003Dh) Name: sqlite3_commit_hook
Addr:61E05B44 Ord: 62 (003Eh) Name: sqlite3_compileoption_get
Addr:61E09874 Ord: 63 (003Fh) Name: sqlite3_compileoption_used
Addr:61E05295 Ord: 64 (0040h) Name: sqlite3_complete
Addr:61EA38E3 Ord: 65 (0041h) Name: sqlite3_complete16
Addr:61E3240D Ord: 66 (0042h) Name: sqlite3_config
Addr:61E03482 Ord: 67 (0043h) Name: sqlite3_context_db_handle
Addr:61E2B2C2 Ord: 68 (0044h) Name: sqlite3_create_collation
Addr:61E2B2F9 Ord: 69 (0045h) Name: sqlite3_create_collation16
Addr:61E2B26B Ord: 70 (0046h) Name: sqlite3_create_collation_v2
Addr:61E373B4 Ord: 71 (0047h) Name: sqlite3_create_filename
Addr:61E2AC20 Ord: 72 (0048h) Name: sqlite3_create_function
Addr:61E2AFF2 Ord: 73 (0049h) Name: sqlite3_create_function16
Addr:61E2AE6A Ord: 74 (004Ah) Name: sqlite3_create_function_v2
Addr:61E1C351 Ord: 75 (004Bh) Name: sqlite3_create_module
Addr:61E1C39B Ord: 76 (004Ch) Name: sqlite3_create_module_v2
Addr:61E2AEB0 Ord: 77 (004Dh) Name: sqlite3_create_window_function
Addr:61E03508 Ord: 78 (004Eh) Name: sqlite3_data_count
Addr:61EC4020 Ord: 79 (004Fh) Name: sqlite3_data_directory
Addr:61E02823 Ord: 80 (0050h) Name: sqlite3_database_file_object
Addr:61E505BC Ord: 81 (0051h) Name: sqlite3_db_cacheflush
Addr:61E13FC8 Ord: 82 (0052h) Name: sqlite3_db_config
Addr:61E130E6 Ord: 83 (0053h) Name: sqlite3_db_filename
Addr:61E03552 Ord: 84 (0054h) Name: sqlite3_db_handle
Addr:61E05534 Ord: 85 (0055h) Name: sqlite3_db_mutex
Addr:61E05B22 Ord: 86 (0056h) Name: sqlite3_db_readonly
Addr:61E19CBF Ord: 87 (0057h) Name: sqlite3_db_release_memory
Addr:61E1C423 Ord: 88 (0058h) Name: sqlite3_db_status
Addr:61E83B89 Ord: 89 (0059h) Name: sqlite3_declare_vtab
Addr:61E8626F Ord: 90 (005Ah) Name: sqlite3_deserialize
Addr:61E1C3B9 Ord: 91 (005Bh) Name: sqlite3_drop_modules
Addr:61E323C7 Ord: 92 (005Ch) Name: sqlite3_enable_load_extension
Addr:61E02ABE Ord: 93 (005Dh) Name: sqlite3_enable_shared_cache
Addr:61E24F5A Ord: 94 (005Eh) Name: sqlite3_errcode
Addr:61E24FCD Ord: 95 (005Fh) Name: sqlite3_errmsg
Addr:61E2B08E Ord: 96 (0060h) Name: sqlite3_errmsg16
Addr:61E0DE45 Ord: 97 (0061h) Name: sqlite3_errstr
Addr:61E6FF07 Ord: 98 (0062h) Name: sqlite3_exec
Addr:61E210D4 Ord: 99 (0063h) Name: sqlite3_expanded_sql
Addr:61E033EC Ord: 100 (0064h) Name: sqlite3_expired
Addr:61E24F95 Ord: 101 (0065h) Name: sqlite3_extended_errcode
Addr:61E05A9B Ord: 102 (0066h) Name: sqlite3_extended_result_codes
Addr:61E1A856 Ord: 103 (0067h) Name: sqlite3_file_control
Addr:61E05AF2 Ord: 104 (0068h) Name: sqlite3_filename_database
Addr:61E09829 Ord: 105 (0069h) Name: sqlite3_filename_journal
Addr:61E09858 Ord: 106 (006Ah) Name: sqlite3_filename_wal
Addr:61E542B8 Ord: 107 (006Bh) Name: sqlite3_finalize
Addr:61E0AA0B Ord: 108 (006Ch) Name: sqlite3_free
Addr:61E0B350 Ord: 109 (006Dh) Name: sqlite3_free_filename
Addr:61E0B303 Ord: 110 (006Eh) Name: sqlite3_free_table
Addr:61EAEBA0 Ord: 111 (006Fh) Name: sqlite3_fts3_may_be_corrupt
Addr:61EAEA18 Ord: 112 (0070h) Name: sqlite3_fts5_may_be_corrupt
Addr:61E05A8A Ord: 113 (0071h) Name: sqlite3_get_autocommit
Addr:61E034AA Ord: 114 (0072h) Name: sqlite3_get_auxdata
Addr:61E85A82 Ord: 115 (0073h) Name: sqlite3_get_table
Addr:61EA3F97 Ord: 116 (0074h) Name: sqlite3_global_recover
Addr:61E32C96 Ord: 117 (0075h) Name: sqlite3_hard_heap_limit64
Addr:61E3260E Ord: 118 (0076h) Name: sqlite3_initialize
Addr:61E08566 Ord: 119 (0077h) Name: sqlite3_interrupt
Addr:61E12C89 Ord: 120 (0078h) Name: sqlite3_keyword_check
Addr:61E04DDB Ord: 121 (0079h) Name: sqlite3_keyword_count
Addr:61E04DA6 Ord: 122 (007Ah) Name: sqlite3_keyword_name
Addr:61E05578 Ord: 123 (007Bh) Name: sqlite3_last_insert_rowid
Addr:61E05516 Ord: 124 (007Ch) Name: sqlite3_libversion
Addr:61E05520 Ord: 125 (007Dh) Name: sqlite3_libversion_number
Addr:61E059CB Ord: 126 (007Eh) Name: sqlite3_limit
Addr:61E42392 Ord: 127 (007Fh) Name: sqlite3_load_extension
Addr:61E22B27 Ord: 128 (0080h) Name: sqlite3_log
Addr:61E32D24 Ord: 129 (0081h) Name: sqlite3_malloc
Addr:61E33DEC Ord: 130 (0082h) Name: sqlite3_malloc64
Addr:61E30A62 Ord: 131 (0083h) Name: sqlite3_memory_alarm
Addr:61E24DDD Ord: 132 (0084h) Name: sqlite3_memory_highwater
Addr:61E24DAD Ord: 133 (0085h) Name: sqlite3_memory_used
Addr:61E405A8 Ord: 134 (0086h) Name: sqlite3_mprintf
Addr:61E017A0 Ord: 135 (0087h) Name: sqlite3_msize
Addr:61E32B6E Ord: 136 (0088h) Name: sqlite3_mutex_alloc
Addr:61E01743 Ord: 137 (0089h) Name: sqlite3_mutex_enter
Addr:61E01730 Ord: 138 (008Ah) Name: sqlite3_mutex_free
Addr:61E0176B Ord: 139 (008Bh) Name: sqlite3_mutex_leave
Addr:61E01756 Ord: 140 (008Ch) Name: sqlite3_mutex_try
Addr:61E035B8 Ord: 141 (008Dh) Name: sqlite3_next_stmt
Addr:61EA3E82 Ord: 142 (008Eh) Name: sqlite3_open
Addr:61EA3EB5 Ord: 143 (008Fh) Name: sqlite3_open16
Addr:61EA3E9D Ord: 144 (0090h) Name: sqlite3_open_v2
Addr:61E32205 Ord: 145 (0091h) Name: sqlite3_os_end
Addr:61E32AA7 Ord: 146 (0092h) Name: sqlite3_os_init
Addr:61E43C6B Ord: 147 (0093h) Name: sqlite3_overload_function
Addr:61E806E0 Ord: 148 (0094h) Name: sqlite3_prepare
Addr:61E81288 Ord: 149 (0095h) Name: sqlite3_prepare16
Addr:61E812AF Ord: 150 (0096h) Name: sqlite3_prepare16_v2
Addr:61E812D6 Ord: 151 (0097h) Name: sqlite3_prepare16_v3
Addr:61E8070E Ord: 152 (0098h) Name: sqlite3_prepare_v2
Addr:61E80B62 Ord: 153 (0099h) Name: sqlite3_prepare_v3
Addr:61E32216 Ord: 154 (009Ah) Name: sqlite3_preupdate_count
Addr:61E32234 Ord: 155 (009Bh) Name: sqlite3_preupdate_depth
Addr:61EA3F55 Ord: 156 (009Ch) Name: sqlite3_preupdate_hook
Addr:61E32256 Ord: 157 (009Dh) Name: sqlite3_preupdate_new
Addr:61E4E419 Ord: 158 (009Eh) Name: sqlite3_preupdate_old
Addr:61E0585E Ord: 159 (009Fh) Name: sqlite3_profile
Addr:61E05747 Ord: 160 (00A0h) Name: sqlite3_progress_handler
Addr:61E46B88 Ord: 161 (00A1h) Name: sqlite3_randomness
Addr:61E376AA Ord: 162 (00A2h) Name: sqlite3_realloc
Addr:61E38B36 Ord: 163 (00A3h) Name: sqlite3_realloc64
Addr:61E01788 Ord: 164 (00A4h) Name: sqlite3_release_memory
Addr:61E56F76 Ord: 165 (00A5h) Name: sqlite3_reset
Addr:61EA37CF Ord: 166 (00A6h) Name: sqlite3_reset_auto_extension
Addr:61E171F1 Ord: 167 (00A7h) Name: sqlite3_result_blob
Addr:61E17881 Ord: 168 (00A8h) Name: sqlite3_result_blob64
Addr:61E13158 Ord: 169 (00A9h) Name: sqlite3_result_double
Addr:61E16F29 Ord: 170 (00AAh) Name: sqlite3_result_error
Addr:61E170A9 Ord: 171 (00ABh) Name: sqlite3_result_error16
Addr:61E170D2 Ord: 172 (00ACh) Name: sqlite3_result_error_code
Addr:61E10958 Ord: 173 (00ADh) Name: sqlite3_result_error_nomem
Addr:61E1715E Ord: 174 (00AEh) Name: sqlite3_result_error_toobig
Addr:61E0AED4 Ord: 175 (00AFh) Name: sqlite3_result_int
Addr:61E0AF0F Ord: 176 (00B0h) Name: sqlite3_result_int64
Addr:61E0AF3A Ord: 177 (00B1h) Name: sqlite3_result_null
Addr:61E13012 Ord: 178 (00B2h) Name: sqlite3_result_pointer
Addr:61E0345E Ord: 179 (00B3h) Name: sqlite3_result_subtype
Addr:61E172DA Ord: 180 (00B4h) Name: sqlite3_result_text
Addr:61E1787B Ord: 181 (00B5h) Name: sqlite3_result_text16
Addr:61E1783D Ord: 182 (00B6h) Name: sqlite3_result_text16be
Addr:61E1785C Ord: 183 (00B7h) Name: sqlite3_result_text16le
Addr:61E178BD Ord: 184 (00B8h) Name: sqlite3_result_text64
Addr:61E16AB4 Ord: 185 (00B9h) Name: sqlite3_result_value
Addr:61E133B7 Ord: 186 (00BAh) Name: sqlite3_result_zeroblob
Addr:61E0B01D Ord: 187 (00BBh) Name: sqlite3_result_zeroblob64
Addr:61E05936 Ord: 188 (00BCh) Name: sqlite3_rollback_hook
Addr:61EA3F9E Ord: 189 (00BDh) Name: sqlite3_rtree_geometry_callback
Addr:61EA401C Ord: 190 (00BEh) Name: sqlite3_rtree_query_callback
Addr:61E86065 Ord: 191 (00BFh) Name: sqlite3_serialize
Addr:61E03C24 Ord: 192 (00C0h) Name: sqlite3_set_authorizer
Addr:61E15E97 Ord: 193 (00C1h) Name: sqlite3_set_auxdata
Addr:61E05586 Ord: 194 (00C2h) Name: sqlite3_set_last_insert_rowid
Addr:61EA3822 Ord: 195 (00C3h) Name: sqlite3_shutdown
Addr:61E32A0D Ord: 196 (00C4h) Name: sqlite3_sleep
Addr:61E229BB Ord: 197 (00C5h) Name: sqlite3_snprintf
Addr:61E32C72 Ord: 198 (00C6h) Name: sqlite3_soft_heap_limit
Addr:61E32B9D Ord: 199 (00C7h) Name: sqlite3_soft_heap_limit64
Addr:61E0855C Ord: 200 (00C8h) Name: sqlite3_sourceid
Addr:61E035F1 Ord: 201 (00C9h) Name: sqlite3_sql
Addr:61E24D55 Ord: 202 (00CAh) Name: sqlite3_status
Addr:61E24CC5 Ord: 203 (00CBh) Name: sqlite3_status64
Addr:61E6F227 Ord: 204 (00CCh) Name: sqlite3_step
Addr:61E03599 Ord: 205 (00CDh) Name: sqlite3_stmt_busy
Addr:61E0357F Ord: 206 (00CEh) Name: sqlite3_stmt_isexplain
Addr:61E03562 Ord: 207 (00CFh) Name: sqlite3_stmt_readonly
Addr:61E11166 Ord: 208 (00D0h) Name: sqlite3_stmt_status
Addr:61E197C9 Ord: 209 (00D1h) Name: sqlite3_str_append
Addr:61E197FE Ord: 210 (00D2h) Name: sqlite3_str_appendall
Addr:61E1456B Ord: 211 (00D3h) Name: sqlite3_str_appendchar
Addr:61E2077B Ord: 212 (00D4h) Name: sqlite3_str_appendf
Addr:61E017BF Ord: 213 (00D5h) Name: sqlite3_str_errcode
Addr:61E16178 Ord: 214 (00D6h) Name: sqlite3_str_finish
Addr:61E017D4 Ord: 215 (00D7h) Name: sqlite3_str_length
Addr:61E33E12 Ord: 216 (00D8h) Name: sqlite3_str_new
Addr:61E0AAFA Ord: 217 (00D9h) Name: sqlite3_str_reset
Addr:61E017E5 Ord: 218 (00DAh) Name: sqlite3_str_value
Addr:61E1F3C7 Ord: 219 (00DBh) Name: sqlite3_str_vappendf
Addr:61E0A5E7 Ord: 220 (00DCh) Name: sqlite3_strglob
Addr:61E01964 Ord: 221 (00DDh) Name: sqlite3_stricmp
Addr:61E0A602 Ord: 222 (00DEh) Name: sqlite3_strlike
Addr:61E0198A Ord: 223 (00DFh) Name: sqlite3_strnicmp
Addr:61E059BA Ord: 224 (00E0h) Name: sqlite3_system_errno
Addr:61E8578B Ord: 225 (00E1h) Name: sqlite3_table_column_metadata
Addr:61EC4024 Ord: 226 (00E2h) Name: sqlite3_temp_directory
Addr:61EA3189 Ord: 227 (00E3h) Name: sqlite3_test_control
Addr:61E05A96 Ord: 228 (00E4h) Name: sqlite3_thread_cleanup
Addr:61E0552A Ord: 229 (00E5h) Name: sqlite3_threadsafe
Addr:61E055C6 Ord: 230 (00E6h) Name: sqlite3_total_changes
Addr:61E057B5 Ord: 231 (00E7h) Name: sqlite3_trace
Addr:61E05806 Ord: 232 (00E8h) Name: sqlite3_trace_v2
Addr:61E12890 Ord: 233 (00E9h) Name: sqlite3_transfer_bindings
Addr:61E055D1 Ord: 234 (00EAh) Name: sqlite3_txn_state
Addr:61E058F4 Ord: 235 (00EBh) Name: sqlite3_update_hook
Addr:61E097AA Ord: 236 (00ECh) Name: sqlite3_uri_boolean
Addr:61E119DD Ord: 237 (00EDh) Name: sqlite3_uri_int64
Addr:61E097DD Ord: 238 (00EEh) Name: sqlite3_uri_key
Addr:61E09753 Ord: 239 (00EFh) Name: sqlite3_uri_parameter
Addr:61E03474 Ord: 240 (00F0h) Name: sqlite3_user_data
Addr:61E2146C Ord: 241 (00F1h) Name: sqlite3_value_blob
Addr:61E212EB Ord: 242 (00F2h) Name: sqlite3_value_bytes
Addr:61E213BC Ord: 243 (00F3h) Name: sqlite3_value_bytes16
Addr:61E1F3BB Ord: 244 (00F4h) Name: sqlite3_value_double
Addr:61E32FA3 Ord: 245 (00F5h) Name: sqlite3_value_dup
Addr:61E0B092 Ord: 246 (00F6h) Name: sqlite3_value_free
Addr:61E0344C Ord: 247 (00F7h) Name: sqlite3_value_frombind
Addr:61E0C477 Ord: 248 (00F8h) Name: sqlite3_value_int
Addr:61E0C484 Ord: 249 (00F9h) Name: sqlite3_value_int64
Addr:61E03433 Ord: 250 (00FAh) Name: sqlite3_value_nochange
Addr:61E305AE Ord: 251 (00FBh) Name: sqlite3_value_numeric_type
Addr:61E11827 Ord: 252 (00FCh) Name: sqlite3_value_pointer
Addr:61E03409 Ord: 253 (00FDh) Name: sqlite3_value_subtype
Addr:61E21433 Ord: 254 (00FEh) Name: sqlite3_value_text
Addr:61E22598 Ord: 255 (00FFh) Name: sqlite3_value_text16
Addr:61E223C5 Ord: 256 (0100h) Name: sqlite3_value_text16be
Addr:61E223D6 Ord: 257 (0101h) Name: sqlite3_value_text16le
Addr:61E0341E Ord: 258 (0102h) Name: sqlite3_value_type
Addr:61EC2E20 Ord: 259 (0103h) Name: sqlite3_version
Addr:61E329AA Ord: 260 (0104h) Name: sqlite3_vfs_find
Addr:61E32A44 Ord: 261 (0105h) Name: sqlite3_vfs_register
Addr:61E32B2E Ord: 262 (0106h) Name: sqlite3_vfs_unregister
Addr:61E3FAC4 Ord: 263 (0107h) Name: sqlite3_vmprintf
Addr:61E2295F Ord: 264 (0108h) Name: sqlite3_vsnprintf
Addr:61E29769 Ord: 265 (0109h) Name: sqlite3_vtab_collation
Addr:61E24E0C Ord: 266 (010Ah) Name: sqlite3_vtab_config
Addr:61E0348F Ord: 267 (010Bh) Name: sqlite3_vtab_nochange
Addr:61E04568 Ord: 268 (010Ch) Name: sqlite3_vtab_on_conflict
Addr:61E0DE9D Ord: 269 (010Dh) Name: sqlite3_wal_autocheckpoint
Addr:61E538C9 Ord: 270 (010Eh) Name: sqlite3_wal_checkpoint
Addr:61E53885 Ord: 271 (010Fh) Name: sqlite3_wal_checkpoint_v2
Addr:61E05978 Ord: 272 (0110h) Name: sqlite3_wal_hook
Addr:61E30BE6 Ord: 273 (0111h) Name: sqlite3_win32_is_nt
Addr:61EA35DE Ord: 274 (0112h) Name: sqlite3_win32_mbcs_to_utf8
Addr:61EA3607 Ord: 275 (0113h) Name: sqlite3_win32_mbcs_to_utf8_v2
Addr:61EA3737 Ord: 276 (0114h) Name: sqlite3_win32_set_directory
Addr:61EA36EB Ord: 277 (0115h) Name: sqlite3_win32_set_directory16
Addr:61EA367C Ord: 278 (0116h) Name: sqlite3_win32_set_directory8
Addr:61E30ACB Ord: 279 (0117h) Name: sqlite3_win32_sleep
Addr:61EA35BD Ord: 280 (0118h) Name: sqlite3_win32_unicode_to_utf8
Addr:61EA362D Ord: 281 (0119h) Name: sqlite3_win32_utf8_to_mbcs
Addr:61EA3656 Ord: 282 (011Ah) Name: sqlite3_win32_utf8_to_mbcs_v2
Addr:61EA359C Ord: 283 (011Bh) Name: sqlite3_win32_utf8_to_unicode
Addr:61E30A69 Ord: 284 (011Ch) Name: sqlite3_win32_write_debug
Addr:61EA5929 Ord: 285 (011Dh) Name: sqlite3changegroup_add
Addr:61EA598B Ord: 286 (011Eh) Name: sqlite3changegroup_add_strm
Addr:61EA59F1 Ord: 287 (011Fh) Name: sqlite3changegroup_delete
Addr:61EA5B40 Ord: 288 (0120h) Name: sqlite3changegroup_new
Addr:61EA596F Ord: 289 (0121h) Name: sqlite3changegroup_output
Addr:61EA59D1 Ord: 290 (0122h) Name: sqlite3changegroup_output_strm
Addr:61EA581C Ord: 291 (0123h) Name: sqlite3changeset_apply
Addr:61EA58DB Ord: 292 (0124h) Name: sqlite3changeset_apply_strm
Addr:61EA57AF Ord: 293 (0125h) Name: sqlite3changeset_apply_v2
Addr:61EA586A Ord: 294 (0126h) Name: sqlite3changeset_apply_v2_strm
Addr:61EA5AC5 Ord: 295 (0127h) Name: sqlite3changeset_concat
Addr:61EA5A4A Ord: 296 (0128h) Name: sqlite3changeset_concat_strm
Addr:61EA4AB3 Ord: 297 (0129h) Name: sqlite3changeset_conflict
Addr:61EA4B16 Ord: 298 (012Ah) Name: sqlite3changeset_finalize
Addr:61EA4AF3 Ord: 299 (012Bh) Name: sqlite3changeset_fk_conflicts
Addr:61EA571A Ord: 300 (012Ch) Name: sqlite3changeset_invert
Addr:61EA5759 Ord: 301 (012Dh) Name: sqlite3changeset_invert_strm
Addr:61E0EBC9 Ord: 302 (012Eh) Name: sqlite3changeset_new
Addr:61EA4A4C Ord: 303 (012Fh) Name: sqlite3changeset_next
Addr:61E0EB8F Ord: 304 (0130h) Name: sqlite3changeset_old
Addr:61EA4A63 Ord: 305 (0131h) Name: sqlite3changeset_op
Addr:61EA4A93 Ord: 306 (0132h) Name: sqlite3changeset_pk
Addr:61EA4984 Ord: 307 (0133h) Name: sqlite3changeset_start
Addr:61EA49E3 Ord: 308 (0134h) Name: sqlite3changeset_start_strm
Addr:61EA49B5 Ord: 309 (0135h) Name: sqlite3changeset_start_v2
Addr:61EA4A18 Ord: 310 (0136h) Name: sqlite3changeset_start_v2_strm
Addr:61EA5B49 Ord: 311 (0137h) Name: sqlite3rebaser_configure
Addr:61EA5A16 Ord: 312 (0138h) Name: sqlite3rebaser_create
Addr:61EA5C69 Ord: 313 (0139h) Name: sqlite3rebaser_delete
Addr:61EA5B99 Ord: 314 (013Ah) Name: sqlite3rebaser_rebase
Addr:61EA5C00 Ord: 315 (013Bh) Name: sqlite3rebaser_rebase_strm
Addr:61EA4213 Ord: 316 (013Ch) Name: sqlite3session_attach
Addr:61EA4837 Ord: 317 (013Dh) Name: sqlite3session_changeset
Addr:61EA484E Ord: 318 (013Eh) Name: sqlite3session_changeset_strm
Addr:61EA5C8E Ord: 319 (013Fh) Name: sqlite3session_config
Addr:61EA4099 Ord: 320 (0140h) Name: sqlite3session_create
Addr:61EA4165 Ord: 321 (0141h) Name: sqlite3session_delete
Addr:61EA435F Ord: 322 (0142h) Name: sqlite3session_diff
Addr:61EA48B5 Ord: 323 (0143h) Name: sqlite3session_enable
Addr:61EA48F0 Ord: 324 (0144h) Name: sqlite3session_indirect
Addr:61EA492B Ord: 325 (0145h) Name: sqlite3session_isempty
Addr:61EA4976 Ord: 326 (0146h) Name: sqlite3session_memory_used
Addr:61EA489B Ord: 327 (0147h) Name: sqlite3session_patchset
Addr:61EA4873 Ord: 328 (0148h) Name: sqlite3session_patchset_strm
Addr:61EA41F8 Ord: 329 (0149h) Name: sqlite3session_table_filter
1. Основные функции библиотеки sqlite3.dll
Функции SQLite позволяют выполнять следующий набор операций:
1. Создание в базе-данных новой таблицы;
2. Заполнение таблицы записями;
3. Чтение строк и столбцов в соответствии с заданным условием;
4. Изменение существующей информации;
5. Удаление записей из ячеек таблицы.
Из этого списка, нашим интересам удовлетворяет только пункт(3), поскольку мы планируем вытягивать из баз-данных кукисы и пароли интернет-браузеров. Если рассматривать возможности программирования всех операций, то основной посыл статьи уйдёт на пятый план, так-что лучше остановимся на одном. По сути, поняв общий принцип формирования запросов, без особого труда можно будет выполнять любые операции – тут главное разобраться, что такое запрос и кто его выполняет.
1.1. sqlite3_open_v2(), sqlite3_close()
База – это файл данных. Согласно общепринятому алгоритму работы с файлами, для начала базу нужно открыть функцией sqlite3_open_v2(). Во-второй этой версии, в прототип были добавлены два дополнительных параметра: flags и zVfs. Последний означает Virtual-File-System (vfs) и нам не нужен. Зато флаг даёт возможность не только открывать базу, но и создавать её. Конкретное действие определяется перечисленными ниже константами:
C-подобный:
sqlite3_open_v2 ( ;//<--- в EAX возвращает SQLITE_ОК = 0, и хэндл базы
dbName dd 0 ;// указатель на имя базы-данных
dbHndl dd 0 ;// указатель на переменную, куда возвратится хэндл
flags dd 0 ;// флаги открытия (чтение/запись/создание)
zVfs dd 0 ;// 0
);
;//*************************************
;// Флаги для операций открытия файлов
;//*************************************
SQLITE_OPEN_READONLY = 0x0001
SQLITE_OPEN_READWRITE = 0x0002
SQLITE_OPEN_CREATE = 0x0004
SQLITE_OPEN_DELETEONCLOSE = 0x0008
SQLITE_OPEN_EXCLUSIVE = 0x0010
SQLITE_OPEN_AUTOPROXY = 0x0020
SQLITE_OPEN_URI = 0x0040
SQLITE_OPEN_MAIN_DB = 0x0100
SQLITE_OPEN_TEMP_DB = 0x0200
SQLITE_OPEN_TRANSIENT_DB = 0x0400
SQLITE_OPEN_MAIN_JOURNAL = 0x0800
SQLITE_OPEN_TEMP_JOURNAL = 0x1000
SQLITE_OPEN_SUBJOURNAL = 0x2000
SQLITE_OPEN_MASTER_JOURNAL = 0x4000
SQLITE_OPEN_NOMUTEX = 0x8000
SQLITE_OPEN_FULLMUTEX = 0x10000
SQLITE_OPEN_SHAREDCACHE = 0x20000
SQLITE_OPEN_PRIVATECACHE = 0x40000
SQLITE_OPEN_WAL = 0x80000
Данная функция открытия базы проделывает огромный объём работы, подготавливая контент и окружение для всех последующих функций sqlite3.dll. Она копирует содержимое базы в оперативную память ОЗУ, выстраивает локальную таблицу указателей на инфо-ячейки таблицы и многое другое. Если open_v2() предоставляет программные ресурсы, то родственная ей функция sqlite3_close() наоборот освобождает их. Однако в её вызове нет необходимости, если далее закрывается сама программа, т.к. ExitProcess() на выходе в любом случае проделывает аналогичную работу, освобождая глобальные ресурсы процесса на более низком уровне.
1.2. Операторы запросов SQLite
Значит базу открыли, и теперь нужно произвести с ней какие-либо действия. Для этого, мы должны послать ядру соответствующий запрос, который состоит как-минимум из двух операторов: SELECT и FROM (рассматриваем чтение). Об этом, прямым текстом сообщает и название языка программирования "Structured Query Language", или язык структурированных запросов. Исторически, операторы любой СУБД делятся на 4 типа, и SQLite здесь не исключение:
Операторы определения данных (Data Definition Language, DDL):
• CREATE – создаёт объект (базу, таблицу и т.д.);
• ALTER – изменяет объект;
• DROP – удаляет объект.
Операторы манипуляции данными (Data Manipulation Language, DML):
• SELECT – запрашивает (выбирает) данные из таблицы, удовлетворяющие условиям WHERE;
• INSERT – добавляет новую информацию;
• UPDATE – изменяет существующие данные;
• DELETE – удаляет данные.
Операторы определения доступа к данным (Data Control Language, DCL):
• DENY – устанавливает запрет, имеющий приоритет над разрешением;
• GRANT – разрешает определённые операции с объектом;
• REVOKE – отзывает ранее выданные разрешения.
Операторы управления транзакциями (Transaction Control Language, TCL):
• COMMIT – применяет транзакцию;
• ROLLBACK – откатывает все изменения, в контексте текущей транзакции;
• SAVEPOINT – делит транзакцию на мелкие части.
Как видим, для обычного чтения данных используется оператор SELECT, которому передаются ещё несколько уточняющих запрос аргументов – это имена столбцов в таблице (т.е. что именно интересует), имя таблицы через оператор FROM (т.е.где искать, поскольку таблиц в одной базе может быть несколько), и если нужно условие, посредством оператора WHERE. Вот пара простых примеров оформления запросов:
C-подобный:
;// прочитать все данные из таблицы "cookies"
select#1 db 'SELECT * FROM cookies',0
;// прочитать только столбцы "key" и "name" из таблицы "cookies"
select#2 db 'SELECT key, name FROM cookies',0
Для начала нам этого хватит, а с диалектом более сложных запросов мы ознакомимся в конце этой статьи. Несколько линков по теме:
Оператор SELECT:
Ссылка скрыта от гостей
Основные запросы SQL, которые должен знать каждый программист:
Ссылка скрыта от гостей
1.3. prepare() и finalize() – подготовка оператора запроса
На следующем этапе, подготовленный запрос в виде текстовой строки необходимо скомпилировать в байт-код, чем занимается синтаксический анализатор функции sqlite3_prepare_v2(). Переварив строку, эта функция модифицирует её в соответствующий формат и помещает полученный бинарник в память, а нам возвращает лишь дескриптор на него. В документации, этот дескриптор называют "STMT", что означает Prepared-Statement-Object (готовый объект заявления).
В последующих операциях чтения, мы должны будем передавать этот объект всем функциям-исполнения конкретно данного запроса. Если-же захотим сменить запрос на другой (с иными операторами), то сначала нужно аннулировать предыдущий функцией sqlite3_finalize(), и только потом оформлять новый, обратно функцией prepare_v2(). Вот её прототип:
C-подобный:
sqlite3_prepare_v2 ( ;//<--- на выходе 0 в EAX означает OK!
dbHndl dd 0 ;// хэндл базы от sqlite_open_v2()
zSql dd 0 ;// указатель на строку операторов запроса SQLite
nByte dd 0 ;// длина запроса в байтах (-1 = до терминального нуля)
pStmt dd 0 ;// линк на переменную, куда вернётся дескриптор запроса
pTail dd 0 ;// 0 = хвост запроса (нам не нужен)
);
В базовой версии этой функции необходимо было всегда финализировать запросы, перед тем-как оформлять новые. Но в усовершенствованной версии(2) необходимость в этом отпала, т.к. автор посчитал данное действо само-собой разумеющимся, и зашил его внутрь исполняющих запрос функций. Теперь, если запрос отрабатывает до конца, то сбрасывать его не нужно. Однако если мы хотим прервать запрос на половине исполнения (например планировали чтение всех строк базы, а потом решили остановиться на 10-ой), то вызов sqlite3_finalize() в этом случае обязателен. Данный нюанс способен изрядно попортить нервы, поэтому не сбрасывайте его со-счетов. По большому счёту, в финализации отработанных запросов нет ничего страшного, поэтому можно действовать по усмотрению.
1.4. step() и exec() – исполнение запроса
Непосредственным исполнением предписанных в запросах операций занимаются две функции – это sqlite3_step() и sqlite3_exec(). Первая немного предпочтительней, поскольку позволяет более тонко контролировать процесс исполнения, хотя для чтения каждой из строк таблицы её нужно вызывать в цикле. Это означает, что на каждом шаге Step, функция просто перемещает указатель на следующую строку, и если это не последняя, то возвращает в регистре EAX константу SQLITE_ROW=64h (есть ещё строки), иначе SQLITE_DONE=65h (выполнено и достигли конца таблицы).
Что делать дальше с этой строкой определяют уже
Ссылка скрыта от гостей
функции sqlite3_step(). Например, сместившись на очередную позицию, мы можем запросить внутри цикла следующие из них, которые будем использовать в примерах ниже:• sqlite3_column_type() – возвращает константу, определяющую тип данных в столбце;
• sqlite3_column_text() – возвращает указатель на строковые данные столбца;
• sqlite3_column_int() – возвращает значение (целое 32-бит число) столбца в текущей строке;
• sqlite3_column_blob() – возвращает указатель на массив двоичных данных столбца;
• sqlite3_column_bytes() – возвращает размер данных в текущей ячейки;
Прототипы у всех этих методов одинаковые – в первом аргументе передаём дескриптор скомпилированного функцией sqlite3_prepare_v2() запроса, а во-втором – индекс столбца для чтения (он привязан к последовательности в запросе, а не к порядковому номеру столбца в глобальной таблице). Здесь уместным будет замечание, что столбцы в таблицах любой базы-данных нумеруются начиная с нуля, а строки с единицы. Метод sqlite3_column_type() может возвращать одну из перечисленных ниже констант:
Как видим, SQLite не имеет отдельного класса для хранения даты/времени – они определяются в виде значений INTEGER, FLOAT или TEXT. При этом предпочтительный вариант именно TEXT, поскольку при помощи операторов ASC/DESC позволяет сортировать строки по дате. В остальных вариантах, эта возможность не поддерживается. Вот как они представляются в ячейках таблицы. Здесь можно ознакомиться с деталями:
Ссылка скрыта от гостей
• TEXT – дата в формате "YYYY-MM-DD HH:MM:SS.SSS"
• FLOAT – число дней, прошедших с полудня в Гринвиче 24 ноября 4714 до нашей эры.
• INTEGER – количество секунд с момента 1970-01-01 00:00:00 UTC.
Вторая функция исполнения запросов sqlite3_exec() присваивает себе право проделывать всю работу без нашего с вами участия. Её можно рассматривать как авто-Step, без применения циклов. Интерфейс представляет собой оболочку "три-в-одном", внутри которой вызываются сразу три рассмотренные выше функции: prepare(), step() и finalize(). Это сокращает исходный код приложения, зато лишает нас возможности контролировать процесс. Прототип данной функции лежит на официальном сайте по
Ссылка скрыта от гостей
линку.2.0. Практика – собираем информацию о базе-данных
Теперь посмотрим, как выглядит всё это хозяйство на практике. В примере я сброшу на консоль общую информацию о базе SQLite, в которой хранятся кукисы браузера Chrome. Чтобы не мешать работе браузера, сначала нужно будет сформировать путь до его кукисов, и скопировать их в свою директорию. Функция из shell32.dll SHGetFolderPathA() с ключом CSIDL_LOCAL_APPDATA возвратит нам папку юзера
..\AppData\Local
, к которой добавим строку с адресом кукисов хрома. Не смотря на то, что функция устаревшая, её не оказалось в инклуде импорта FASM\INCLUDE\API\SHELL32.INC
, поэтому добавим её туда самостоятельно. Вот исходник и результат его работы:
C-подобный:
format pe console
include 'win32ax.inc'
include 'equates\sqlite3.inc'
entry start
;//------------
.data
cookDbName db 'Cookies.db',0 ;//<--- имя для скопированной базы
cookHndl dd 0
cookPath db 128 dup(0)
szCook db '\Google\Chrome\User Data\Default\Cookies',0
typeTable dd 0,szInt,szFloat,szText,szBlob,szNull ;//<--- таблица с именами типов данных
szInt db 'INTEGER',0
szFloat db 'FLOAT',0
szText db 'TEXT',0
szBlob db 'BLOB',0
szNull db 'NULL',0
select db 'SELECT * FROM cookies',0 ;//<---//**** строка запроса с операторами ****//
index dd 0 ;// будет индексом столбца
stmt dd 0 ;// дескриптор скомпилированного запроса
buff db 0 ;// для производственных нужд..
;//------------
.code
start: invoke SetConsoleTitle,<'*** Chrome cookies DB info ***',0>
;// Формируем путь и копируем файл кукисов из Хрома
invoke SHGetFolderPathA,0,CSIDL_LOCAL_APPDATA,0,0,cookPath
invoke lstrcat,cookPath,szCook
invoke CopyFile,cookPath,cookDbName,0
or eax,eax ;//<----------- ошибка?
jne @ok
cinvoke printf,<10,' ERROR! Google path not found.',0>
jmp @exit
@ok: cinvoke printf,<10,' Cookies path: %s',10,0>,cookPath
;//****************************************************************
;//************* Работа с таблицей "SQLite" *********************
;//****************************************************************
;// Подключаемся к базе и оформляем запрос
cinvoke sqlite3_open_v2,cookDbName,cookHndl,SQLITE_OPEN_READONLY,0
cinvoke sqlite3_prepare_v2,[cookHndl],select,-1,stmt,0
;// Подпрограммы возвращают версию DLL, имя базы и таблицы, кол-во столбцов.
cinvoke sqlite3_libversion
cinvoke printf,<10,' DLL library..: v%s',0>,eax
cinvoke sqlite3_column_database_name,[stmt],[index]
cinvoke printf,<10,' Database name: %s',0>,eax
cinvoke sqlite3_column_table_name,[stmt],[index]
cinvoke printf,<10,' Table name...: %s',0>,eax
cinvoke sqlite3_column_count,[stmt]
cinvoke printf,<10,' Table columns: %d',10,\
10,' Columns list...',10,0>,eax
;// Цикл Step с выводом имени столбца, и типом его значений
@nextColumn:
cinvoke sqlite3_column_origin_name,[stmt],[index]
cmp eax,0
je @exit
cinvoke printf,<10,' %3d. %-16s',0>,[index],eax ;// числа форматируют отступ
cinvoke sqlite3_step,[stmt] ;// функция,
cinvoke sqlite3_column_type,[stmt],[index] ;// ..и её метод.
mov esi,typeTable
shl eax,2
mov eax,[esi+eax]
cinvoke printf,<' %s',0>,eax
inc [index] ;// следующий индекс
jmp @nextColumn ;// повторить для всех столбцов..
@exit: cinvoke sqlite3_finalize,[stmt]
cinvoke _getch
cinvoke exit,0
;//------------
section '.idata' import data readable
library kernel32,'kernel32.dll',shell32,'shell32.dll',\
msvcrt,'msvcrt.dll',sqlite3,'sqlite3.dll'
include 'api\kernel32.inc'
include 'api\shell32.inc'
include 'api\sqliteAPI.inc' ;//<--- импорт API
include 'api\msvcrt.inc' ;// ^^^^^^^^^^
Так, не открывая базу в стороннем редакторе, мы получили имена столбцов и если это шелл-код, он может сформировать строку запроса прямо на-лету. Ясно, что структура таблицы кукисов известна всем, но если мы столкнёмся с какой-нибудь базой на удалённом узле, то "слепое" вычисление имени столбцов (и типов данных в них) может сыграть нам на руку. К примеру обнаружив поле BLOB (Binary-Long-Object, массив двоичных данных) можно сделать вывод, что перед нами зашифрованное содержимое, и это может быть пароль или другая конфиденциальная инфа.
2.1. Практика – чтение "cookies" браузеров
Теперь чуть усложним задачу, и попробуем изъять из этой базы все кукисы. Читать будем обозначенные на скрине выше поля, но сначала дадим короткое определение, что такое вообще "cookie", какие они бывают, и зачем нужны.
Ссылка скрыта от гостей
можно найти более развёрнутый ответ на эти вопросы, от самих разрабов Хром. -----------------------
Кукисы – это текстовые файлы у нас на компьютерах, в которых хранится инфа о наших предыдущих действиях на сайтах. Когда мы совершаем какое-то действие (например, вводим пароли входа в аккаунт), сервер сбрасывает эту информацию в куки и отправляет браузеру вместе со страницей. Теперь, когда мы следующий раз заходим на тот-же сайт или страницу, браузер отправляет куки обратно. Они бывают временными и постоянными – в браузерах Хром, время их жизни определяет значение в столбце "expires_utc". Постоянные куки остаются на компьютере, когда мы закрываем вкладку сайта, а временные удаляются.
По сути куки не опасны – это обычный текст. Они не могут запускать процессы и взаимодействовать с ОС как-бы то нибыло. Но некоторые подозрительные личности в маске джокера могут попытаться украсть их, чтобы отследить наши действия в сети, или зайти в аккаунт без авторизации. Именно это и представляет потенциальную угрозу в хранение кукисов. Кроме входов в аккаунты они умеют запоминать:
• предпочтения юзеров, например язык/валюту/шрифт;
• товары, которые мы просматривали или добавили в корзину;
• текст, который мы вводили на сайте раньше;
• IP-адрес и местоположение пользователя;
• время посещения сайта;
• версию ОС и браузера;
• клики и переходы.
Согласно общепринятым правилам, серверы могут высылать кукисы строго предопределённого типа, которые можно распознать по их именам:
• _ga – кукис аналитики (стистика и прочее);
• _gads, _gas_ – реклама на партнёрских сайтах;
• _gcl_ – отслеживание конверсий;
• CGIC – ускоряет действия в поисковой строке (интерактивный поиск);
• DSID – киллер рекламы для авторизированных юзеров;
• IDE, ANID – показ рекламы юзерам без реги;
• NID, VISITOR_INFO1_LIVE – идентификатор настроек и предпочтений юзера (язык, шрифт и т.д.);
• PREF, YSC, pm_sess – предотвращение спама, и настройки медиа-проигрывателя в ютубе (громкость, размер и т.д.);
• SID, HSID – цифровая подписью и зашифрованные сведения об аккаунте Google.
Ну и теперь немного о самом коде..
Поскольку значения всех столбцов таблицы нам не интересны (см.скрин выше), то в строке запроса перечисляем только нужные из них. То-есть запрос будет такого вида:
select db 'SELECT host_key, name FROM cookies',0
Кстати макс.значение индекса столбцов для методов функции sqlite3_step() в этом случае будет =1 (отсчёт с нуля). На запрос такого рода получим всего по два значения из каждой строки – это имя хоста и кукиса. Раз-уж разборки с паролем мы оставили для сл.части статьи, то прицепом к именам можно вывести хотя-бы время создания/окончания действия кукиса. Значит добавим к этому запросу ещё два столбца – creation_utc и expires_utc. Но здесь буйком всплывает проблема преобразования значения INTEGER в строку даты/времени.
Одной из примечательных особенностей языка SQL является возможность оформлять вложенные запросы – т.е. в основной запрос помещаем дочерний под-запрос. Немного попыхтев при его обработке, ядро выдаст результаты обоих, и остаётся вывести их на консоль в подобающем виде. В данном случае, для преобразования времени мы воспользуемся этой фишкой и вложим в запрос целую функцию SQLite для работы с датами strftime(). Она чем-то напоминает printf() из msvcrt.dll и ожидает в аргументе спецификаторы типа %s. В конечном итоге, оформленный по этим правилам строка запроса будет выглядеть так, и мы получим время в текстовом виде:
C-подобный:
select db "SELECT host_key, name,"
db "strftime('%Y.%m.%d %H:%M',"
db "creation_utc /1000000 + (strftime('%s','1601-01-01')),'unixepoch','localtime'),"
db "strftime('%Y.%m.%d %H:%M',"
db " expires_utc /1000000 + (strftime('%s','1601-01-01')),'unixepoch','localtime')"
db "FROM cookies",0
В остальном – всё довольно прозрачно. Значит делаем Step и проверяем его выхлоп на SQLITE_ROW, что означает наличие следующих строк в таблице. Теперь, внутри цикла зовём метод sqlite3_column_text() и в регистре EAX получаем указатель на данные в текстовом виде, текущего столбца и строки. Вызываем этот-же метод для всех столбцов, которые перечислены в запросе. При этом не забываем каждый раз добавлять к индексу 1. Можно предусмотреть и переменную для подсчёта обработанных строк – это будет счётчиком кукисов в базе. Вот пример такого алго:
C-подобный:
format pe console
include 'win32ax.inc'
include 'equates\sqlite3.inc'
entry start
;//------------
.data
cookPath db 128 dup(0)
szCook db '\Google\Chrome\User Data\Default\Cookies',0
cookDbName db 'Cookies.db',0
cookHndl dd 0
select db "SELECT host_key, name,"
db "strftime('%Y.%m.%d %H:%M',"
db "creation_utc /1000000 + (strftime('%s','1601-01-01')),'unixepoch','localtime'),"
db "strftime('%Y.%m.%d %H:%M',"
db " expires_utc /1000000 + (strftime('%s','1601-01-01')),'unixepoch','localtime')"
db "FROM cookies",0
counter dd 0
stmt dd 0
buff db 0
;//------------
.code
start: invoke SetConsoleTitle,<'*** Chrome cookies list ***',0>
;// Формируем путь и копируем файл кукисов из Хрома
invoke SHGetFolderPathA,0,CSIDL_LOCAL_APPDATA,0,0,cookPath
invoke lstrcat,cookPath,szCook
invoke CopyFile,cookPath,cookDbName,0
or eax,eax ;//<----------- ошибка?
jne @ok
cinvoke printf,<10,' ERROR! Google path not found.',0>
jmp @exit
@ok: cinvoke printf,<10,' Cookies path: %s',10,0>,cookPath
;//****************************************************************
;//************* Работа с таблицей "SQLite" *********************
;//****************************************************************
;// Подключаемся к базе и оформляем запрос
cinvoke sqlite3_open_v2,cookDbName,cookHndl,SQLITE_OPEN_READONLY,0
cinvoke sqlite3_prepare_v2,[cookHndl],select,-1,stmt,0
;// Цикл чтения и обработки строк таблицы
@@: cinvoke sqlite3_step,[stmt]
cmp eax,SQLITE_ROW ;// есть ещё строки?
jne @free ;// нет – на выход.
cinvoke sqlite3_column_text,[stmt],0 ;//<--- индекс(0) в запросе = host_key
cinvoke printf,<10,\
10,' Host.......: %s',0>,eax
cinvoke sqlite3_column_text,[stmt],1 ;//<--- индекс(1) = name
cinvoke printf,<10,' Cookie name: %s',0>,eax
cinvoke sqlite3_column_text,[stmt],2 ;//<--- индекс(2) = creation_utc
cinvoke printf,<10,' LifeTime...: %s',0>,eax
cinvoke sqlite3_column_text,[stmt],3 ;//<--- индекс(3) = expires_utc
cinvoke printf,<' --> %s',0>,eax
inc [counter] ;// считаем кукисы
jmp @b ;// уходим на повтор..
@free: cinvoke printf,<10,10,' ******************************',\
10,' Total cookies found: %d',10,0>,[counter]
@exit: cinvoke _getch
cinvoke exit,0
;//------------
section '.idata' import data readable
library kernel32,'kernel32.dll',shell32,'shell32.dll',\
msvcrt,'msvcrt.dll',sqlite3,'sqlite3.dll'
include 'api\kernel32.inc'
include 'api\shell32.inc'
include 'api\sqliteAPI.inc' ;//<--- импорт API
include 'api\msvcrt.inc' ;// ^^^^^^^^^^^^^^
Обратите внимание на время жизни последнего кукиса с достопочтенного сайта wasm.in. Актуальность его заканчивается далеком в прошлом 1601-год (время отсчёта Unix-систем). Это потому, что данный кукис вечный и в его столбце expires_utc лежит значение нуль. По идее, такие ошибки нужно обрабатывать, что было делать мне лень.
На этом ставлю точку.
В скрепке можно будет найти два экзешника, и три инклуда: SqliteAPI, MsvcrtAPI и sqlite3.inc с описанием констант. Всем удачи, пока!
Вложения
Последнее редактирование: