jet2jet / resedit-js Goto Github PK
View Code? Open in Web Editor NEWJS library editing Windows Resource data
License: MIT License
JS library editing Windows Resource data
License: MIT License
The example code has a FileVersion specified, but as far as I can tell this does nothing. The true file version seems to come from the fileVersionMS and fileVersionLS. I think it would be useful to simply remove the FileVersion line to avoid confusion if it does indeed do nothing.
It would also be helpful to include a utility for converting a regular number the fileVersionMS & fileVersionLS formats as this does not seem to be straightforward
Hello. We need to sign .cab files.
/Users/maxpain/dev/signer/node_modules/resedit/dist/util/functions.js:27
return new DataView(bin.buffer, newOffset, newLength);
^
RangeError: Start offset 1547057292 is outside the bounds of the buffer
at new DataView (<anonymous>)
at Object.createDataView (/Users/maxpain/dev/signer/node_modules/resedit/dist/util/functions.js:27:16)
at Function.ImageNtHeaders.from (/Users/maxpain/dev/signer/node_modules/resedit/dist/format/ImageNtHeaders.js:31:33)
at Function.NtExecutable.from (/Users/maxpain/dev/signer/node_modules/resedit/dist/NtExecutable.js:54:43)
at main (/Users/maxpain/dev/signer/.build/index.js:73:47)
I've been trying to use this library to extract executable icons.
for RawIconItem
types (png) i do the following:
resource.bin
from arraybuffer
to array
.png
extensionBut when i try to dump a resource of type IconItem
(bitmap), i encounter issues where the resulting file seems corrupted, here is what i tried:
resource.generate()
array buffer
to a buffer
.ico
extension or .bmp
extensionWhat am i missing?
Less of an issue and more a general question... Should this library allow for modifications to be done to EXE files within a Linux environment or does it rely on the Windows API to facilitate the changes?
Thank you for your time.
Hey,
Thanks for creating this project. I'm looking to integrate this into a build process which uses ESM to import modules. You're already bundling an ESM version which works for type-hinting and bundling, but when importing directly into a non-bundled build script, the following error is thrown.
Syntax Error: Cannot use import statement outside a module
The modern way to resolve this is to set "type": "module"
in package.json
, which would need to be done for pe-library
as well as resedit-js
. I was going to make a quick PR, but I'm not sure how setting that property would work with how this project is built, but it would be great to get this working with ESM.
I noticed the use of "module": "./dist/_esm/index.js",
but this is unfortunately non-standard and not used by Node.js, only by bundlers, so the error is thrown regardless.
https://nodejs.org/api/packages.html#type
https://nodejs.org/api/esm.html#esm_enabling
Thanks!
I've ran into an issue trying to get the icon from iconsext.exe
(https://www.nirsoft.net/utils/iconsext.html). It gives me an error when passing the NtExecutable
into ResEdit.NtExecutableResource.from
. My usage extractExeIcon(). Windows 10 is able to parse this icon and the program works. In general this code works, but this exe
specifically wasn't working.
I am wondering if anyone has an idea why this might be happening?
Thanks for any help!
The main
and types
paths package.json
are incorrect (at-least in the version published to NPM).
They are set to:
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
But those files are are actually at:
./dist/src/main/index.js
./dist/src/main/index.d.ts
When attempting to load the module I get this error.
Error: Cannot find module '.../node_modules/resedit/dist/index.js'. Please verify that the package.json has a valid "main" entry
I can still use it if I use a deep-import, but it would be nice if this were fixed properly.
require('resedit/dist/src/main')
PS. This is a pretty cool module. With a little scripting I think this can be used as a platform-independent replacement for rcedit.
In the next major version, I'm planning the following changes, which may be breaking change:
typescript
and use import type
/ export type
await
or callback function)I'm using Typescript with CommonJS (for gulpfile), and I'm trying to change the icon of a file with it.
But it shows an error.
[17:43:27] TypeError: Cannot read properties of undefined (reading 'length')
at file:///V:/Developer/typescript/Dev/InfDev/L%C3%96VETS/gulp/node_modules/resedit/dist/resource/VersionInfo.js:244:67
at Array.reduce (<anonymous>)
at generateStringTableInfo (file:///V:/Developer/typescript/Dev/InfDev/L%C3%96VETS/gulp/node_modules/resedit/dist/resource/VersionInfo.js:281:28)
at generateVersionEntryBinary (file:///V:/Developer/typescript/Dev/InfDev/L%C3%96VETS/gulp/node_modules/resedit/dist/resource/VersionInfo.js:322:30)
at VersionInfo.generateResource (file:///V:/Developer/typescript/Dev/InfDev/L%C3%96VETS/gulp/node_modules/resedit/dist/resource/VersionInfo.js:645:19)
at VersionInfo.outputToResourceEntries (file:///V:/Developer/typescript/Dev/InfDev/L%C3%96VETS/gulp/node_modules/resedit/dist/resource/VersionInfo.js:660:24)
at V:\Developer\typescript\Dev\InfDev\LÖVETS\gulp\pack_love.ts:226:16
var l = await WindowsRESEdit_CrossPlatform(
MLV_EXE, // It's an existing executable file.
"My Software",
"An testing description.",
"Test Enterprise",
[1,0,0,7]
// ,icoFile || fs.readFileSync("./include/appicon/app.ico"),
)
import {type ResEdit, load as RESEdit_loader} from "resedit/cjs"
import {load as PELibrary_loader, type PE} from "pe-library/cjs"
...
export async function WindowsRESEdit_CrossPlatform(
executableFile: string,
ProductName: string,
ProductDescription: string,
CompanyName: string,
FileVersion: [number,number,number,number],
IconFile?: string | ArrayBuffer | ArrayBufferView,
LegalCopyright?: string,
LegalTrademarks?: string,
OriginalFilename?: string,
Comments?: string,
) {
return new Promise<void>((resolve, reject) => {
PELibrary_loader().then((PELibrary: typeof PE) => {
RESEdit_loader().then((RESEdit: typeof ResEdit) => {
const DataEXEFile = readFileSync(executableFile)
const ExeFileParsed = PELibrary.NtExecutable.from(DataEXEFile)
const ResFileData = PELibrary.NtExecutableResource.from(ExeFileParsed)
if (IconFile) {
if (typeof IconFile === "string") {
IconFile = readFileSync(IconFile)
}
const IconFileParsed = RESEdit.Data.IconFile.from(IconFile)
RESEdit.Resource.IconGroupEntry.replaceIconsForResource(
ResFileData.entries,
101,
1033,
IconFileParsed.icons.map((item) => item.data)
)
console.log("Changed Icon.")
}
const viList = RESEdit.Resource.VersionInfo.fromEntries(ResFileData.entries)
const versioninfo_res: any = {
ProductName: ProductName,
FileDescription: ProductDescription,
OriginalFilename: OriginalFilename,
CompanyName: CompanyName || "ALL RIGHTS UNRESERVED"
}
if (Comments) versioninfo_res.Comments = Comments
if (LegalCopyright) versioninfo_res.LegalCopyright = LegalCopyright
if (LegalTrademarks) versioninfo_res.LegalTrademarks = LegalTrademarks
if (OriginalFilename) {
versioninfo_res.OriginalFilename = OriginalFilename
}
const vi = viList[0]
vi.setFileVersion(FileVersion[0], FileVersion[1], FileVersion[2], FileVersion[3], 1033)
vi.setStringValues(
{lang: 1033, codepage: 1200},
versioninfo_res
)
vi.outputToResourceEntries(ResFileData.entries)
ResFileData.outputResource(ExeFileParsed)
let newBinary = ExeFileParsed.generate()
rename(executableFile, executableFile.slice(0, -4) + ".old.exe")
writeFileSync(executableFile, Buffer.from(newBinary))
resolve()
})
})
})
}
I'm running on Windows 11 - 22H2 (pretty irrelevant info).
And i'm using folder such as gulp/
to separate packages from main + .gulp.json
.
So, how do I fix that? Did I miss something?
Here's a Gist which takes a signed exe, reads it in, and writes it out again.
https://gist.github.com/AlexanderOMara/f14a4ba62a2432a1bb3a96f1de541c98
Apart from the checksum (fixed in another issue, but not published to NPM yet) the only difference is that the code signature data at the end it not preserved, though the headers says it has been (the entry is ImageDirectoryEntry.Security
in resedit-js
).
A quick note on how the code signature works, the code signature is simply at the end of the file, with the Security entry specifying the file offset and size of the data (not the virtual address).
In order to achieve feature parity with rcedit, I started to try to implement a way to preserve this data, but it looks like it requires some restructuring to do this, and I wasn't sure how best to go about refactoring this.
With some direction, I could probably create a pull request.
Sorry to keep making these bug reports, but I think I've found one last minor bug. The codepage is always being set to 0 when passed through this library.
resedit-js/src/main/NtExecutableResource.ts
Lines 556 to 557 in 615b5a1
Here's a Gist to demo the issue.
https://gist.github.com/AlexanderOMara/bec719dbd4303edc770d85877ee36d08
I'll submit a pull request in just a second.
Here's a Gist to demo:
https://gist.github.com/AlexanderOMara/1b53507b4da53fb5c9febb125096a756
It looks like offset isn't being 32-bit aligned in a few places where it needs to be. Pull request on the way.
I got an error when trying to change the icon for an executable generated by pkg.
/node_modules/resedit/dist/util/functions.js:43
: new Uint8Array(src, srcOffset, length);
RangeError: Invalid typed array length: 1920
at new Uint8Array (<anonymous>)
at Object.copyBuffer (/node_modules/resedit/dist/util/functions.js:43:11)
at IconItem.generate (/node_modules/resedit/dist/data/IconItem.js:149:21)
at /node_modules/resedit/dist/resource/IconGroupEntry.js:176:31
at Array.map (<anonymous>)
at IconGroupEntry.replaceIconsForResource (/node_modules/resedit/dist/resource/IconGroupEntry.js:155:34)
at file:///dist/winbuild.js:9:25
Node.js v18.4.0
The error was generated by this:
import { readFile, writeFile } from 'fs/promises';
import { join } from 'path';
import { fileURLToPath } from 'url';
import { NtExecutable, NtExecutableResource, Data, Resource } from 'resedit';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const main = async () => {
try {
const binary = await readFile(join(__dirname, '../pkg/win.exe'))
const exe = NtExecutable.from(binary);
const resource = NtExecutableResource.from(exe);
const icon = await readFile(join(__dirname, 'pdf.ico'));
const icon_file = Data.IconFile.from(icon);
Resource.IconGroupEntry.replaceIconsForResource(resource.entries, 101, 1033, icon_file.icons.map(item => item.data));
const vi_list = Resource.VersionInfo.fromEntries(resource.entries);
const vi = vi_list.at(0);
if (!vi) throw Error('vi is undefined');
vi.setFileVersion(1, 0, 0, 0, 1033);
vi.setStringValues(
{ lang: 1033, codepage: 1200 },
{
FileDescription: 'My application',
ProductName: 'My product',
},
);
vi.outputToResourceEntries(resource.entries);
resource.outputResource(exe);
const output = exe.generate();
await writeFile(join(__dirname, '../pkg/sample.exe'), Buffer.from(output));
} catch (e) {
console.error((e as Error).message);
}
}
main();
I have attached a sample executable and icon file.
ExeIcon.zip
Any help would be greatly appreciated.
Icons with an alpha mask have their heights doubled, which leads to replaceIconsForResource
setting the wrong height values, and software which displays those icons choosing the wrong icons to display.
I've created a Gist to demo the issue.
Essentially RawIconItem
and IconItem
may not have the correct height
value for an icon group entry (possibly doubled for the alpha mask), but the array entries returned from resedit.Data.IconFile.from
do. However only the data property of those entries (RawIconItem
and IconItem
) are passed to replaceIconsForResource
so the wrong values are written to the icon group.
So if I use icons with sizes like this:
icons:
ico: 0 0
raw: 256 256
ico: 128 128
bmp: 128 256
ico: 32 32
bmp: 32 64
I get a group with sizes like this:
group:
icon: 0 0
icon: 128 0
icon: 32 64
Instead of the correct values:
group:
icon: 0 0
icon: 128 128
icon: 32 32
codes
const ResEdit = require('resedit');
const fs = require('fs');
let package = require('./package.json');
let data = fs.readFileSync('./build/web-automation.exe');
let exe = ResEdit.NtExecutable.from(data);
let res = ResEdit.NtExecutableResource.from(exe);
// -- replace version
let viList = ResEdit.Resource.VersionInfo.fromEntries(res.entries);
let vi = viList[0];
let versions = package.version.split('.');
// vi.fixedInfo.fileVersionMS = 0x40004; // '1.1'
vi.fixedInfo.fileVersionLS = 0;
vi.setStringValues(
{ lang: 1033, codepage: 1200 },
{
FileVersion: '1.1',
FileDescription: `${package.version}`,
ProductName: '小花'
}
);
vi.outputToResourceEntries(res.entries);
// write to another binary
res.outputResource(exe);
let newBinary = exe.generate();
fs.writeFileSync('./build/web-automation.exe', Buffer.from(newBinary));
Hello for some reason I don't want to change the icon
const ResEdit = require('resedit');
const fs = require('fs');
let data = fs.readFileSync('./MyApp.exe');
let exe = ResEdit.NtExecutable.from(data);
let res = ResEdit.NtExecutableResource.from(exe);
let iconFile = ResEdit.Data.IconFile.from(fs.readFileSync('icon.ico'));
ResEdit.Resource.IconGroupEntry.replaceIconsForResource(
// destEntries
res.entries,
// iconGroupID
101,
// lang ('lang: 1033' means 'en-US')
1033,
// icons (map IconFileItem to IconItem/RawIconItem)
iconFile.icons.map((item) => item.data)
);
// -- replace version
let viList = ResEdit.Resource.VersionInfo.fromEntries(res.entries);
let vi = viList[0];
// vi.fixedInfo.fileVersionMS = 0x40004; // '1.1'
vi.fixedInfo.fileVersionLS = 0;
vi.setStringValues(
{ lang: 1033, codepage: 1200 },
{
FileVersion: '1.1',
FileDescription: `test`,
ProductName: 'test'
}
);
vi.outputToResourceEntries(res.entries);
// write to another binary
res.outputResource(exe);
let newBinary = exe.generate();
fs.writeFileSync('./MyAppEdit.exe', Buffer.from(newBinary));
I want to extract the icon for an exe file.
However, I cannot extract the icon for C:\Windows\System32\notepad.exe.
Here's my code.
public static async getFileIcon(path:string, index:number|undefined): Promise<string | undefined> {
const resEdit = await load();
const binary = await fs.readFile(path);
const ex = resEdit.NtExecutable.from( binary, { ignoreCert: true});
const exRes = resEdit.NtExecutableResource.from(ex, true);
const iconEntries = resEdit.Resource.IconGroupEntry.fromEntries(exRes.entries); // iconEntries is empty array.
for ( let i = 0 ; i < iconEntries.length ; i++ ) {
const entry = iconEntries[i];
const iconItems = entry.getIconItemsFromEntries(exRes.entries);
for ( let j = 0 ; j < iconItems.length ; j ++ ) {
const iconGroupItem = iconItems[j];
if ( iconGroupItem instanceof resEdit.Data.RawIconItem ) {
const base64 = Buffer.from(iconGroupItem.bin).toString('base64');
return `data:image/png;base64,${base64}`;
}
}
}
one more.
How can i get icon in c:\windows\system32\shell32.dll.
Thanks for the great library.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.