更改可执行文件中的内部版本号

时间:2014-02-12 16:41:06

标签: delphi winapi binary patch versioninfo

我希望在可执行文件的版本信息中更改版本号(VersionLS的低位)。所以,我应该阅读VS_VERSIONINFO结构,更改内部版本号,然后将其更新回PE。

我正在使用此代码作为基础:https://stackoverflow.com/a/7999813/1970843。此代码非常适合更改VS_FIXEDFILEINFO数据,但不会更改(也不会访问)StringFileInfo信息。

我很确定我应该在VERSIONHEADER打包记录中添加一些内容来添加VS_VERSIONINFO的Children条目,但我不知道该怎么做。这就是我到目前为止所做的:

type
    StringStruc = Packed Record
        wLength: Word;
        wValueLength: Word;
        wType: Word;
        //szKey: ?;
        //Value: ?;
    End;

    StringTable = Packed Record
        wLength: Word;
        wValueLength: Word;
        wType: Word;
        szKey: Array[0..8] Of WideChar;
        Children: StringStruc;
    End;

    StringFileInfo = Packed Record
        wLength: Word;
        wValueLength: Word;
        wType: Word;
        szKey: Array[0..14] Of WideChar;   // 'STRINGFILEINFO'
        Children: StringTable;
    End;

    VERSIONHEADER = Packed Record
        wLength: Word;
        wValueLength: Word;
        wType: Word;
        szKey: Array[0..16] Of WideChar;   // 'VS_VERSION_INFO'
        Version: VS_FIXEDFILEINFO;
        Children: StringFileInfo;
    End;

...

var VersionHandle, VersionRes: THandle;
    VersionSize: Cardinal;
    Version: Array Of AnsiChar;
    Ver: ^VERSIONHEADER;
Begin
    VersionSize := GetFileVersionInfoSize(PChar(sExe), VersionHandle);

    SetLength(Version, VersionSize);
    Ver := Pointer(Version);
    GetFileVersionInfo(PChar(sExe), 0, VersionSize, Ver);

因此,信息似乎正确地到达第一个StringStruc。但由于szKey和Value都不是固定大小,我不知道如何正确定义我的Packed Record(甚至可能?)来获取这些值。我也遇到阵列问题......如何定义它们?我正在做的方式,我只是在每个Struc上得到第一个孩子。请注意,我忽略了填充...这可以吗?

感谢任何帮助。我在这里所做的大部分工作都是经过反复试验,所以我真的不明白发生了什么。

PS:我还在努力,所以我可能经常更新这篇文章。

1 个答案:

答案 0 :(得分:1)

感谢您的关注和帮助。我在SO上找到了一个现成的解决方案。事实上,这是对我所关联的问题的评论(对我来说很羞耻!)。

它基于Colin Wilson的库。它使用指针算法来提取和写入信息,因此,很难(也许是唯一的)方式。关于如何使用Jason Penny的库,还有一个很好的例子:SetVersion。由于我正在使用D7,我从here(在Resource Utilities下)下载了Colin Wilson的库,但是使用UnicodeString和更好的指针算法的更新版本可用here

这是我现在的实际实施:

uses ..., unitResourceVersionInfo, unitPEFile;

...

var VersionInfo: TVersionInfoResourceDetails;
    PEResModule: TPEResourceModule;
    VersionNumber: ULARGE_INTEGER;
    sVersion: String;
    I: Integer;
Begin
    PEResModule := TPEResourceModule.Create;
    Try
        PEResModule.LoadFromFile(sExe);

        For I := 0 To PEResModule.ResourceCount - 1 Do Begin
            If PEResModule.ResourceDetails[I] Is TVersionInfoResourceDetails Then Begin
                VersionInfo := (PEResModule.ResourceDetails[I] As TVersionInfoResourceDetails);
                Break;
            End;
        End;

        VersionNumber.LowPart := MakeLong(NewBuildNumber, HiWord(VersionInfo.FileVersion.LowPart));
        VersionNumber.HighPart := VersionInfo.FileVersion.HighPart;
        VersionInfo.FileVersion := VersionNumber;
        VersionInfo.ProductVersion := VersionNumber;

        VersionInfo.CodePage := $04e4;

        sVersion := Format('%d.%d.%d.%d', [HiWord(VersionInfo.FileVersion.HighPart), LoWord(VersionInfo.FileVersion.HighPart), HiWord(VersionInfo.FileVersion.LowPart), LoWord(VersionInfo.FileVersion.LowPart)]);
        VersionInfo.SetKeyValue('FileVersion', sVersion);

        PEResModule.SaveToFile(ChangeFileExt(sExe, '.exe2'));

    Finally
        FreeAndNil(PEResModule);
    End;
End;

代码页行是由于库中的错误(我相信它)。它不会读取代码页(来自0),因此,当您保存时,它显示为0。