24
24
#include < cryptopp/files.h>
25
25
#include < cryptopp/sha.h>
26
26
#include < psapi.h>
27
+ #pragma comment( lib, "Version.lib" )
27
28
28
29
29
30
struct ArgumentManager {
30
31
31
32
void validateArguments (int argc, char * argv[]) {
32
33
33
34
namespace po = boost::program_options;
34
- std::string version = " v1.0.5 " ;
35
+ std::string version = " v1.0.6 " ;
35
36
po::options_description description (" Windows memory extractor " + version + " \n Usage" );
36
37
37
38
description.add_options ()
38
39
(" help,h" , " Display this help message" )
40
+ (" file-version-info,i" , " Retrieve version information about the file corresponding to a module" )
39
41
(" join,j" , " Generate an additional .dmp file with the contents of the other .dmp files joined" )
40
- (" output-directory,o" , po::value<std::string>(), " Directory where the output will be stored" )
41
42
(" module,m" , po::value<std::string>(), " Module of the process" )
43
+ (" output-directory,o" , po::value<std::string>(), " Directory where the output will be stored" )
42
44
(" pid,p" , po::value<int >()->required (), " Process ID" )
43
45
(" protections,s" , po::value<std::string>(), " Memory protections" )
44
46
(" version,v" , " Version" )
@@ -79,6 +81,15 @@ struct ArgumentManager {
79
81
}
80
82
}
81
83
84
+ if (vm.count (" file-version-info" )) {
85
+ isFileVersionInfoOptionSupplied = true ;
86
+ if (!isModuleOptionSupplied) {
87
+ // As with the --join option, the --file-version-info option is implemented to work alongside the --module option
88
+ // If the --file-version-info option is supplied without the --module option, the tool interprets that the user is asking for the version information of the file corresponding to the main module
89
+ isModuleOptionSupplied = true ;
90
+ }
91
+ }
92
+
82
93
if (vm.count (" pid" )) {
83
94
pid = vm[" pid" ].as <int >();
84
95
}
@@ -135,6 +146,10 @@ struct ArgumentManager {
135
146
return isOutputDirectoryOptionSupplied;
136
147
}
137
148
149
+ bool getIsFileVersionInfoOptionSupplied () {
150
+ return isFileVersionInfoOptionSupplied;
151
+ }
152
+
138
153
private:
139
154
140
155
void validateProtections (std::string suppliedProtectionsAsString) {
@@ -193,6 +208,7 @@ struct ArgumentManager {
193
208
bool isProtectionsOptionSupplied;
194
209
bool isJoinOptionSupplied;
195
210
bool isOutputDirectoryOptionSupplied;
211
+ bool isFileVersionInfoOptionSupplied;
196
212
197
213
};
198
214
@@ -229,7 +245,7 @@ struct MemoryExtractionManager {
229
245
}
230
246
231
247
if (argumentManager.getIsModuleOptionSupplied () && argumentManager.getModule ().length () == 0 ) {
232
- // The user is asking for the contents of the main module
248
+ // The user is asking for data about the main module
233
249
char mainModulePathAsCharArray[MAX_PATH];
234
250
if (GetProcessImageFileNameA (processHandle, mainModulePathAsCharArray, MAX_PATH) != 0 ) {
235
251
std::string mainModulePath (mainModulePathAsCharArray);
@@ -242,6 +258,8 @@ struct MemoryExtractionManager {
242
258
}
243
259
}
244
260
261
+ directoryName = createDirectory ();
262
+
245
263
BYTE* memoryPointer = NULL ; // Virtual address 0x0000000000000000
246
264
247
265
// Module option related variables
@@ -257,9 +275,25 @@ struct MemoryExtractionManager {
257
275
moduleBaseAddress = moduleInformation.modBaseAddr ;
258
276
moduleSize = moduleInformation.modBaseSize ;
259
277
moduleBaseAddressAsNumber = reinterpret_cast <size_t >(moduleInformation.modBaseAddr );
260
- }
261
278
262
- directoryName = createDirectory ();
279
+ if (argumentManager.getIsFileVersionInfoOptionSupplied ()) {
280
+ std::wstring modulePathW{ moduleInformation.szExePath };
281
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t >> converter;
282
+ std::string modulePath = converter.to_bytes (modulePathW);
283
+ DWORD dwHandle;
284
+ DWORD fileVersionInfoSize = GetFileVersionInfoSizeA (modulePath.c_str (), &dwHandle);
285
+ if (fileVersionInfoSize == 0 ) {
286
+ throw std::exception{ " An error has occurred trying to get the version information at function GetFileVersionInfoSizeA" };
287
+ }
288
+ std::vector<unsigned char > fileVersionInfoBuffer (fileVersionInfoSize);
289
+ if (!GetFileVersionInfoA (modulePath.c_str (), dwHandle, fileVersionInfoSize, &fileVersionInfoBuffer[0 ]))
290
+ {
291
+ throw std::exception{ " An error has occurred trying to get the version information at function GetFileVersionInfoA" };
292
+ }
293
+
294
+ retrieveFileVersionInformation (&fileVersionInfoBuffer[0 ]);
295
+ }
296
+ }
263
297
264
298
std::ofstream resultsFile (directoryName + " /results.txt" , std::ofstream::out);
265
299
resultsFile << " List of .dmp files generated:\n " ;
@@ -304,7 +338,35 @@ struct MemoryExtractionManager {
304
338
305
339
joinedModuleContentsStream.close ();
306
340
}
307
- resultsFile << " Number of .dmp files generated: " << dmpFilesGeneratedCount << std::endl;
341
+
342
+ resultsFile << " Number of .dmp files generated: " << dmpFilesGeneratedCount << " \n " ;
343
+
344
+ if (argumentManager.getIsFileVersionInfoOptionSupplied ()) {
345
+ resultsFile << " \n Additional files generated:\n " ;
346
+
347
+ using namespace CryptoPP ;
348
+ dmpFilesGeneratedCount++;
349
+
350
+ // Calculate the SHA-256 of the file moduleFileVersionInfo.fileinfo
351
+ std::ifstream moduleFileVersionInfoStream (directoryName + " /moduleFileVersionInfo.fileinfo" , std::ios::in | std::ios::binary);
352
+ std::string contents ((std::istreambuf_iterator<char >(moduleFileVersionInfoStream)),
353
+ (std::istreambuf_iterator<char >()));
354
+ HexEncoder hexEncoder (new FileSink (resultsFile), false );
355
+ std::string sha256Digest;
356
+ SHA256 hash;
357
+ hash.Update ((const byte*)contents.c_str (), contents.length ());
358
+ sha256Digest.resize (hash.DigestSize ());
359
+ hash.Final ((byte*)&sha256Digest[0 ]);
360
+
361
+ // Create an entry in the results file for the moduleFileVersionInfo.fileinfo file
362
+ resultsFile << " Filename: " << " moduleFileVersionInfo.fileinfo" << " , SHA-256: " ;
363
+ StringSource (sha256Digest, true , new Redirector (hexEncoder));
364
+ resultsFile << " \n " ;
365
+
366
+ moduleFileVersionInfoStream.close ();
367
+ }
368
+
369
+ resultsFile << std::endl;
308
370
resultsFile.close ();
309
371
CloseHandle (processHandle);
310
372
}
@@ -539,6 +601,53 @@ struct MemoryExtractionManager {
539
601
return TRUE ;
540
602
}
541
603
604
+ void retrieveFileVersionInformation (LPCVOID fileVersionInfoBufferPointer) {
605
+ std::vector<std::string> versionInfoKeys{
606
+ " Comments" ,
607
+ " CompanyName" ,
608
+ " FileDescription" ,
609
+ " FileVersion" ,
610
+ " InternalName" ,
611
+ " LegalCopyright" ,
612
+ " LegalTrademarks" ,
613
+ " OriginalFilename" ,
614
+ " ProductName" ,
615
+ " ProductVersion" ,
616
+ " PrivateBuild" ,
617
+ " SpecialBuild"
618
+ };
619
+
620
+ struct LANGANDCODEPAGE {
621
+ WORD wLanguage;
622
+ WORD wCodePage;
623
+ } *lpTranslate;
624
+
625
+ UINT cbTranslate = 0 ;
626
+ if (!VerQueryValueA (fileVersionInfoBufferPointer, " \\ VarFileInfo\\ Translation" , (LPVOID*)&lpTranslate, &cbTranslate)) {
627
+ throw std::exception{ " An error has occurred trying to get the version information at function VerQueryValueA" };
628
+ }
629
+
630
+ std::ofstream moduleVersionInfoFile (directoryName + " /moduleFileVersionInfo.fileinfo" , std::ofstream::out);
631
+
632
+ for (unsigned int i = 0 ; i < (cbTranslate / sizeof (LANGANDCODEPAGE)); i++) {
633
+ BOOST_FOREACH (const std::string & versionInfoKey, versionInfoKeys) {
634
+ std::string versionInfoKeyFormat = " \\ StringFileInfo\\ %04x%04x\\ " + versionInfoKey;
635
+ char versionInfoKeyWithLanguage[256 ];
636
+ sprintf_s (versionInfoKeyWithLanguage, versionInfoKeyFormat.c_str (), lpTranslate[i].wLanguage , lpTranslate[i].wCodePage );
637
+ LPSTR versionInfoValuePointer = NULL ;
638
+ UINT versionInfoValueSize = 0 ;
639
+ if (VerQueryValueA (fileVersionInfoBufferPointer, versionInfoKeyWithLanguage, (LPVOID*)&versionInfoValuePointer, &versionInfoValueSize)) {
640
+ moduleVersionInfoFile << versionInfoKey << " ," << std::string (versionInfoValuePointer) << " \n " ;
641
+ }
642
+ else {
643
+ // The value for the key is empty
644
+ moduleVersionInfoFile << versionInfoKey << " ,\n " ;
645
+ }
646
+ }
647
+ }
648
+ moduleVersionInfoFile.close ();
649
+ }
650
+
542
651
ArgumentManager& argumentManager;
543
652
std::string directoryName; // The directory where the memory data files will be placed
544
653
unsigned int dmpFilesGeneratedCount;
0 commit comments