Created
September 8, 2017 05:01
-
-
Save kou1okada/438edf0316760f843c68b34316f63952 to your computer and use it in GitHub Desktop.
Get a hash for `thumbcache_*.db`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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