Skip to content

Instantly share code, notes, and snippets.

@justaguywhocodes
Created November 10, 2025 15:35
Show Gist options
  • Select an option

  • Save justaguywhocodes/5e2c91ac392f1af04907ff600f662e5f to your computer and use it in GitHub Desktop.

Select an option

Save justaguywhocodes/5e2c91ac392f1af04907ff600f662e5f to your computer and use it in GitHub Desktop.
#include <windows.h>
#include <shlobj.h>
#include <iostream>
#include <string>
#include "sqlite3.h"
#include <wincrypt.h>
#include <cstdlib> // For system("pause")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "sqlite3.lib")
int main() {
std::cout << "Starting program..." << std::endl;
char localAppData[MAX_PATH];
HRESULT hr = SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, localAppData);
if (FAILED(hr)) {
std::cerr << "Error getting Local AppData path." << std::endl;
system("pause");
return 1;
}
std::cout << "Local AppData path: " << localAppData << std::endl;
std::string basePath = std::string(localAppData) + "\\ConnectedDevicesPlatform";
std::cout << "Scanning base path: " << basePath << std::endl;
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA((basePath + "\\*").c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE) {
std::cerr << "Error opening ConnectedDevicesPlatform directory." << std::endl;
system("pause");
return 1;
}
std::cout << "Successfully opened directory for scanning subfolders." << std::endl;
bool found = false;
do {
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
strcmp(findData.cFileName, ".") != 0 &&
strcmp(findData.cFileName, "..") != 0) {
std::string idFolder = basePath + "\\" + findData.cFileName;
std::string dbPath = idFolder + "\\ActivitiesCache.db";
std::cout << "Checking subfolder: " << idFolder << std::endl;
DWORD attr = GetFileAttributesA(dbPath.c_str());
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
std::cout << "Found ActivitiesCache.db at: " << dbPath << std::endl;
// Query the database
sqlite3* db;
int rc = sqlite3_open(dbPath.c_str(), &db);
if (rc != SQLITE_OK) {
std::cerr << "Cannot open database: " << sqlite3_errmsg(db) << std::endl;
sqlite3_close(db);
continue;
}
std::cout << "Database opened successfully." << std::endl;
const char* sql = "SELECT ClipboardPayload FROM ActivityOperation";
sqlite3_stmt* stmt;
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
sqlite3_close(db);
continue;
}
std::cout << "SQL prepared: " << sql << std::endl;
// Print header for all columns
int num_cols = sqlite3_column_count(stmt);
std::cout << "All Columns:" << std::endl;
for (int i = 0; i < num_cols; ++i) {
std::cout << sqlite3_column_name(stmt, i) << "\t";
}
std::cout << std::endl;
int row_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
row_count++;
std::cout << "Row " << row_count << ":" << std::endl;
for (int i = 0; i < num_cols; ++i) {
int col_type = sqlite3_column_type(stmt, i);
const char* col_name = sqlite3_column_name(stmt, i);
switch (col_type) {
case SQLITE_INTEGER:
std::cout << sqlite3_column_int64(stmt, i);
break;
case SQLITE_FLOAT:
std::cout << sqlite3_column_double(stmt, i);
break;
case SQLITE_TEXT: {
const char* text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, i));
if (text) {
// Attempt base64 decode
DWORD decoded_size = 0;
DWORD text_len = static_cast<DWORD>(strlen(text));
BOOL crypt_res = CryptStringToBinaryA(text, text_len, FALSE, NULL, &decoded_size, NULL, NULL);
if (crypt_res && decoded_size > 0) {
BYTE* decoded = new BYTE[decoded_size];
crypt_res = CryptStringToBinaryA(text, text_len, FALSE, decoded, &decoded_size, NULL, NULL);
if (crypt_res) {
// Assume decoded is text, print it
std::cout.write(reinterpret_cast<char*>(decoded), decoded_size);
}
else {
std::cerr << "Failed to decode base64 for TEXT column " << col_name << std::endl;
std::cout << text; // Fallback to original
}
delete[] decoded;
}
else {
// Not base64 or error, print original
std::cout << text;
}
}
else {
std::cout << "NULL";
}
break;
}
case SQLITE_BLOB: {
const void* blob = sqlite3_column_blob(stmt, i);
int blob_size = sqlite3_column_bytes(stmt, i);
if (blob && blob_size > 0) {
// For ClipboardPayload, it's a JSON blob, so skip direct base64 and go to JSON extraction
// Assume it's JSON text and extract "content" key value
std::string json_str(reinterpret_cast<const char*>(blob), blob_size);
size_t content_pos = json_str.find("\"content\"");
bool extracted = false;
if (content_pos != std::string::npos) {
size_t colon_pos = json_str.find(':', content_pos);
if (colon_pos != std::string::npos) {
size_t value_start = colon_pos + 1;
// Skip whitespace
while (value_start < json_str.size() &&
(json_str[value_start] == ' ' || json_str[value_start] == '\t' ||
json_str[value_start] == '\n' || json_str[value_start] == '\r')) {
++value_start;
}
if (value_start < json_str.size() && json_str[value_start] == '"') {
++value_start; // Skip opening quote
std::string content;
size_t pos = value_start;
while (pos < json_str.size()) {
char c = json_str[pos];
if (c == '"') {
// End of string
break;
}
else if (c == '\\') {
++pos;
if (pos < json_str.size()) {
char next = json_str[pos];
switch (next) {
case '"': content += '"'; break;
case '\\': content += '\\'; break;
case '/': content += '/'; break;
case 'b': content += '\b'; break;
case 'f': content += '\f'; break;
case 'n': content += '\n'; break;
case 'r': content += '\r'; break;
case 't': content += '\t'; break;
default: content += next; break; // Pass through others
}
}
}
else {
content += c;
}
++pos;
}
// Now base64 decode the content
DWORD content_decoded_size = 0;
DWORD content_len = static_cast<DWORD>(content.length());
BOOL content_crypt_res = CryptStringToBinaryA(content.c_str(), content_len, FALSE, NULL, &content_decoded_size, NULL, NULL);
if (content_crypt_res && content_decoded_size > 0) {
BYTE* content_decoded = new BYTE[content_decoded_size];
content_crypt_res = CryptStringToBinaryA(content.c_str(), content_len, FALSE, content_decoded, &content_decoded_size, NULL, NULL);
if (content_crypt_res) {
// Print decoded content
std::cout.write(reinterpret_cast<char*>(content_decoded), content_decoded_size);
extracted = true;
}
else {
std::cerr << "Failed to decode base64 content for BLOB column " << col_name << std::endl;
std::cout << content; // Fallback to raw content
extracted = true;
}
delete[] content_decoded;
}
else {
// Not base64 or error, print raw content
std::cout << content;
extracted = true;
}
}
}
}
if (!extracted) {
std::cout << "[BLOB " << blob_size << " bytes]";
}
}
else {
std::cout << "NULL";
}
break;
}
case SQLITE_NULL:
std::cout << "NULL";
break;
default:
std::cout << "[UNKNOWN]";
break;
}
std::cout << "\t";
}
std::cout << std::endl;
}
std::cout << "Processed " << row_count << " rows." << std::endl;
sqlite3_finalize(stmt);
sqlite3_close(db);
found = true;
// Assuming only one such folder; break if found
break;
}
else {
std::cout << "No ActivitiesCache.db in " << idFolder << std::endl;
}
}
} while (FindNextFileA(hFind, &findData));
FindClose(hFind);
if (!found) {
std::cout << "ActivitiesCache folder not found." << std::endl;
}
std::cout << "Program ending. Press any key to close..." << std::endl;
system("pause");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment