显示最近的浏览历史记录





5.00/5 (9投票s)
本文解释了浏览历史记录的存储位置和方式,以及如何获取它。
Github 仓库:https://github.com/securedglobe/browsinghistory
引言
在尝试获取浏览历史记录时,有几个问题
- 它存储在哪里?
- 它更新的频率是多少?
- 它以什么格式存储?
- 访问该信息的最佳方法是什么?
Microsoft Edge
Microsoft Edge 将其历史记录存储在 "<用户配置文件>\AppData\Local\Microsoft\Edge\User Data\Default\History" 中。 它使用名为 urls 的表来存储每次访问,但不包括 InPrivate 模式。
从编程的角度来看,如果您找到了用户的配置文件路径并将其存储在 *userProfilePath* 中,则数据库路径将是
userProfilePath + "\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\History"
Chrome
Google Chrome 将其历史记录存储在 "<用户配置文件>\AppData\Local\Google\Chrome\User Data\Default\History" 中。 它使用名为 urls 的表来存储每次访问,但不包括 InPrivate 模式。
从编程的角度来看,如果您找到了用户的配置文件路径并将其存储在 *userProfilePath* 中,则数据库路径将是
userProfilePath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\History"
构建块
为了本文的目的,我使用 Visual Studio 2022 创建了一个控制台应用程序。
数据库
由于浏览历史记录存储在 sqlite3 数据库中,因此我们需要包含 sqlite3 库或源代码文件。
为了能够读取浏览历史记录数据库,我们需要能够处理 sqlite3 数据库。 您可以在 这里 找到关于 sqlite3 的更多信息。 然后我们需要将 sqlite3.c 和 sqlite3.h 添加到项目中。
用户配置文件文件夹
所有位置都相对于 c:\users 文件夹中当前 用户配置文件路径。 我们首先需要找到该路径。 这是一个执行此操作的函数
// Get the current user's profile path (e.g., C:\Users\<username>\) std::wstring GetUserProfilePath() { WCHAR path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path))) { return std::wstring(path); } return L""; }
使用被锁定的数据库
由于数据库可能被锁定,并且如果 Edge 或 Chrome 正在运行,它们将被锁定,因此我们首先需要将它们复制到另一个位置并从那里访问它们。
// Function to copy the locked database to a temporary file for querying bool CopyDatabaseToTemp(const std::wstring& dbPath, std::wstring& tempDbPath) { wchar_t tempPath[MAX_PATH]; if (GetTempPathW(MAX_PATH, tempPath) == 0) { return false; } wchar_t tempFileName[MAX_PATH]; if (GetTempFileNameW(tempPath, L"dbcopy", 0, tempFileName) == 0) { return false; } tempDbPath = std::wstring(tempFileName); try { std::filesystem::copy_file(dbPath, tempDbPath, std::filesystem::copy_options::overwrite_existing); return true; } catch (const std::filesystem::filesystem_error& e) { wprintf(L"Failed to copy database: %s\n", ConvertUtf8ToWide(e.what()).c_str()); return false; } }
处理 Unix 日期和时间
有几种存储日期和时间的方法。
WebKit Epoch
WebKit 时间戳从 1601 年 1 月 1 日(UTC)开始。
Unix Epoch
Unix 时间戳从 1970 年 1 月 1 日(UTC)开始。
在 WebKit Epoch 和 Unix Epoch 之间转换
我们使用以下函数进行转换。ConvertWebKitToUnixTime()
这是它的工作原理
参数
webkitTime:这是一个 int64_t 值,表示自 WebKit epoch(1601 年 1 月 1 日)以来的微秒级时间戳。
返回类型
该函数返回一个 time_t 值,该值表示自 Unix epoch(1970 年 1 月 1 日)以来的秒级 Unix 时间戳。
逻辑
WebKit 时间戳以微秒为单位,而 Unix 时间戳以秒为单位。 通过将 webkitTime 除以 1,000,000,我们将微秒转换为秒。
调整 Epoch 差异
两个 epoch(1601 年 1 月 1 日和 1970 年 1 月 1 日)之间的差异为 369 年。
这种差异转换为 11644473600 秒。
计算中的 - 11644473600LL 将时间戳从 WebKit epoch 调整为 Unix epoch。
最终计算
static_cast<time_t>(webkitTime / 1000000 - 11644473600LL);
它采用以微秒为单位的 WebKit 时间戳,将其转换为秒,然后减去两个 epoch 之间以秒为单位的差异,从而产生正确的 Unix 时间戳。
这是函数
// Convert WebKit timestamp (microseconds) to Unix timestamp (seconds) time_t ConvertWebKitToUnixTime(int64_t webkitTime) { return static_cast<time_t>(webkitTime / 1000000 - 11644473600LL); // Adjusting for WebKit epoch }
还有一些代码用于以人类可读的格式打印结果,在我的例子中,我以 UTC 格式显示它们。
// Convert time_t to human-readable UTC time string std::wstring FormatUnixTimeToUTC(time_t unixTime) { struct tm timeInfo; if (gmtime_s(&timeInfo, &unixTime) != 0) // Safe version of gmtime { return L"Invalid time"; } wchar_t buffer[80]; wcsftime(buffer, sizeof(buffer), L"%Y-%m-%d %H:%M:%S", &timeInfo); // Format time return std::wstring(buffer); }
打印最近的浏览历史记录
在下面的源代码中,我们打印了 Edge 和 Chrome 最近的浏览历史记录。
// Function to read browsing history from a given database path
void PrintUrlsFromDatabase(const std::wstring& dbPath, const time_t currentTime, const time_t timeRangeInSeconds)
{
std::wstring tempDbPath;
if (!CopyDatabaseToTemp(dbPath, tempDbPath))
{
wprintf(L"Failed to copy database to temporary file: %s\n", dbPath.c_str());
return;
}
sqlite3* db;
if (sqlite3_open16(tempDbPath.c_str(), &db) != SQLITE_OK)
{
wprintf(L"Failed to open database: %s\n", tempDbPath.c_str());
return;
}
// Query to get URLs and visit times
const char* query = "SELECT u.url, v.visit_time FROM urls u JOIN visits v ON u.id = v.url ORDER BY v.visit_time DESC;";
sqlite3_stmt* stmt;
if (sqlite3_prepare_v2(db, query, -1, &stmt, nullptr) != SQLITE_OK)
{
wprintf(L"Failed to prepare statement: %S\n", sqlite3_errmsg(db));
sqlite3_close(db);
return;
}
// Execute the query and process the results
while (sqlite3_step(stmt) == SQLITE_ROW)
{
const char* foundUrlUtf8 = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
int64_t visitTimeWebKit = sqlite3_column_int64(stmt, 1);
time_t visitTimeUnix = ConvertWebKitToUnixTime(visitTimeWebKit);
// Check if the URL was visited within the last 10 minutes
if (difftime(currentTime, visitTimeUnix) <= timeRangeInSeconds)
{
// Convert the URL from UTF-8 to wide string using the Windows API function
std::wstring foundUrl = ConvertUtf8ToWide(foundUrlUtf8);
// Format the visit time to a human-readable UTC string
std::wstring visitTimeStr = FormatUnixTimeToUTC(visitTimeUnix);
wprintf(L"URL: %s, Visit Time (UTC): %s\n", foundUrl.c_str(), visitTimeStr.c_str());
}
}
sqlite3_finalize(stmt);
sqlite3_close(db);
// Remove the temporary file after use
std::filesystem::remove(tempDbPath);
}