This is a tool to make builds of Portable Executables (PEs) and PDBs reproducible.
Timestamps and other non-deterministic data are embedded in DLLs, EXEs, and PDBs. If some source is compiled and linked twice without changing any source, the binary and PDB will not be bit-for-bit identical both times. This tool fixes that by modifying DLLs/EXEs in-place and rewriting PDBs.
Don't worry, Ducible won't mess with the functionality of your executable. All changes have no functional effect. It merely transforms one perfectly good executable into another perfectly good, yet reproducible(!), executable.
In general, reproducible builds give a verifiable path from source code to binary code. There are a number of security reasons and practical reasons for why this is good. More specifically, it enables
See also https://reproducible-builds.org/ for more information on why you should want this.
Usage is as follows:
$ ducible IMAGE [PDB]
The EXE/DLL is specified as the first parameter and the PDB is optionally specified as the second. The PDB must be modified because changing the image invalidates the signature for the PDB.
As a post-build step, simply run:
$ ducible MyModule.dll MyModule.pdb
The files are overwritten in-place.
See the releases for downloads.
This tool cannot prevent you from shooting yourself in the foot. Please don't ever have anything like this in your code:
std::cout << "Build date: " << __DATE__ << " " << __TIME__ << std::endl;
There is nothing that Ducible can do about this. Embedding dates or times might seem useful, but all they do is prevent reproducible builds. Once you have reproducible builds and a proper versioning scheme, embedding this information is pointless.
Digital signing with trusted timestamping cannot be made reproducible (e.g.,
signtool). Even while doing digital signing,
you can still gain some of the benefits that using Ducible provides (e.g.,
recreating a PDB for debugging purposes). Digital signatures can also be
stripped off after being applied to make comparing binaries possible.
Incremental linking using
/INCREMENTAL changes the
executable quite extensivly upon subsequent builds. Ducible will invalidate
.ilk file and force the linker to do a full relink every time. However,
this isn't enough to make the build reproducible. You can work around this
issue by disabling
/INCREMENTAL in the linker settings. (Unfortunately
this is usually enabled by default for
Debug builds in Visual Studio.)
This is written in C++11. There are no third party dependencies and it should be buildable and runnable on any platform (even non-Windows!).
Required build tools:
Python 3 is used to generate
Git is used to get the current commit hash. This is embedded in the
src/version.h that is generated by Python.
Both of these tools must be in your
First, clone the repository:
git clone https://github.com/jasonwhite/ducible.git
Note: Downloading a zip of the source or cloning via SVN will cause the build to fail. The current commit hash is embedded in the executable to help trace the executable back to the exact source used to build it.
vs/vs2015/ducible.sln and build it. Of course, this requires Visual
Studio 2015 or later. If another version of Visual Studio is needed, please
submit an issue or, better yet, a pull request.
You can also use the free Visual Studio 2015 build
tools to build.
You just need to invoke
msbuild directly (in a Visual Studio command prompt):
msbuild vs\vs2015\ducible.sln /m /t:Build /p:Configuration=Release /p:Platform=x64
Although this is primarily a Windows utility, it was developed in a Unix environment simply because it was faster and easier. One might also want to use it when compiling Windows binaries on Linux. Thus, it builds and runs on Linux and Mac as well.
To build it, just run
As always, this tool uses the very liberal MIT License. Use it for whatever nefarious purposes you like.