Skip to content

Instantly share code, notes, and snippets.

@ross-spencer
Forked from angea/sqlbuddy.py
Created December 30, 2024 07:41
Show Gist options
  • Save ross-spencer/752a622f748c3a2be52b4a8d2f8a0b5f to your computer and use it in GitHub Desktop.
Save ross-spencer/752a622f748c3a2be52b4a8d2f8a0b5f to your computer and use it in GitHub Desktop.
Scans SQLite files for known features (UserVersion, AppId, Schema...)
#!/usr/bin/env python3
# Scans SQLite files for known features (UserVersion, AppId, Schema...)
# Ange Albertini 2024
import argparse
import hashlib
import sqlite3
import sys
user_versions = {
b"_MTN": "Monotone source repository",
}
application_ids = {
b"\x0F\x05\x51\x11": "Fossil repository",
b"\x0F\x05\x51\x12": "Fossil checkout",
b"\x0F\x05\x51\x13": "Fossil configuration",
b"Acrn": "FlyingMeat Acorn",
b"BeDb": "Bentley Systems BeSQLite",
b"BeLn": "Bentley Systems Localization",
b"Esri": "Esri Spatially-Enabled",
b"MPBX": "MBTiles tileset",
b"j\3WD": "TeXnicard card",
b"CEWE": "CEWE Photobuch",
b"TOIR": "Riot Games patcher",
b"TMPR": "TwinMotion",
b"V35\0": "Vector35 Binary Ninja",
b"\x5C\xDE\x09\xEF": "Maple Workbook",
b"AUDY": "Audacity3 Project file",
b"\x5E\x96\x73\x0E": "Corsair iCue",
b"CHEW": "Chewing IME",
# Bitcoin
# magic: https://en.bitcoin.it/wiki/Protocol_documentation#Message_structure
b"\xF9\xBE\xB4\xD9": "Bitcoin Wallet", # MainNet
b"\x0B\xBE\xB4\xD9": "Bitcoin Wallet", # Testnet3
b"\xFA\xBF\xB5\xDA": "Bitcoin Wallet", # testnet/regtest
b"\x0A\x03\xCF\x40": "Bitcoin Wallet", # signet
b"\xF9\xBE\xB4\xFE": "Bitcoin Wallet", # namecoin
b"GPKG": "OGC GeoPackage",
b"GP10": "OGC GeoPackage", # v1.0
}
schemas = {
'CREATE TABLE GlobalState (LastSuccessfulSync DATE, HTTPModifiedDate DATE, FileLastModifiedDate DATE, TestPopulation VARCHAR(30), TestSegment VARCHAR(30),'
' ProductName VARCHAR(30), ProductMajorVersion INTEGER, ProductMinorVersion INTEGER, LicenseState VARCHAR(15), Language VARCHAR(15), OEM VARCHAR(15), Channel VARCHAR(15) );\n'
'CREATE TABLE IPMMessage (ID INTEGER PRIMARY KEY, Title VARCHAR(50), Content VARCHAR(100), ExternalLink VARCHAR(60), AcceptString VARCHAR(20), RejectString VARCHAR(20),'
' StartDate DATE, ExpiryDate DATE, LastModifiedDate DATE, Priority INTEGER, DisplayLocation INTEGER, Context INTEGER, PairID INTEGER, MinProductVersion VARCHAR(15),'
' MaxProductVersion VARCHAR(15), CCID INTEGER, Status INTEGER, AlreadyDisplayed INTEGER, DisplayCount INTEGER, Version INTEGER, MessageFlag INTEGER );\n'
'CREATE TABLE MsgAssetMap (MessageID INTEGER NOT NULL, AssetContext VARCHAR(50) NOT NULL, AssetTitle VARCHAR(100), AssetAction VARCHAR(100), primaryURI VARCHAR(60),'
'secondaryURI VARCHAR(60),flags INTEGER DEFAULT 0, AssetType VARCHAR(10) , locationId VARCHAR(32) , LastSyncDate DATE , LastModDate DATE , PRIMARY KEY (MessageID, AssetContext ),'
' FOREIGN KEY (MessageID) REFERENCES IPMMessage(ID) ON DELETE CASCADE );\n'
'CREATE TABLE ControlMessages (CMDisplayLocation INTEGER, CMMessage VARCHAR(1000) NOT NULL, CMValue VARCHAR(1000), PRIMARY KEY (CMDisplayLocation, CMMessage ) );\n'
'CREATE TABLE MessageProperties (msgID INTEGER NOT NULL, messagePropKey VARCHAR(50) NOT NULL, messagePropVal VARCHAR(100), PRIMARY KEY (msgID, messagePropKey ),'
' FOREIGN KEY (msgID) REFERENCES IPMMessage(ID) ON DELETE CASCADE );\n': 'Adobe In-Product Messages',
'CREATE TABLE pref_events (event_id INTEGER NOT NULL PRIMARY KEY, event_time INTEGER NOT NULL,'
' instance_guid TEXT NOT NULL, section_name TEXT NOT NULL, pref_key TEXT, pref_value TEXT, client_nonce INTEGER NOT NULL, added INTEGER NOT NULL );\n'
'CREATE TABLE version_table ( version INTEGER NOT NULL PRIMARY KEY );\n': 'Adobe SharedDataEvents',
'CREATE TABLE files (\n'
' path_id integer primary key check(path_id != 0),\n'
' path text not null check(length(path) != 0),\n'
' size integer not null,\n'
' timestamp integer not null,\n'
' permissions integer not null,\n'
' symlink text not null,\n'
' chunking_version integer not null,\n'
' min_chunk_size integer not null,\n'
' chunk_size integer not null,\n'
' max_chunk_size integer not null,\n'
' type integer not null\n'
');\n'
'CREATE TABLE chunks (\n'
' path_id integer not null,\n'
' offset integer not null,\n'
' id integer not null check (id != 0),\n'
' size integer not null,\n'
' foreign key (path_id) references files(path_id),\n'
' primary key (path_id, offset)\n'
') without rowid;\n'
'CREATE TABLE sqlite_stat1(tbl,idx,stat);\n': "Riot Games patcher",
'CREATE TABLE main(key BLOB PRIMARY KEY NOT NULL, value BLOB NOT NULL);\n': "Bitcoin wallet",
'CREATE TABLE sqlar(\n'
' name TEXT PRIMARY KEY,\n'
' mode INT,\n'
' mtime INT,\n'
' sz INT,\n'
' data BLOB\n'
');\n': 'SQLite Archive (sqlarfs)',
'CREATE TABLE sqlar(\n'
' name TEXT PRIMARY KEY, -- name of the file\n'
' mode INT, -- access permissions\n'
' mtime INT, -- last modification time\n'
' sz INT, -- original file size\n'
' data BLOB -- compressed content\n'
');\n': 'SQLite Archive',
'CREATE TABLE sqlar(\n'
' name TEXT PRIMARY KEY,\n'
' mode INT,\n'
' mtime INT,\n'
' sz INT,\n'
' data BLOB\n'
' );\n': 'SQLite Archive (rust)',
'CREATE TABLE s3item_pending_changes\n'
' (\n'
' sequence_number INTEGER PRIMARY KEY ASC,\n'
' op blob,\n'
' args blob,\n'
' time float,\n'
' done int default 0 \n'
' );\n'
'CREATE TABLE s3item_history\n'
' (\n'
' sequence_number INTEGER PRIMARY KEY ASC,\n'
' key blob,\n'
' op blob,\n'
' data blob,\n'
' time float\n'
' );\n'
'CREATE TABLE s3api_per_key_metadata\n'
' (\n'
' s3key blob,\n'
' headers blob,\n'
' live_date real,\n'
' old_version_of blob,\n'
' primary key (s3key),\n'
' unique (s3key)\n'
' );\n': 'Internet Archive metadata',
'CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);\n'
'CREATE TABLE cookies(creation_utc INTEGER NOT NULL,host_key TEXT NOT NULL,top_frame_site_key TEXT NOT NULL,name TEXT NOT NULL,'
'value TEXT NOT NULL,encrypted_value BLOB NOT NULL,path TEXT NOT NULL,expires_utc INTEGER NOT NULL,is_secure INTEGER NOT NULL,'
'is_httponly INTEGER NOT NULL,last_access_utc INTEGER NOT NULL,has_expires INTEGER NOT NULL,is_persistent INTEGER NOT NULL,'
'priority INTEGER NOT NULL,samesite INTEGER NOT NULL,source_scheme INTEGER NOT NULL,source_port INTEGER NOT NULL,is_same_party INTEGER NOT NULL,last_update_utc INTEGER NOT NULL);\n'
'CREATE UNIQUE INDEX cookies_unique_index ON cookies(host_key, top_frame_site_key, name, path);\n': "Cookies.db",
"CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY,"
" originAttributes TEXT NOT NULL DEFAULT '',"
" name TEXT, value TEXT, host TEXT, path TEXT, expiry INTEGER, lastAccessed INTEGER,"
" creationTime INTEGER, isSecure INTEGER, isHttpOnly INTEGER, inBrowserElement INTEGER DEFAULT 0,"
" sameSite INTEGER DEFAULT 0, rawSameSite INTEGER DEFAULT 0, schemeMap INTEGER DEFAULT 0,"
" isPartitionedAttributeSet INTEGER DEFAULT 0,"
" CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes));\n": "Mozilla Cookies",
'CREATE TABLE moz_formhistory (\n'
' id INTEGER PRIMARY KEY, fieldname TEXT NOT NULL, value TEXT NOT NULL, timesUsed INTEGER, firstUsed INTEGER, lastUsed INTEGER, guid TEXT\n'
' \n'
' );\n'
'CREATE TABLE moz_deleted_formhistory (\n'
' id INTEGER PRIMARY KEY, timeDeleted INTEGER, guid TEXT\n'
' \n'
' );\n'
'CREATE TABLE moz_sources (\n'
' id INTEGER PRIMARY KEY, source TEXT NOT NULL\n'
' \n'
' );\n'
'CREATE TABLE moz_history_to_sources (\n'
' history_id INTEGER, source_id INTEGER\n'
' ,\n'
' PRIMARY KEY (history_id, source_id),\n'
' FOREIGN KEY (history_id) REFERENCES moz_formhistory(id) ON DELETE CASCADE,\n'
' FOREIGN KEY (source_id) REFERENCES moz_sources(id) ON DELETE CASCADE\n'
' \n'
' ) WITHOUT ROWID;\n'
'CREATE INDEX moz_formhistory_index ON moz_formhistory(fieldname);\n'
'CREATE INDEX moz_formhistory_lastused_index ON moz_formhistory(lastUsed);\n'
'CREATE INDEX moz_formhistory_guid_index ON moz_formhistory(guid);\n': 'Mozilla Form History',
}
schema_hashes = {
'e4634cc4f8e933a19105d0517bc52e358d58a4fa3cc052a1adeeed61fee5e982': 'Twin Motion',
'73255bd07ef841f4e83fd1b200a9159cf4f0526a797b3427b1733ca38e146bcd': 'Internet Archive metadata',
'a912b5ec3cc97373f00b4359bff0dcef772e22c8fcdac1906edba2edaa7ac328': 'Monotone source repository',
'c9d31186c845b56c59f02b6b53d508648c10b7f6cec0a993bbae8e97b012ec46': 'Firefox bookmark icons',
'519f988a92e0b7271a783b2043d5ee1c4289f8358b50244e78fb51fc2bc63c11': 'Cookies',
'25bef53e35d91470e5b9b910a427f6feb9c7c2fb7c3e0be6d9008560998b107c': 'Mozilla Cookies',
'43406bf1c991d7c56919f776eabbd861c326f31edde35d0eaf1911bc49cdf5d5': 'Mozilla Form History',
'20736fb77f994d6c55f3a3be1d1ad202764f82bade53e719232513bfc5110c2c': 'Microsoft stores',
'b1532ea493e5dba68c00d38ccd9e22873e6fcc2f00baaaa1864a9ab8d8ab6eff': 'CloudFlare Network Error Logging reports',
'805fafb0cd67a189ee818645149d10f28c4357a4e8e455b9bb66b89d2f6702d3': 'Bitcoin Wallet',
'199aa46e1d5c832d77a7019b78b6ef0bc9eef219dad1d347f0cc0fbc4312c585': 'Chewing IME',
"cbf1d291ccd67a6d669803d68bf73f848ed9c4f37b79aa47820da0840ed5a8e4": "sqlar",
"561fb39579a4b92b1e0fac372c930ec87d7b0321b99edc59808e48677e633895": "sqlar",
"3e83e986bf152bd51fd7f8619f19eaaba4c53d84392db25f28ec8622dcfb2526": "sqlar",
"b92816a2117ca795240b00f44bdaa43098ec31360cdd677ada807125eb990579": "Ccmdb",
"38c7d766819ab324103085c0a6891a0599e98e9a7160987653baa618e10ba4a1": "360safe.Summary.dat",
"fe4072e1e296e15e443a6d5b5b69b4bc29a15a5716cf3d59e91857ced650cc2a": "3870112724rsegmnoittet-es.sqlite",
"69beb90d7a2577df0ac6acd5fc2b0d5ddd87d3f3ff5864f0e8bad141d6bd42e0": "ActivitiesCache.db",
"b078d27aa611271d5ec2024d1766a1bd8c42ca914e88601c3593a0363d60250a": "AdobeNGLAppIDMap.db",
"44d211178031186065e0224e2af304cde276a33e5707d83f67124a7443b65145": "AssemblyRegister.db",
"3c758542ea2e4c24046b03e9566f5de10993630184541d61bb676f59cbf85e5c": "Browse.VC.db",
"613a27ef3dc08a0cc49e425406632bad8832f5f24da3b98b9a41a176fcf7dfac": "Browse.VC.db",
"1d8892cad25f37ec0834e94ac238919fabde479a245fd3948ce922faff1dd6e6": "Census.db",
"17cf7e999c5d802921a28572e50befd40281e5ac6f5acd094a4b84520ff42626": "DIPS",
"9d499a107dba5cd7d87ee9eb0af93c98dac5da7524f14b602f9d8217dd72e97b": "EventLog.db",
"5bdd528ded6cb02292f66ef1d198741f18f690f807297f9113c53dd604a3e64e": "EventStore.db",
"6f0d392603def8441c50393c016bab91a31a406b8b9c6f318f7fce57894da015": "GPLS.db",
"ace46d10f4b8bf1260a56474ccb62e7245343b4cb39f975bc46aec622518ffdd": "History",
"62126bd759757089a7fbc0f019040cb181c30a435f5d51dffd4fd40d32e429c7": "Install.db",
"bfc588e1a9445f890cfd7c400f0de1caa3885aa36762c5d83c66a3dd07213dc0": "LocalStorage.db",
"0a692cbfeed9c2285d00f11bdddd99e9946dcf2a08207cfd37562eedc00075cf": "Login Data",
"99f5185950e11829d88ade25bf8d7fa2fd303ac816860d15cc453309e65dee54": "MBG",
"95fae60fadc74d78add71470120c27d8f89d1331ea621cc2f0d108c2666985a8": "Media_db.db",
"cba30cd327ee3fe2845b825977087908456aa4b588fcc809f352d74b11baf0d2": "Network Action Predictor",
"5ef8da39ca87190b068b5c3d1bfc2ed7c84588a1177ef94e5e642870878d0186": "Network Action Predictor",
"b2e379f10b23b6b9c1dfe2b975d9c0df78cabe04f05065be3ab797ec5b89bdc3": "Quarantine.db",
"2e3a061cb62dceffdca4a66c71999985b4508bd07255c99a46e267a9a6b2da68": "StateRepository-Deployment.srd",
"c42a92e515028ca5e617af551017163d712f8576a67ebfb9bafad76258011393": "StateRepository-Machine.srd",
"cee901dfa7ee2d29fef4bff27bc364282b5cf8d13bcb3d9bf51df0accea7f01a": "Synchronizer",
"72712f0e4d06d89f550e54ad461ca96243a7840394b0d3c9fd5bb17d21a1ab50": "TDData-data.db",
"6a0e7ac0505cf62b6620da2abb61217c570f049e70cd2c93a6463bdd3216600e": "Web Data",
"d1a222bf23547148d08a124cf431108f25dd6f97035c3a23d63df5b103442377": "Web Data",
"64c3ee4941f5a535e76f1f3dcd186148a2767f13170d1e7bfbf7d1c69ef41591": "WebAssistDatabase",
"4e9f5fb453532fbae415552c9b2c6ad666c9ed24628584486139cfe82e04f546": "__leanplum.sqlite",
"33cf0d178cd6224ba78fa0eb99f4b268c221c88ed1e8c57587d9de544a19b01c": "anzu.db",
"ee6d84735a82d7db8a2d19a11288c6ad1b6a2fb9ed3be4d58c4562bd2649ba7a": "app_database.db",
"529b1addbabfd3306f6ac8f734b5b1734bf6623e517a73649b645d2c956c2ebb": "archive.db",
"a9f0625c7a0f991fc8975d9e0730adbbadc62e304b0edf4849995a8f49324f8f": "autopsy.db",
"aa8204611e828d737b3a9c4489dab5e4d17e267005b92d51bfade256107b70cc": "c2rclient.db",
"5da6ddf73033935d2a095c1a76c6181c2275fa5405e70cb875f4c19336147cb5": "cache.db",
"99a792e6047af56198c389e3cc85068a49459a802cde1336e3947d702fe3ae2f": "cert9.db",
"e96577026e7b071c2dcd0752b59541c48a7b5903f7a0f6298abecef4addb6461": "client.serverlist.1.db",
"edd318f30f9d0f04c6259e182213ec0522ad022b19fbb91da2b3684212b89ecd": "cty.dat.sqlite",
"c1c25fd09cee6681c27a006087279afd927b948cb72afc24da19f82dd2af5a0c": "data.db",
"1b06b0ebf9884001143dfec20a280f4e352030adf350468f400732325842c49a": "data.sqlite",
"60ecc3bb8821dcced901e81dc46e9b0fe1e8b32bd5ed1a377f323362d5695a86": "file__0.localstorage",
"b45b5fd2bb47a79b542d88fd8e59e48a0a6c6174874600193edfc49e50a90658": "first_party_sets.db",
"fb1ee772956b7021141370312d7c9931585909228d3bcc7cd635541b05d28a39": "folder_icon_link.db",
"ae4411fa7ceb8a722cbdb785bbf62d5e29cccd93ff9c9c18dfefb446590305ea": "ga.sqlite3",
"df697cd67c7c7d142c361fd32f1e02aa946b74c7da3138b1ec6ab1590203cb9b": "hdpim.db",
"4c6647fd0a4e3c68c7f2606e30f31d488624d03278ecc95d2c525e5bf22071fe": "hitomi_downloader_GUI.ini",
"f161614a81ae0f54f843635659ccedd1aca81e642c0d370f2a9d77141bd726f1": "hydra.db",
"d7d5c6da0c6168083aa41f4340499d318a4919fb8ad905fd3df2b050b73620ca": "installer.db",
"ba297b1936ce3563f92e616ec5eedc69fd2a1f27f0bbfcc54e1f356792cc68c8": "key4.db",
"8f01548a007263677255ba374784564b05d069d7f0353d935546ac8f712bbe93": "launcher-v2.sqlite",
"806f40fa990e9793e88d8227e11e8ad498a339e5bab9d39d24280c8bff9dca32": "main.db",
"8e1022e8f0f69d011ef83d2222f1a62f5f7a61ed60992da836d4d5f1b7f917d1": "metadata.db",
"6e67e9acffbddd7daaa8afb5683d888ce2b7c3aa34b167b6cb3badfdc69a95d8": "weird_6e67",
"8b7135a83720e7078e4cc96e27e03d7e26616f6ee3acd1ac080051a1f070bde4": "pal.db",
"6ae0e03f6d1c8d45bf91b7d80f7ca8eb1c088dda736341c5cf16dfe147ea9079": "pcd.db",
"e45d95d2aa4d6363095f5a9ea62752c798b31f73263e974aee493b351d1acf9a": "permissions.sqlite",
"28900b3652398ebd7c9d892fc476cdec8a0b0808d6267515cef36c7c6bac9500": "photothumb.db",
"0cde4d48c0fb79fc3672b3f16b90a0fb859a8e41de22e83b564ca9e87872d2fd": "pim.db",
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855": "psid.db",
"48224a37a39dfd3cb94cac4d747f4ea1676df576672661fa5cb1672af623ae00": "quotamanager",
"3b2da09df7757eac41fd706df56b2befa1dbf62cb8acdf31c25ceec5ba00502b": "reportnew.db",
"1602399d818eb2ff0d858bc7000944b1cd28066e3d6e3bb2271f9c4fc76bdf53": "resume.dat",
"f69ffeee0558c1948758a0228a6de3d0e5eace6836268e4a9dd69a6a73c2e398": "settings.db",
"25b9c32e16fd94a9850829c16dc9874f2dcffc365fbabe8d7474c3d5d094c48d": "slnx.sqlite",
"c972ccbe9357e5f061e28843419def0f0d4bcbce3af5ab13cadffc5a66c8d3c3": "sponge.dat",
"c14043a957c79761fd67c118ab8d093aa769119730adfbabb56b61c84bd2b579": "store.bak",
"9b21a6a0ab430fc8a164a7dbc57aaf4cb24e45b6d28a17c9b4e1c4f8585efe15": "task",
"8dc99fbb154f3fa6a7ea3cdc81772168a6cab65cff6990520e12dd0f76fce78c": "trash_database",
"0dfa976a291cca097a5911cf6b0133427d9581307f79183fd6757e03bb51a00c": "uFiler.db",
"1dc000686fd94fb5ce6c167d3580b660c1942f34b4820dd998f3aecaa11a4028": "ukm_db",
"1a0420300d7432986582f9408cc18ce1710ef6026a3dc2e8ab1c1dcc6f93cbdc": "user_vod.db_magis",
"88f4525e69ce8d49a1e2b34ec3d37c6a44e46fd3ca09d86f40198a60f257cb66": "wdch.dat",
"b933b2a2c39db398dd2ec8540e113c560dd336fc30a97ed9a320243aa8a81836": "wpndatabase.db",
"2836469e240f01b8f08eba04b74201a8f3d167f191318c117e707d9a849acd33": "z.xyz",
}
queries = {
"Fossil repository": "SELECT login AS Login, pw as Password FROM user",
"Mozilla Cookies": "SELECT host, name, value FROM moz_cookies",
"Cookies": "SELECT host_key, name, value FROM cookies",
"sqlar": "SELECT name, sz AS Size, SUBSTR(data, 1, 10) AS Contents FROM sqlar",
"Web Data": "SELECT name_on_card FROM credit_cards",
"Fossil checkout": "SELECT pathname AS PathName FROM vfile",
"History": "SELECT top_level_url, frame_url FROM visited_links",
"Mozilla Form History": "SELECT value AS Url FROM moz_formhistory",
}
HEADER_LENGTH = 80
def readSQLiteFile(fn):
try:
fh = open(fn, "rb")
except FileNotFoundError:
return False, "file not found"
data = fh.read(HEADER_LENGTH)
fh.close()
if len(data) < HEADER_LENGTH:
return False, "file too small"
if data[:16] != b"SQLite format 3\0":
fh.close()
return False, "invalid signature"
page_size_bytes = int.from_bytes(data[16:16+2], byteorder="little")
if page_size_bytes not in [2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100]:
return False, "invalid page_size_bytes: %X" % page_size_bytes
file_format_write_version = int.from_bytes(
data[18:18+1], byteorder="little")
if file_format_write_version not in [1, 2]:
return False, "invalid file_format_write_version: %X" % file_format_write_version
file_format_read_version = int.from_bytes(
data[19:19+1], byteorder="little")
if file_format_read_version not in [1, 2]:
return False, "invalid file_format_read_version: %X" % file_format_read_version
return True, data
def run_query(connection, query, data=(), map=lambda x: x[0]):
lines = []
cursor = connection.cursor()
for row in cursor.execute(query, data):
if row is not None and row[0] is not None:
lines.append(map(row))
cursor.close()
connection.commit()
return lines
parser = argparse.ArgumentParser(
prog='SQLbuddy', description='SQLite file type checker')
parser.add_argument('filename', help='database file')
parser.add_argument(
'--dump-schema', help='dump the database schema', action='store_true')
args = parser.parse_args()
fn = args.filename
result, info = readSQLiteFile(fn)
if result == False:
print("Error %s: %s" % (repr(fn), info))
sys.exit()
# https://www.sqlite.org/pragma.html#pragma_user_version
user_version = info[60:60+4]
# https://www.sqlite.org/pragma.html#pragma_application_id
application_id = info[68:68+4]
print("Filename: %s" % (repr(fn)))
def b2h(b):
return b" ".join(b"%02X" % c for c in b).decode()
if user_version != b'\0\0\0\0':
print("user_version: %s (%s) [%s]" % (
repr(user_version[1:]), b2h(user_version),
user_versions[user_version] if user_version in user_versions else "UNK"))
if application_id != b'\0\0\0\0':
print("application_id: %s (%s) [%s]" % (
repr(application_id)[1:], b2h(application_id),
application_ids[application_id] if application_id in application_ids else "UNK"))
connection = sqlite3.connect(fn)
# adding ";\n" to each statement like '.schema' does
QUERY_END = ";\n"
GET_SQL = "SELECT sql FROM sqlite_schema;" # include index, triggers and views
try:
lines = run_query(connection, GET_SQL, data=(),
map=lambda row: row[0] + QUERY_END)
connection.close()
except sqlite3.OperationalError:
print("Error: Operational Error")
sys.exit()
schema = "".join(lines)
def printSchema(schema):
lines = schema.split("\n")
for line in lines[:-1]:
print(repr(line + "\n"))
if schema in schemas:
print("Schema: %s" % (schemas[schema] if schema in schemas else 'UNK'))
if args.dump_schema:
printSchema(schema)
schema_hash = hashlib.sha256(schema.encode()).hexdigest()
appName = schema_hashes[schema_hash] if schema_hash in schema_hashes else 'UNK'
print("Schema Hash: %s [%s]" % (
schema_hash, appName))
if appName in queries:
query = queries[appName]
connection = sqlite3.connect(fn)
try:
lines = run_query(connection, query, data=())
connection.close()
except sqlite3.OperationalError:
print("Error: Operational Error")
sys.exit()
print("Contents: %s" % (" ".join(repr(line) for line in lines)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment