Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

resedit

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

resedit - npm Package Compare versions

Comparing version 0.3.1 to 0.4.0

dist/sign/certUtil.d.ts

7

CHANGELOG.md
# Changelog
## v0.4.0
- Added signing process function (#14), which enables to generate signed executable binaries
- Additionally, signed executables are now supported on `NtExecutable.from` with explicit option. (On `NtExecutable.generate` signed information will be lost.)
- Support for `ArrayBufferView` as an input data for some methods (e.g. `NtExecutable.from` and `IconFile.from`)
- TypedArray (e.g. `Uint8Array`), `DataView`, and Node.js `Buffer` class are subclasses of `ArrayBufferView`, so these classes now can be used as input data directly.
## v0.3.1

@@ -4,0 +11,0 @@

4

dist/data/IconFile.d.ts

@@ -20,5 +20,5 @@ import IconItem from './IconItem';

/** @internal */
constructor(bin: ArrayBuffer);
static from(bin: ArrayBuffer): IconFile;
constructor(bin: ArrayBuffer | ArrayBufferView);
static from(bin: ArrayBuffer | ArrayBufferView): IconFile;
generate(): ArrayBuffer;
}

@@ -101,3 +101,3 @@ "use strict";

}
var view = new DataView(bin);
var view = functions_1.createDataView(bin);
var totalSize = view.byteLength;

@@ -119,3 +119,3 @@ var icons = [];

else {
data = RawIconItem_1.default.from(bin.slice(dataOffset, dataOffset + dataSize), width || 256, height || 256, bitCount);
data = RawIconItem_1.default.from(bin, width || 256, height || 256, bitCount, dataOffset, dataSize);
}

@@ -122,0 +122,0 @@ icons.push({

@@ -33,3 +33,3 @@ import BitmapInfo from './BitmapInfo';

*/
static from(bin: ArrayBuffer, byteOffset?: number, byteLength?: number): IconItem;
static from(bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): IconItem;
/**

@@ -43,3 +43,3 @@ * Generates `IconItem` instance from bitmap data binary width actual icon size (width and height).

*/
static from(width: number, height: number, bin: ArrayBuffer, byteOffset?: number, byteLength?: number): IconItem;
static from(width: number, height: number, bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): IconItem;
isIcon(): this is IconItem;

@@ -46,0 +46,0 @@ isRaw(): false;

@@ -10,3 +10,3 @@ "use strict";

function IconItem(width, height, bin, byteOffset, byteLength) {
var view = new DataView(bin, byteOffset, byteLength);
var view = functions_1.createDataView(bin, byteOffset, byteLength);
var totalSize = view.byteLength;

@@ -59,3 +59,3 @@ var headerSize = view.getUint32(0, true);

var size = sizeImage || (bi.bitCount * absWidthRound * absActualHeight) / 8;
this.pixels = functions_1.allocatePartialBinary(bin, view.byteOffset + offset, size);
this.pixels = functions_1.allocatePartialBinary(view, offset, size);
offset += size;

@@ -67,3 +67,3 @@ var maskSize = calcMaskSize(bi.width, absActualHeight);

if (maskSize) {
this.masks = functions_1.allocatePartialBinary(bin, view.byteOffset + offset, maskSize);
this.masks = functions_1.allocatePartialBinary(view, offset, maskSize);
}

@@ -70,0 +70,0 @@ else {

@@ -5,10 +5,10 @@ /**

export default class RawIconItem {
bin: ArrayBuffer;
width: number;
height: number;
bitCount: number;
constructor(bin: ArrayBuffer, width: number, height: number, bitCount: number);
static from(bin: ArrayBuffer, width: number, height: number, bitCount: number): RawIconItem;
bin: ArrayBuffer;
constructor(bin: ArrayBuffer | ArrayBufferView, width: number, height: number, bitCount: number, byteOffset?: number, byteLength?: number);
static from(bin: ArrayBuffer | ArrayBufferView, width: number, height: number, bitCount: number, byteOffset?: number, byteLength?: number): RawIconItem;
isIcon(): false;
isRaw(): this is RawIconItem;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var functions_1 = require("../util/functions");
/**

@@ -7,10 +8,17 @@ * Represents the raw-graphic icon item, such as PNG data.

var RawIconItem = /** @class */ (function () {
function RawIconItem(bin, width, height, bitCount) {
this.bin = bin;
function RawIconItem(bin, width, height, bitCount, byteOffset, byteLength) {
this.width = width;
this.height = height;
this.bitCount = bitCount;
if (typeof byteOffset !== 'number') {
byteOffset = 0;
byteLength = bin.byteLength;
}
else if (typeof byteLength !== 'number') {
byteLength = bin.byteLength - byteOffset;
}
this.bin = functions_1.allocatePartialBinary(bin, byteOffset, byteLength);
}
RawIconItem.from = function (bin, width, height, bitCount) {
return new RawIconItem(bin, width, height, bitCount);
RawIconItem.from = function (bin, width, height, bitCount, byteOffset, byteLength) {
return new RawIconItem(bin, width, height, bitCount, byteOffset, byteLength);
};

@@ -17,0 +25,0 @@ RawIconItem.prototype.isIcon = function () {

@@ -11,2 +11,3 @@ import ArrayFormatBase from './ArrayFormatBase';

private constructor();
/** @note This does not clone binary data; the changes to the array will modify the specified buffer `bin` */
static from(bin: ArrayBuffer, offset?: number): ImageDataDirectoryArray;

@@ -13,0 +14,0 @@ get(index: number): Readonly<ImageDataDirectory>;

@@ -24,2 +24,3 @@ "use strict";

}
/** @note This does not clone binary data; the changes to the array will modify the specified buffer `bin` */
ImageDataDirectoryArray.from = function (bin, offset) {

@@ -26,0 +27,0 @@ if (offset === void 0) { offset = 0; }

@@ -6,2 +6,3 @@ declare enum ImageDirectoryEntry {

Exception = 3,
Certificate = 4,
Security = 4,

@@ -8,0 +9,0 @@ BaseRelocation = 5,

@@ -9,2 +9,4 @@ "use strict";

ImageDirectoryEntry[ImageDirectoryEntry["Exception"] = 3] = "Exception";
ImageDirectoryEntry[ImageDirectoryEntry["Certificate"] = 4] = "Certificate";
// alias
ImageDirectoryEntry[ImageDirectoryEntry["Security"] = 4] = "Security";

@@ -11,0 +13,0 @@ ImageDirectoryEntry[ImageDirectoryEntry["BaseRelocation"] = 5] = "BaseRelocation";

@@ -6,3 +6,3 @@ import FormatBase from './FormatBase';

private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageDosHeader;
static from(bin: ArrayBuffer | ArrayBufferView, offset?: number): ImageDosHeader;
isValid(): boolean;

@@ -9,0 +9,0 @@ get magic(): number;

@@ -17,2 +17,3 @@ "use strict";

var FormatBase_1 = require("./FormatBase");
var functions_1 = require("../util/functions");
var ImageDosHeader = /** @class */ (function (_super) {

@@ -25,3 +26,3 @@ __extends(ImageDosHeader, _super);

if (offset === void 0) { offset = 0; }
return new ImageDosHeader(new DataView(bin, offset, 64));
return new ImageDosHeader(functions_1.createDataView(bin, offset, 64));
};

@@ -28,0 +29,0 @@ ImageDosHeader.prototype.isValid = function () {

@@ -9,3 +9,3 @@ import FormatBase from './FormatBase';

private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageNtHeaders;
static from(bin: ArrayBuffer | ArrayBufferView, offset?: number): ImageNtHeaders;
isValid(): boolean;

@@ -18,3 +18,4 @@ is32bit(): boolean;

get optionalHeaderDataDirectory(): ImageDataDirectoryArray;
getDataDirectoryOffset(): number;
getSectionHeaderOffset(): number;
}

@@ -21,2 +21,3 @@ "use strict";

var ImageDataDirectoryArray_1 = require("./ImageDataDirectoryArray");
var functions_1 = require("../util/functions");
var ImageNtHeaders = /** @class */ (function (_super) {

@@ -29,3 +30,3 @@ __extends(ImageNtHeaders, _super);

if (offset === void 0) { offset = 0; }
var magic = new DataView(bin, offset + ImageFileHeader_1.default.size, 6).getUint16(4, true);
var magic = functions_1.createDataView(bin, offset + ImageFileHeader_1.default.size, 6).getUint16(4, true);
var len = 4 + ImageFileHeader_1.default.size + ImageDataDirectoryArray_1.default.size;

@@ -38,3 +39,3 @@ if (magic === ImageOptionalHeader64_1.default.DEFAULT_MAGIC) {

}
return new ImageNtHeaders(new DataView(bin, offset, len));
return new ImageNtHeaders(functions_1.createDataView(bin, offset, len));
};

@@ -81,11 +82,3 @@ ImageNtHeaders.prototype.isValid = function () {

get: function () {
var off = ImageFileHeader_1.default.size + 4;
var magic = this.view.getUint16(off, true);
if (magic === ImageOptionalHeader64_1.default.DEFAULT_MAGIC) {
off += ImageOptionalHeader64_1.default.size;
}
else {
off += ImageOptionalHeader_1.default.size;
}
return ImageDataDirectoryArray_1.default.from(this.view.buffer, this.view.byteOffset + off);
return ImageDataDirectoryArray_1.default.from(this.view.buffer, this.view.byteOffset + this.getDataDirectoryOffset());
},

@@ -95,3 +88,4 @@ enumerable: true,

});
ImageNtHeaders.prototype.getSectionHeaderOffset = function () {
// @internal
ImageNtHeaders.prototype.getDataDirectoryOffset = function () {
var off = ImageFileHeader_1.default.size + 4;

@@ -105,4 +99,7 @@ var magic = this.view.getUint16(off, true);

}
return off + ImageDataDirectoryArray_1.default.size;
return off;
};
ImageNtHeaders.prototype.getSectionHeaderOffset = function () {
return this.getDataDirectoryOffset() + ImageDataDirectoryArray_1.default.size;
};
ImageNtHeaders.DEFAULT_SIGNATURE = 0x4550; // 'PE\x00\x00'

@@ -109,0 +106,0 @@ return ImageNtHeaders;

@@ -7,2 +7,3 @@ import NtExecutable from './NtExecutable';

import * as Resource from './resource';
export { NtExecutable, NtExecutableResource, version, Data, Format, Resource };
import { generateExecutableWithSign, SignerObject } from './sign';
export { NtExecutable, NtExecutableResource, version, Data, Format, Resource, generateExecutableWithSign, SignerObject, };

@@ -15,1 +15,3 @@ "use strict";

exports.Resource = Resource;
var sign_1 = require("./sign");
exports.generateExecutableWithSign = sign_1.generateExecutableWithSign;
import ImageDirectoryEntry from './format/ImageDirectoryEntry';
import ImageDosHeader from './format/ImageDosHeader';
import ImageNtHeaders from './format/ImageNtHeaders';
import { ImageSectionHeader } from './format/ImageSectionHeaderArray';
export interface NtExecutableFromOptions {
/** true to parse binary even if the binary contains Certificate data (i.e. 'signed') */
ignoreCert?: boolean;
}
export interface NtExecutableSection {

@@ -18,5 +24,6 @@ info: ImageSectionHeader;

* @param bin binary data
* @param options additional option for parsing
* @return NtExecutable instance
*/
static from(bin: ArrayBuffer): NtExecutable;
static from(bin: ArrayBuffer | ArrayBufferView, options?: NtExecutableFromOptions): NtExecutable;
/**

@@ -27,2 +34,5 @@ * Returns whether the executable is for 32-bit architecture

getTotalHeaderSize(): number;
get dosHeader(): ImageDosHeader;
get newHeader(): ImageNtHeaders;
getRawHeader(): ArrayBuffer;
getImageBase(): number;

@@ -55,5 +65,5 @@ getFileAlignment(): number;

*/
generate(): ArrayBuffer;
generate(paddingSize?: number): ArrayBuffer;
private rearrangeSections;
private replaceSectionImpl;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ImageDataDirectoryArray_1 = require("./format/ImageDataDirectoryArray");
var ImageDirectoryEntry_1 = require("./format/ImageDirectoryEntry");

@@ -35,5 +36,6 @@ var ImageDosHeader_1 = require("./format/ImageDosHeader");

* @param bin binary data
* @param options additional option for parsing
* @return NtExecutable instance
*/
NtExecutable.from = function (bin) {
NtExecutable.from = function (bin, options) {
var dh = ImageDosHeader_1.default.from(bin);

@@ -47,7 +49,8 @@ var nh = ImageNtHeaders_1.default.from(bin, dh.newHeaderAddress);

}
// Currently we cannot treat signed executables properly
// (Signed executables may be supported with some restrictions in the future)
var securityEntry = nh.optionalHeaderDataDirectory.get(ImageDirectoryEntry_1.default.Security);
var securityEntry = nh.optionalHeaderDataDirectory.get(ImageDirectoryEntry_1.default.Certificate);
if (securityEntry && securityEntry.size > 0) {
throw new Error('Signed executable binary is not supported now');
// Signed executables should be parsed only when `ignoreCert` is true
if (!options || !options.ignoreCert) {
throw new Error('Parsing signed executable binary is not allowed by default.');
}
}

@@ -57,3 +60,4 @@ var secOff = dh.newHeaderAddress + nh.getSectionHeaderOffset();

var sections = [];
var secArray = ImageSectionHeaderArray_1.default.from(bin, secCount, secOff);
var tempSectionHeaderBinary = functions_1.allocatePartialBinary(bin, secOff, secCount * ImageSectionHeaderArray_1.default.itemSize);
var secArray = ImageSectionHeaderArray_1.default.from(tempSectionHeaderBinary, secCount, 0);
// console.log(`from data size 0x${bin.byteLength.toString(16)}:`);

@@ -70,5 +74,4 @@ secArray.forEach(function (info) {

else {
var secBin = new ArrayBuffer(info.sizeOfRawData);
// console.log(` section ${info.name}: 0x${info.pointerToRawData.toString(16)}, size = 0x${info.sizeOfRawData.toString(16)}`);
functions_1.copyBuffer(secBin, 0, bin, info.pointerToRawData, info.sizeOfRawData);
var secBin = functions_1.allocatePartialBinary(bin, info.pointerToRawData, info.sizeOfRawData);
sections.push({

@@ -81,4 +84,3 @@ info: info,

// the size of DOS and NT headers is equal to section offset
var headers = new ArrayBuffer(secOff);
functions_1.copyBuffer(headers, 0, bin, 0, secOff);
var headers = functions_1.allocatePartialBinary(bin, 0, secOff);
return new NtExecutable(headers, sections);

@@ -95,2 +97,20 @@ };

};
Object.defineProperty(NtExecutable.prototype, "dosHeader", {
get: function () {
return this._dh;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NtExecutable.prototype, "newHeader", {
get: function () {
return this._nh;
},
enumerable: true,
configurable: true
});
// @internal
NtExecutable.prototype.getRawHeader = function () {
return this._headers;
};
NtExecutable.prototype.getImageBase = function () {

@@ -225,3 +245,3 @@ return this._nh.optionalHeader.imageBase;

*/
NtExecutable.prototype.generate = function () {
NtExecutable.prototype.generate = function (paddingSize) {
// calculate binary size

@@ -232,3 +252,3 @@ var dh = this._dh;

var size = secOff;
size += this._sections.length * 40;
size += this._sections.length * ImageSectionHeaderArray_1.default.itemSize;
var align = nh.optionalHeader.fileAlignment;

@@ -246,2 +266,5 @@ size = Math.floor((size + align - 1) / align) * align;

});
if (typeof paddingSize === 'number') {
size += Math.floor((paddingSize + align - 1) / align) * align;
}
// make buffer

@@ -251,3 +274,8 @@ var bin = new ArrayBuffer(size);

u8bin.set(new Uint8Array(this._headers, 0, secOff));
var secArray = ImageSectionHeaderArray_1.default.from(bin, this._sections.length * 40, secOff);
// reset Security section offset (eliminate it)
ImageDataDirectoryArray_1.default.from(bin, dh.newHeaderAddress + nh.getDataDirectoryOffset()).set(ImageDirectoryEntry_1.default.Certificate, {
size: 0,
virtualAddress: 0,
});
var secArray = ImageSectionHeaderArray_1.default.from(bin, this._sections.length, secOff);
this._sections.forEach(function (sec, i) {

@@ -254,0 +282,0 @@ if (!sec.data) {

@@ -229,3 +229,3 @@ "use strict";

name: name,
entireBin: functions_1.allocatePartialBinary(view.buffer, view.byteOffset + offset, childLen),
entireBin: functions_1.allocatePartialBinary(view, offset, childLen),
});

@@ -232,0 +232,0 @@ break;

export declare function cloneObject<T extends object>(object: Readonly<T>): T;
export declare function cloneObject<T extends object>(object: T): T;
export declare function createDataView(bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): DataView;
export declare function calculateCheckSumForPE(bin: ArrayBuffer, storeToBinary?: boolean): number;
export declare function roundUp(val: number, align: number): number;
export declare function copyBuffer(dest: ArrayBuffer, destOffset: number, src: ArrayBuffer, srcOffset: number, length: number): void;
export declare function allocatePartialBinary(binBase: ArrayBuffer, offset: number, length: number): ArrayBuffer;
export declare function copyBuffer(dest: ArrayBuffer, destOffset: number, src: ArrayBuffer | ArrayBufferView, srcOffset: number, length: number): void;
export declare function allocatePartialBinary(binBase: ArrayBuffer | ArrayBufferView, offset: number, length: number): ArrayBuffer;
export declare function cloneToArrayBuffer(binBase: ArrayBuffer | ArrayBufferView): ArrayBuffer;
export declare function readInt32WithLastOffset(view: DataView, offset: number, last: number): number;

@@ -8,0 +10,0 @@ export declare function readUint8WithLastOffset(view: DataView, offset: number, last: number): number;

@@ -12,2 +12,20 @@ "use strict";

exports.cloneObject = cloneObject;
function createDataView(bin, byteOffset, byteLength) {
if ('buffer' in bin) {
var newOffset = bin.byteOffset;
var newLength = bin.byteLength;
if (typeof byteOffset !== 'undefined') {
newOffset += byteOffset;
newLength -= byteOffset;
}
if (typeof byteLength !== 'undefined') {
newLength = byteLength;
}
return new DataView(bin.buffer, newOffset, newLength);
}
else {
return new DataView(bin, byteOffset, byteLength);
}
}
exports.createDataView = createDataView;
function calculateCheckSumForPE(bin, storeToBinary) {

@@ -54,3 +72,8 @@ var dosHeader = ImageDosHeader_1.default.from(bin);

function copyBuffer(dest, destOffset, src, srcOffset, length) {
new Uint8Array(dest, destOffset, length).set(new Uint8Array(src, srcOffset, length));
if ('buffer' in src) {
new Uint8Array(dest, destOffset, length).set(new Uint8Array(src.buffer, src.byteOffset + (srcOffset || 0), length));
}
else {
new Uint8Array(dest, destOffset, length).set(new Uint8Array(src, srcOffset, length));
}
}

@@ -64,2 +87,15 @@ exports.copyBuffer = copyBuffer;

exports.allocatePartialBinary = allocatePartialBinary;
function cloneToArrayBuffer(binBase) {
if ('buffer' in binBase) {
var b = new ArrayBuffer(binBase.byteLength);
new Uint8Array(b).set(new Uint8Array(binBase.buffer, binBase.byteOffset, binBase.byteLength));
return b;
}
else {
var b = new ArrayBuffer(binBase.byteLength);
new Uint8Array(b).set(new Uint8Array(binBase));
return b;
}
}
exports.cloneToArrayBuffer = cloneToArrayBuffer;
function readInt32WithLastOffset(view, offset, last) {

@@ -66,0 +102,0 @@ return offset + 4 <= last ? view.getInt32(offset, true) : 0;

@@ -1,2 +0,2 @@

declare const _default: "0.3.1";
declare const _default: "0.4.0";
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = '0.3.1';
exports.default = '0.4.0';
{
"name": "resedit",
"version": "0.3.1",
"version": "0.4.0",
"engines": {

@@ -5,0 +5,0 @@ "node": ">=10",

@@ -18,6 +18,28 @@ [![NPM version](https://badge.fury.io/js/resedit.svg)](https://www.npmjs.com/package/resedit)

- Executables for 16-bit Windows is not supported.
- Signed executables are not supported and throw an error when calling `NtExecutable.from`.
- `.res` file is not supported now.
- PNG-based icon data is supported on `require('resedit').Resource.IconGroupEntry` class.
## Parsing signed executables
- Parsing signed executables (by using Authenticode or etc.) is not allowed by default and an exception will be thrown if `NtExecutable.from` receives a signed binary.
- To parse signed, `{ ignoreCert: true }` object must be passed to the second argument of `NtExecutable.from`.
- Although the base executable data is signed, `NtExecutable.generate` will generate unsigned executable binary. If you want to re-sign it, generate function with signing (see below) or any other signing tool such as Microsoft `signtool` must be used.
## (Beta) Signing executables with resedit-js
resedit-js provides basic signing process `generateExecutableWithSign` function, which is based on [Authenticode specification](https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx) and related RFCs.
To keep resedit-js generic library, the followings are required to use signing process.
- Encryption / calculating hash (digest) process (e.g. Node.js built-in `crypto` module)
- A private key data is implicitly required to encrypt data.
- DER-format public key binary (such as `*.cer` file data or `*.p7b` file data with DER-format), which is paired with the private key used by encryption process.
- (optional) Generating timestamp data, especially communicating with TSA server (e.g. HTTP/HTTPS API)
These requirements are represented as [`SignerObject`](./src/main/sign/SignerObject.ts). The caller of `generateExecutableWithSign` function must implement this object to sign executables.
An example code is here: [signTest.js](./examples/sign/signTest.js)
Note that resedit-js only provides basic signing process, and provides as beta version. For example adding more attributes/informations to certificates are not supported now.
## Notes

@@ -38,3 +60,3 @@

let data = fs.readFileSync('MyApp.exe');
let exe = ResEdit.NtExecutable.from(data.buffer);
let exe = ResEdit.NtExecutable.from(data);
let res = ResEdit.NtExecutableResource.from(exe);

@@ -41,0 +63,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc