Skip to content

Instantly share code, notes, and snippets.

@kou1okada
Created September 8, 2017 05:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kou1okada/438edf0316760f843c68b34316f63952 to your computer and use it in GitHub Desktop.
Save kou1okada/438edf0316760f843c68b34316f63952 to your computer and use it in GitHub Desktop.
Get a hash for `thumbcache_*.db`.
/**
* Usage: gethash FULLPATH EXT
* ex)
* gethash C:\Users\kou\Pictures\20160904_090200.PNG .PNG
*
* Copyright (c) 2017 Koichi OKADA.
* License:
* GPLv3 or later.
*/
#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib, "ole32.lib")
#include <windows.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <wchar.h>
#include <locale.h>
#include <cstdint>
/*
errno_t wmemcpy_s( wchar_t *dest, size_t destSize, const wchar_t *src, size_t count )
{
// The g++ (cygwin) does not have wmemcpy_s.
// @see https://msdn.microsoft.com/ja-jp/library/wes2t00f.aspx
// @TODO imprement codes for the g++ (cygwin).
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BEGIN_CODEFROM: https://github.com/thumbcacheviewer/thumbcacheviewer/blob/1bf92cb085dee934198c865b0a626a9fb9e73707/thumbcache_viewer/map_entries.cpp
// thumbcache_viewer will extract thumbnail images from thumbcache database files.
// Copyright (C) 2011-2016 Eric Kutcher
wchar_t g_filepath[ MAX_PATH ] = { 0 }; // Path to the files and folders to scan.
bool is_win_7_or_higher = true; // Windows Vista uses a different file hashing algorithm.
bool is_win_8_1_or_higher = true; // Windows 8.1 uses a different file hashing algorithm.
CLSID clsid; // Holds a drive's Volume GUID.
BOOL IsWindowsVersionOrGreater( WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor )
{
OSVERSIONINFOEXW osvi = { sizeof( osvi ), 0, 0, 0, 0, { 0 }, 0, 0 };
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
VER_MINORVERSION, VER_GREATER_EQUAL ),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW( &osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask ) != FALSE;
}
BOOL IsWindows7OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN7 ), LOBYTE( _WIN32_WINNT_WIN7 ), 0 );
}
BOOL IsWindows8Point1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WINBLUE ), LOBYTE( _WIN32_WINNT_WINBLUE ), 0 );
}
unsigned long long hash_data( char *data, unsigned long long hash, short length )
{
while ( length-- > 0 )
{
hash = ( ( ( hash * 0x820 ) + ( *data++ & 0x00000000000000FF ) ) + ( hash >> 2 ) ) ^ hash;
}
return hash;
}
//void hash_file( wchar_t *filepath, wchar_t *extension )
unsigned long long hash_file( wchar_t *filepath, wchar_t *extension )
{
// Initial hash value. This value was found in shell32.dll.
unsigned long long hash = 0x95E729BA2C37FD21;
//HANDLE hFile = CreateFile( filepath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
HANDLE hFile = CreateFile( filepath, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
if ( hFile != INVALID_HANDLE_VALUE )
{
// Hash Volume GUID
hash = hash_data( ( char * )&clsid, hash, sizeof( CLSID ) );
// Hash File ID - found in the Master File Table.
BY_HANDLE_FILE_INFORMATION bhfi;
GetFileInformationByHandle( hFile, &bhfi );
CloseHandle( hFile );
unsigned long long file_id = bhfi.nFileIndexHigh;
file_id = ( file_id << 32 ) | bhfi.nFileIndexLow;
hash = hash_data( ( char * )&file_id, hash, sizeof( unsigned long long ) );
// Windows Vista doesn't hash the file extension or modified DOS time.
if ( is_win_7_or_higher )
{
// Hash Wide Character File Extension
hash = hash_data( ( char * )extension, hash, wcslen( extension ) * sizeof( wchar_t ) );
// Hash Last Modified DOS Time
unsigned short fat_date;
unsigned short fat_time;
FileTimeToDosDateTime( &bhfi.ftLastWriteTime, &fat_date, &fat_time );
unsigned int dos_time = fat_date;
dos_time = ( dos_time << 16 ) | fat_time;
hash = hash_data( ( char * )&dos_time, hash, sizeof( unsigned int ) );
// Windows 8.1 calculates the precision loss between the converted write time and original write time.
if ( is_win_8_1_or_higher )
{
// Convert the DOS time back into a FILETIME.
FILETIME converted_write_time;
DosDateTimeToFileTime( fat_date, fat_time, &converted_write_time );
// We only need to hash the low order int.
unsigned int precision_loss = converted_write_time.dwLowDateTime - bhfi.ftLastWriteTime.dwLowDateTime;
// Hash if there's any precision loss.
if ( precision_loss != 0 )
{
hash = hash_data( ( char * )&precision_loss, hash, sizeof( unsigned int ) );
}
}
}
//update_scan_info( hash, filepath );
return hash;
}
return 0;
}
unsigned __stdcall map_entries( void *pArguments )
{
/*
// This will block every other thread from entering until the first thread is complete.
EnterCriticalSection( &pe_cs );
SetWindowTextA( g_hWnd_scan, "Map File Paths to Cache Entry Hashes - Please wait..." ); // Update the window title.
SendMessage( g_hWnd_scan, WM_CHANGE_CURSOR, TRUE, 0 ); // SetCursor only works from the main thread. Set it to an arrow with hourglass.
*/
// 0 = scan directories, 1 = scan ese database
unsigned char scan_type = ( unsigned char )pArguments;
/*
// Disable scan button, enable cancel button.
SendMessage( g_hWnd_scan, WM_PROPAGATE, 1, 0 );
create_fileinfo_tree();
file_count = 0; // Reset the file count.
match_count = 0; // Reset the match count.
*/
if ( scan_type == 0 )
{
// File path will be at least 2 characters. Copy our drive to get the volume GUID.
wchar_t drive[ 4 ] = { 0 };
wchar_t volume_guid[ 50 ] = { 0 };
wmemcpy_s( drive, 4, g_filepath, 2 );
drive[ 2 ] = L'\\'; // Ensure the drive ends with "\".
drive[ 3 ] = L'\0';
// Get the volume GUID first.
if ( GetVolumeNameForVolumeMountPoint( drive, volume_guid, 50 ) == TRUE )
{
volume_guid[ 48 ] = L'\0';
CLSIDFromString( ( LPOLESTR )( volume_guid + 10 ), &clsid );
// Assume anything below Windows 7 is running on Windows Vista.
is_win_7_or_higher = ( IsWindows7OrGreater() != FALSE ? true : false );
is_win_8_1_or_higher = ( IsWindows8Point1OrGreater() != FALSE ? true : false );
// traverse_directory( g_filepath );
}
/*
else
{
SendNotifyMessageA( g_hWnd_scan, WM_ALERT, 0, ( LPARAM )"Volume name could not be found." );
}
*/
}
/*
else
{
traverse_ese_database();
}
cleanup_fileinfo_tree();
InvalidateRect( g_hWnd_list, NULL, TRUE );
// Update the details.
if ( !g_show_details )
{
char msg[ 11 ] = { 0 };
sprintf_s( msg, 11, "%lu", file_count );
SendMessageA( g_hWnd_scan, WM_PROPAGATE, 5, ( LPARAM )msg );
}
// Reset button and text.
SendMessage( g_hWnd_scan, WM_PROPAGATE, 2, 0 );
if ( match_count > 0 )
{
char msg[ 30 ] = { 0 };
sprintf_s( msg, 30, "%d file%s mapped.", match_count, ( match_count > 1 ? "s were" : " was" ) );
SendNotifyMessageA( g_hWnd_scan, WM_ALERT, 1, ( LPARAM )msg );
}
else
{
SendNotifyMessageA( g_hWnd_scan, WM_ALERT, 1, ( LPARAM )"No files were mapped." );
}
SendMessage( g_hWnd_scan, WM_CHANGE_CURSOR, FALSE, 0 ); // Reset the cursor.
SetWindowTextA( g_hWnd_scan, "Map File Paths to Cache Entry Hashes" ); // Reset the window title.
// We're done. Let other threads continue.
LeaveCriticalSection( &pe_cs );
_endthreadex( 0 );
*/
return 0;
}
// END_CODEFROM: https://github.com/thumbcacheviewer/thumbcacheviewer/blob/1bf92cb085dee934198c865b0a626a9fb9e73707/thumbcache_viewer/map_entries.cpp
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow)
int wmain(int argc, wchar_t *argv[])
{
/*
// not worked
int argc;
LPWSTR *argv;
setlocale(LC_CTYPE, "JPN");
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
wchar_t **argv = (wchar_t **) _argv;
*/
if (argc < 2) {
wprintf(L"Usage: gethash FULLPATH [EXT]\n");
return EXIT_FAILURE;
}
wprintf(L"argc : %d\n", argc);
wprintf(L"argv[1] : %wS\n", argv[1]);
wprintf(L"argv[2] : %wS\n", argc < 3 ? L"" : argv[2]);
wmemcpy_s( g_filepath, MAX_PATH, argv[1], wcslen(argv[1]) );
map_entries( NULL );
unsigned long long hash = hash_file( argv[1], argc < 3 ? L"" : argv[2] );
wprintf(L"VolumeCLSID : 0x%016llx\n", *(( uint64_t *) &clsid));
wprintf(L"hash : 0x%016llx\n", hash);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment