К примеру, есть программа, из которой необходимо экспортировать какие-то данные. Это может быть, например каталог товаров конкурента, база вопросов для тестирования и пр.
Обычно разработчики дают файлам с данными вполне осмысленные имена, и найти их несложно (расширение файла значения не имеет, важен внутренний формат). Здесь я рассмотрю вариант с базой данных на SQLite.
Выбор среди расширений для защиты SQLite баз данных небольшой. К тому же некоторые из них коммерческие. Компания Hwaci, Inc., отвечающая за разработку SQLite предлагает пару таких коммерческих расширений:
- SQLite EncryptionExtension (SEE) шифрует БД по мере того как она пишется на диск, по-видимому эффективная штука.
- Compressed and Encrypted Read-Only Database (CEROD) это расширение пошло дальше и не только шифрует БД, но еще и обеспечивает сжатие. Сжатие естественно уменьшает занимаемое базой данных место, но есть побочный эффект база данных становится read-only. Предлагают использовать при распространении лицензионных материалов.
Первый шаг определить зашифрована БД или нет. При моем первом знакомстве с SQLite я использовал программу SQLabs SQLiteManager. А эта программа иногда при открытии БД показывала сообщение «Database file seems to be encrypted. Please enter the encryption key». Казалось, что БД защищена каким-нибудь SEE или CEROD. Однако БД нормально открывалась стандартным sqlite3.exe или другой тулзой например SQLite Administrator.
Далее если схема БД нетривиальная, то разобраться что к чему довольно сложно. Или названия таблиц и полей могут быть сокращены до неузнаваемости. В таких случаях, хорошо бы посмотреть на SQL-запросы, которые программа делает к БД.
Способ, который далее описывается, работает, только если SQLite представлен в программе в виде внешней библиотеки (sqlite3.dll). Идея в том чтобы скомпилировать свой SQLite с логированием запросов и подменить им тот, который используется программой.
Я буду использовать компилятор Visual C++ 2010, но в принципе это неважно.
1) Открываем MSVC и создаем новый Win32 Project. В Application Wizard выбираем DLL и ставим галочку «Empty project».
2) Добавим в проект файлы sqlite3.h и sqlite3.c из исходников SQLite.
3) Также скопируем в папку с проектом файл sqlite3.def из дистрибутива SQLite. .def файл можно сгенерировать из файла sqlite3.dll с помощью утилиты dumpbin.
4) В свойствах проекта, добавим sqlite3.def в Linker -> Input -> Module definition file.
5) Также в С/С++ -> Preprocessor -> Preprocessor Definitions можно добавить:
- WIN32
- _DEBUG
- _WINDOWS
- _USRDLL
- SQLITE3_EXPORTS
- SQLITE_ENABLE_RTREE
- SQLITE_ENABLE_COLUMN_METADATA
- SQLITE_ENABLE_ATOMIC_WRITE
- SQLITE_ENABLE_FTS3
- SQLITE_ENABLE_FTS3_PARENTHESIS
- SQLITE_ENABLE_FTS4
- SQLITE_ENABLE_IOTRACE
- SQLITE_ENABLE_LOCKING_STYLE
- SQLITE_ENABLE_MEMORY_MANAGEMENT
- SQLITE_ENABLE_MEMSYS3
- SQLITE_ENABLE_MEMSYS5
- SQLITE_ENABLE_STAT2
- SQLITE_ENABLE_STAT3
- SQLITE_ENABLE_UNLOCK_NOTIFY
- SQLITE_ENABLE_UPDATE_DELETE_LIMIT
6) Изменим код в файле sqlite3.c, тут:
SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
int rc;
FILE *fp;
fp = fopen("c:\sqlite3_prepare_v2.txt","a+");
fprintf(fp, "%snn", zSql);
fclose(fp);
rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
и тут:
SQLITE_API int sqlite3_exec(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite3_callback xCallback, /* Invoke this callback routine */
void *pArg, /* First argument to xCallback() */
char **pzErrMsg /* Write error messages here */
){
int rc = SQLITE_OK; /* Return code */
const char *zLeftover; /* Tail of unprocessed SQL */
sqlite3_stmt *pStmt = 0; /* The current SQL statement */
char **azCols = 0; /* Names of result columns */
int nRetry = 0; /* Number of retry attempts */
int callbackIsInit; /* True if callback data is initialized */
FILE *fp;
fp = fopen("c:\sqlite3_exec.txt","a+");
fprintf(fp, "%snn", zSql);
fclose(fp);
7) Теперь остается сделать билд (Ctrl + Shift + B) и подменить оригинальный sqlite3.dll используемый программой нашим новым sqlite3.dll. Далее, когда программа будет обращаться к БД через эти функции то все запросы будут попадать в лог.
После получения SQL запросов можно увидеть что-нибудь типа
SELECT customFunction();
что означает использование самописных расширений. Они могут быть вшиты в программу или быть «загружаемыми» (loadable) DLL. Загружаемое расширение можно загрузить в свою программу с помощью функции:
int sqlite3_load_extension( sqlite3 *db, const char *ext_name, const char *entry_point, char **error )
Автор: Informatik