Edits resources in existing Win32 PE files.
In a POSIX environment, it is common in porting projects for developers to want to embed resources into Windows PE binary files. Examples include updating version information or setting icons.
However, the development environment must have a toolchain such as windres installed.
While there are other libraries for manipulating the PE binary format, they can be cumbersome to use—even when you only want to manipulate resources—because they involve a large API.
engraver is a small library implemented entirely in C99 that specializes solely in editing the resource information of PE binary files after the fact. You can easily integrate it into your project.
The project contains:
libengraver: C99 library published aslibengraver.aandlibengraver.soengraver: small CLI wrapper around the library
You can use with pre-built packages (Debian/Ubuntu deb packages and windows executables) in release page.
make clean all testThe build creates:
build/libengraver.abuild/libengraver.sobuild/engraver
engraver <input-pe file> <updates-json file> <output-pe file>The input and output paths must differ. Resources not mentioned by JSON are preserved.
The JSON root object may contain strings, version, icons, and raw.
{
"strings": [{ "id": 1, "language": 1041, "value": "Title" }],
"version": {
"language": 1041,
"codePage": 1200,
"fixed": {
"fileVersion": "1.2.3.4",
"productVersion": "1.2.3.4",
"fileType": "app"
},
"strings": {
"CompanyName": "Example",
"FileDescription": "Example App"
}
},
"icons": [{ "id": 1, "language": 1041, "path": "assets/app.ico" }],
"raw": [{ "type": 24, "id": 1, "language": 1041, "path": "assets/manifest.xml" }]
}Asset paths are resolved relative to the JSON file directory. v1 accepts numeric id, type, and language values.
Icon paths must point to .ico files.
eg_json_document *document = NULL;
eg_resource_update *update = NULL;
eg_pe_file *file = NULL;
eg_load_json_file("updates.json", &document);
eg_json_document_to_update(document, &update);
eg_pe_open_file("input.exe", &file);
eg_pe_write_file(file, update, "output.exe");
eg_pe_close(file);
eg_resource_update_destroy(update);
eg_release_json(document);The functions above use the default POSIX file I/O implementation.
Use the _with_io variants when embedding libengraver in an environment that
needs custom file handles or virtual files.
eg_io_ops ops = {
.context = user_context,
.open_read = open_read,
.open_write = open_write,
.read = read_file,
.write = write_file,
.close = close_file
};
eg_load_json_file_with_io(&ops, "updates.json", &document);
eg_json_document_to_update_with_io(&ops, document, &update);
eg_pe_open_file_with_io(&ops, "input.exe", &file);
eg_pe_write_file_with_io(&ops, file, update, "output.exe");read() reports EOF by returning EG_OK with *out_size == 0.
write() must write the full requested size or return an error.
close() is called after a successful open, including when a later read or write fails.
build_package.sh runs Debian package builds inside distro-specific Podman
containers and Win32 package builds with MinGW and Wine. Run prereq.sh first
to build target-specific Podman images with the apt build dependencies already
installed for Linux packages.
Prerequisites:
sudo apt-get install podman qemu-user-static dpkg-dev binutils mingw-w64 wine zip unzip
npm install -g screw-upBuild examples:
# Prepare prerequisite images
./prereq.sh
# Ubuntu 24.04 / amd64
./build_package.sh --target deb --distro ubuntu --release 24.04 --arch amd64
# Debian bookworm / arm64
./build_package.sh --target deb --distro debian --release bookworm --arch arm64
# Win32 / amd64 and i686
./build_package.sh --target win32
# Full Linux and Win32 matrix
./build_package.sh --target allNotes:
- Generated packages are
engraverandlibengraver-dev. - Win32 packages are generated as zip files with
engraver.exe,libengraver.dll, import/static libraries, headers, and docs. - Supported targets are Debian
bookworm(x86_64,i686,arm64,armv7l), Debiantrixie(x86_64,i686,arm64,armv7l,riscv64), and Ubuntu22.04,24.04,26.04(x86_64,arm64). - Supported Win32 architectures are
amd64andi686. - Arch aliases:
x86_64|amd64,i686|i386,armv7l|armv7|armhf,arm64|aarch64. - Ubuntu release aliases:
24.04|noble,22.04|jammy. - Debug build: add
--debug. - Rebuild prerequisite images after dependency or base-image changes:
./prereq.sh --force. - Outputs:
artifacts/<package>-<version>-<distro>-<release>-<deb-arch>.deb. - Win32 outputs:
artifacts/engraver-<version>-win32-<arch>.zip.
Batch build for all predefined combos:
./build_package_all.shUnder MIT.