Reverse Engineering - Extract Version Information From And Executable Using ResHacker

Posted at

For the example I'll choose something I'm using every now and again.. Chromium exe installer

icompile.eladkarako.com_exe_info_from_windows_ui

icompile.eladkarako.com_exe_info_from_reshacker_ui

icompile.eladkarako.com_exe_info_from_reshack_helpfile

Working with information dumped in text files is easy,
you can use every GNU exe you'll like (grep, awk, sed) or even feed it NodeJS, see if I'll care ;)
But first you have to get it.
...Here is how to....






You can choose to extract the resource as plain whatever (for example bmp, wav, txt) or as windows-compiled resource (res file).
It is all depend on if you give RC or RES as the output extension.

Since I want to extract the version information (a.k.a VERSIONINFO) I'll use .rc:
ResHacker.exe -extract "mini_installer.exe,mini_installer_version_information.rc,VERSIONINFO,1,1033"



I am VERY specific on the sub-tree and language,
..well because I can.

icompile.eladkarako.com_exe_info_from_reshack_extract_very_specific

But,
You might as well ignore and since version-information is (usually) just in plain US-ASCII English, or at least single language it should be OK to just extract everything VERSIONINFO,
To do it, just don't specify the 1 or 1033 (in my example above).

ResHacker.exe -extract "mini_installer.exe,mini_installer_version_information.rc,VERSIONINFO,,"


You MUST however still write those ,, at the end, since it is part of reshacker's (ambiguous) syntax,
(will not work without those ,, at the end).


Reading the "dumped" information (plain text) is quite easy using any notepad application.
icompile.eladkarako.com_reshack_read_raw_information

p.s.
icompile.eladkarako.com_reshack_read_compiled_resource2

Reading the compiled resource is somewhat possible with notpad due to the predictability of the information,
but not really human-readable, unless filtered. you can however feed it to reshacker.exe again, as an input, if you wish to..
Or compile it yourself using the RC command https://msdn.microsoft.com/en-us/library/windows/desktop/aa381055(v=vs.85).aspx








Would You like to script-it?
after you've dumped it to a (for example versioninfo.rc)
use grep and sed, to filter out and leave you just with the version information itself.

grep -m 1 "FileVersion" versioninfo.rc | sed -e "s@^.*FileVersion\\", \\"@@g" -e "s@\\"$@@"


Would you like to know what other stuff you can extract from the VERSIONINFO block of the file?
Well..
Assuming your target application has implemented the VERSIONINFO block as Microsoft had defined it
There are only a handful of so called attributes you can "query" for, *Microsoft well-defines only a handful of platforms.

According to VERSIONINFO resource
https://msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx

Those are (ordered a,b,c,... including the description as is from the msdn link above)
Name	Description
Comments	Additional information that should be displayed for diagnostic purposes.
CompanyName	Company that produced the file?for example, "Microsoft Corporation" or "Standard Microsystems Corporation, Inc." This string is required.
FileDescription	File description to be presented to users. This string may be displayed in a list box when the user is choosing files to install?for example, "Keyboard Driver for AT-Style Keyboards". This string is required.
FileVersion	Version number of the file?for example, "3.10" or "5.00.RC2". This string is required.
InternalName	Internal name of the file, if one exists?for example, a module name if the file is a dynamic-link library. If the file has no internal name, this string should be the original filename, without extension. This string is required.
LegalCopyright	Copyright notices that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, and so on. This string is optional.
LegalTrademarks	Trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. This string is optional.
OriginalFilename	Original name of the file, not including a path. This information enables an application to determine whether a file has been renamed by a user. The format of the name depends on the file system for which the file was created. This string is required.
PrivateBuild	Information about a private version of the file?for example, "Built by TESTER1 on \\TESTBED". This string should be present only if VS_FF_PRIVATEBUILD is specified in the fileflags parameter of the root block.
ProductName	Name of the product with which the file is distributed. This string is required.
ProductVersion	Version of the product with which the file is distributed?for example, "3.10" or "5.00.RC2". This string is required.
SpecialBuild	Text that indicates how this version of the file differs from the standard version?for example, "Private build for TESTER1 solving mouse problems on M250 and M250E computers". This string should be present only if VS_FF_SPECIALBUILD is specified in the fileflags parameter of the root block.


so, for example, one may easily fetch the CompanyName value using the following commands-chain:

grep -m 1 "CompanyName" versioninfo.rc | sed -e "s@^.*CompanyName\\", \\"@@g" -e "s@\\"$@@"




*note that due to grep/sed combination an empty grep match (for example, if CompanyName was not found) will result in an empty string,
- which in this case is 100% valid output for those kind of things,

naturally if you wish to know if the entry CompanyName is missing instead of just empty, you should probably query some more, for example wrap the grep value with characters such as apostrophes (') or even pre-test the grep output before sed'ding. Overkill?



The following (simple) batch file will generate a rc file for each exe you'll drag&drop on top of it
(well actually it should even work even if instead of exe you will drag&drop a res file on top of the batch file since I'm not really verifying the content here at all...)

@echo off

set FILE_INPUT="%~s1"
set FILE_OUTPUT="%~d1%~p1%~n1_versioninfo.rc"

call C:\\Software\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,,"


* fix the path to reshacker exe's path.
* you can read|download resource-hacker from the wiki page https://en.wikipedia.org/wiki/Resource_Hacker

icompile.eladkarako.com_batch_generate_rc_file






Here is a slightly improved batch-file:
@echo off
setlocal enableextensions

set FILE_INPUT="%~s1"
set FILE_OUTPUT="%~d1%~p1%~n1_versioninfo.rc"

    ::call D:\\DOS\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,1,1033"
call D:\\DOS\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,,"

set QUERY=FileVersion
for /f "tokens=*" %%a in ('grep -o "%QUERY%.*$" %FILE_OUTPUT% ^| sed -e "s@.*, @@g" ^| tr -d """" ') do (set RESULT=%%a);
echo file's version is [%RESULT%]. Cool!

endlocal

*again, please set the path to your reshack exe.

That will output
file's version is [56.0.2886.0]. Cool!


You'll also may notice that the file is highly modular, in which you may replace the FileVersion with (for example) ProductName...

@echo off
setlocal enableextensions

set FILE_INPUT="%~s1"
set FILE_OUTPUT="%~d1%~p1%~n1_versioninfo.rc"

    ::call D:\\DOS\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,1,1033"
call D:\\DOS\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,,"

set QUERY=ProductName
for /f "tokens=*" %%a in ('grep -o "%QUERY%.*$" %FILE_OUTPUT% ^| sed -e "s@.*, @@g" ^| tr -d """" ') do (set RESULT=%%a);
echo You are checking [%RESULT%]. Nice.

endlocal


which will then output:
You are checking [ChromiumInstaller]. Nice.


but wait! something is wrong! the value of the ProductName is missing a space (should be Chromium Installer) the reason is that replacing the " character is doomed due to Windows' escape hell, you can escape using the ^ character for the batch (cmd) and \\ for the GNU programs, but when included in multiple ' and ", there is another way to escape... """"... for the sake of clarity of the script I will handle the only cases where " character and white-space is not an issue, such as version-like numbering.
Windows cmd-shell is nothing like linux, or cygwin, in which escaping is (kind'a) possible.

You are much better writing an application implementing a DLL to read the version-information block, through binary processing, than walking through the Windows-CMD-Escape hell.

Anyway, if " characters are not an issue with the response, you may possible tolerate or process them otherwise (maybe in a separate batch or through cmd-variable-string-manipulation [GOOD GOD!.. amm well it is not THATTTTT BADDDD...]
but you may still use this one:
@echo off
setlocal enableextensions

    set FILE_INPUT="%~s1"
    set FILE_OUTPUT="%~d1%~p1%~n1_versioninfo.rc"

    ::call D:\\DOS\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,1,1033"
    call D:\\DOS\\ResHack\\RESHAC~1.EXE -extract "%FILE_INPUT%,%FILE_OUTPUT%,VERSIONINFO,,"
    
    set QUERY=FileVersion
    for /f "tokens=*" %%a in ('grep -o "%QUERY%.*$" %FILE_OUTPUT%  ^|  sed -e "s@.*, @@g") do (set RESULT=%%a);
    echo file's version is [%RESULT%]. Cool!

endlocal


Enjoy :)