main funcions fixes

This commit is contained in:
2025-09-29 22:06:11 +09:00
parent 40e016e128
commit c8c3274527
7995 changed files with 1517998 additions and 1057 deletions

View File

@@ -0,0 +1,90 @@
import ImageDirectoryEntry from './format/ImageDirectoryEntry.js';
import ImageDosHeader from './format/ImageDosHeader.js';
import ImageNtHeaders from './format/ImageNtHeaders.js';
import { ImageSectionHeader } from './format/ImageSectionHeaderArray.js';
export interface NtExecutableFromOptions {
/** true to parse binary even if the binary contains Certificate data (i.e. 'signed') */
ignoreCert?: boolean;
}
export interface NtExecutableSection {
info: ImageSectionHeader;
data: ArrayBuffer | null;
}
export default class NtExecutable {
private readonly _headers;
private readonly _sections;
private _ex;
private readonly _dh;
private readonly _nh;
private readonly _dda;
private constructor();
/**
* Creates an NtExecutable instance with an 'empty' executable binary.
* @param is32Bit set true if the binary is for 32-bit (default: false)
* @param isDLL set true if the binary is DLL (default: true)
* @return NtExecutable instance
*/
static createEmpty(is32Bit?: boolean, isDLL?: boolean): NtExecutable;
/**
* Parse the binary and create NtExecutable instance.
* An error will be thrown if the binary data is invalid
* @param bin binary data
* @param options additional option for parsing
* @return NtExecutable instance
*/
static from(bin: ArrayBuffer | ArrayBufferView, options?: NtExecutableFromOptions): NtExecutable;
/**
* Returns whether the executable is for 32-bit architecture
*/
is32bit(): boolean;
getTotalHeaderSize(): number;
get dosHeader(): ImageDosHeader;
get newHeader(): ImageNtHeaders;
getRawHeader(): ArrayBuffer;
getImageBase(): number;
getFileAlignment(): number;
getSectionAlignment(): number;
/**
* Return all sections. The returned array is sorted by raw address.
*/
getAllSections(): readonly NtExecutableSection[];
/**
* Return the section data from ImageDirectoryEntry enum value.
* @note
* The returned instance is equal to the value in {@link getAllSections}'s return value.
*/
getSectionByEntry(entry: ImageDirectoryEntry): Readonly<NtExecutableSection> | null;
/**
* Set the section data from ImageDirectoryEntry enum value.
* If entry is found, then replaces the secion data. If not found, then adds the section data.
*
* NOTE: 'virtualAddress' and 'pointerToRawData' of section object is ignored
* and calculated automatically. 'virtualSize' and 'sizeOfRawData' are used, but
* if the 'section.data.byteLength' is larger than 'sizeOfRawData', then
* these members are replaced.
*
* @param entry ImageDirectoryEntry enum value for the section
* @param section the section data, or null to remove the section
*/
setSectionByEntry(entry: ImageDirectoryEntry, section: Readonly<NtExecutableSection> | null): void;
/**
* Returns the extra data in the executable, or `null` if nothing.
* You can rewrite the returned buffer without using `setExtraData` if
* the size of the new data is equal to the old data.
*/
getExtraData(): ArrayBuffer | null;
/**
* Specifies the new extra data in the executable.
* The specified buffer will be cloned and you can release it after calling this method.
* @param bin buffer containing the new data
* @note
* The extra data will not be aligned by `NtExecutable`.
*/
setExtraData(bin: ArrayBuffer | ArrayBufferView | null): void;
/**
* Generates the executable binary data.
*/
generate(paddingSize?: number): ArrayBuffer;
private rearrangeSections;
private replaceSectionImpl;
}

View File

@@ -0,0 +1,420 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ImageDataDirectoryArray_js_1 = require("./format/ImageDataDirectoryArray.js");
var ImageDirectoryEntry_js_1 = require("./format/ImageDirectoryEntry.js");
var ImageDosHeader_js_1 = require("./format/ImageDosHeader.js");
var ImageNtHeaders_js_1 = require("./format/ImageNtHeaders.js");
var ImageSectionHeaderArray_js_1 = require("./format/ImageSectionHeaderArray.js");
var functions_js_1 = require("./util/functions.js");
var generate_js_1 = require("./util/generate.js");
var NtExecutable = /** @class */ (function () {
function NtExecutable(_headers, _sections, _ex) {
this._headers = _headers;
this._sections = _sections;
this._ex = _ex;
var dh = ImageDosHeader_js_1.default.from(_headers);
var nh = ImageNtHeaders_js_1.default.from(_headers, dh.newHeaderAddress);
this._dh = dh;
this._nh = nh;
this._dda = nh.optionalHeaderDataDirectory;
_sections.sort(function (a, b) {
var ra = a.info.pointerToRawData;
var rb = a.info.pointerToRawData;
if (ra !== rb) {
return ra - rb;
}
var va = a.info.virtualAddress;
var vb = b.info.virtualAddress;
if (va === vb) {
return a.info.virtualSize - b.info.virtualSize;
}
return va - vb;
});
}
/**
* Creates an NtExecutable instance with an 'empty' executable binary.
* @param is32Bit set true if the binary is for 32-bit (default: false)
* @param isDLL set true if the binary is DLL (default: true)
* @return NtExecutable instance
*/
NtExecutable.createEmpty = function (is32Bit, isDLL) {
if (is32Bit === void 0) { is32Bit = false; }
if (isDLL === void 0) { isDLL = true; }
return this.from(generate_js_1.makeEmptyNtExecutableBinary(is32Bit, isDLL));
};
/**
* Parse the binary and create NtExecutable instance.
* An error will be thrown if the binary data is invalid
* @param bin binary data
* @param options additional option for parsing
* @return NtExecutable instance
*/
NtExecutable.from = function (bin, options) {
var dh = ImageDosHeader_js_1.default.from(bin);
var nh = ImageNtHeaders_js_1.default.from(bin, dh.newHeaderAddress);
if (!dh.isValid() || !nh.isValid()) {
throw new TypeError('Invalid binary format');
}
if (nh.fileHeader.numberOfSymbols > 0) {
throw new Error('Binary with symbols is not supported now');
}
var fileAlignment = nh.optionalHeader.fileAlignment;
var securityEntry = nh.optionalHeaderDataDirectory.get(ImageDirectoryEntry_js_1.default.Certificate);
if (securityEntry.size > 0) {
// Signed executables should be parsed only when `ignoreCert` is true
if (!(options === null || options === void 0 ? void 0 : options.ignoreCert)) {
throw new Error('Parsing signed executable binary is not allowed by default.');
}
}
var secOff = dh.newHeaderAddress + nh.getSectionHeaderOffset();
var secCount = nh.fileHeader.numberOfSections;
var sections = [];
var tempSectionHeaderBinary = functions_js_1.allocatePartialBinary(bin, secOff, secCount * ImageSectionHeaderArray_js_1.default.itemSize);
var secArray = ImageSectionHeaderArray_js_1.default.from(tempSectionHeaderBinary, secCount, 0);
var lastOffset = functions_js_1.roundUp(secOff + secCount * ImageSectionHeaderArray_js_1.default.itemSize, fileAlignment);
// console.log(`from data size 0x${bin.byteLength.toString(16)}:`);
secArray.forEach(function (info) {
if (!info.pointerToRawData || !info.sizeOfRawData) {
info.pointerToRawData = 0;
info.sizeOfRawData = 0;
sections.push({
info: info,
data: null,
});
}
else {
// console.log(` section ${info.name}: 0x${info.pointerToRawData.toString(16)}, size = 0x${info.sizeOfRawData.toString(16)}`);
var secBin = functions_js_1.allocatePartialBinary(bin, info.pointerToRawData, info.sizeOfRawData);
sections.push({
info: info,
data: secBin,
});
var secEndOffset = functions_js_1.roundUp(info.pointerToRawData + info.sizeOfRawData, fileAlignment);
if (secEndOffset > lastOffset) {
lastOffset = secEndOffset;
}
}
});
// the size of DOS and NT headers is equal to section offset
var headers = functions_js_1.allocatePartialBinary(bin, 0, secOff);
// extra data
var exData = null;
var lastExDataOffset = bin.byteLength;
// It may contain that both extra data and certificate data are available.
// In this case the extra data is followed by the certificate data.
if (securityEntry.size > 0) {
lastExDataOffset = securityEntry.virtualAddress;
}
if (lastOffset < lastExDataOffset) {
exData = functions_js_1.allocatePartialBinary(bin, lastOffset, lastExDataOffset - lastOffset);
}
return new NtExecutable(headers, sections, exData);
};
/**
* Returns whether the executable is for 32-bit architecture
*/
NtExecutable.prototype.is32bit = function () {
return this._nh.is32bit();
};
NtExecutable.prototype.getTotalHeaderSize = function () {
return this._headers.byteLength;
};
Object.defineProperty(NtExecutable.prototype, "dosHeader", {
get: function () {
return this._dh;
},
enumerable: false,
configurable: true
});
Object.defineProperty(NtExecutable.prototype, "newHeader", {
get: function () {
return this._nh;
},
enumerable: false,
configurable: true
});
NtExecutable.prototype.getRawHeader = function () {
return this._headers;
};
NtExecutable.prototype.getImageBase = function () {
return this._nh.optionalHeader.imageBase;
};
NtExecutable.prototype.getFileAlignment = function () {
return this._nh.optionalHeader.fileAlignment;
};
NtExecutable.prototype.getSectionAlignment = function () {
return this._nh.optionalHeader.sectionAlignment;
};
/**
* Return all sections. The returned array is sorted by raw address.
*/
NtExecutable.prototype.getAllSections = function () {
return this._sections;
};
/**
* Return the section data from ImageDirectoryEntry enum value.
* @note
* The returned instance is equal to the value in {@link getAllSections}'s return value.
*/
NtExecutable.prototype.getSectionByEntry = function (entry) {
var dd = this._dda.get(entry);
var r = this._sections
.filter(function (sec) {
var vaEnd = sec.info.virtualAddress + sec.info.virtualSize;
return (dd.virtualAddress >= sec.info.virtualAddress &&
dd.virtualAddress < vaEnd);
})
.shift();
return r !== undefined ? r : null;
};
/**
* Set the section data from ImageDirectoryEntry enum value.
* If entry is found, then replaces the secion data. If not found, then adds the section data.
*
* NOTE: 'virtualAddress' and 'pointerToRawData' of section object is ignored
* and calculated automatically. 'virtualSize' and 'sizeOfRawData' are used, but
* if the 'section.data.byteLength' is larger than 'sizeOfRawData', then
* these members are replaced.
*
* @param entry ImageDirectoryEntry enum value for the section
* @param section the section data, or null to remove the section
*/
NtExecutable.prototype.setSectionByEntry = function (entry, section) {
var sec = section
? { data: section.data, info: section.info }
: null;
var dd = this._dda.get(entry);
var hasEntry = dd.size > 0;
if (!sec) {
if (!hasEntry) {
// no need to replace
}
else {
// clear entry
this._dda.set(entry, { size: 0, virtualAddress: 0 });
var len = this._sections.length;
for (var i = 0; i < len; ++i) {
var sec_1 = this._sections[i];
var vaStart = sec_1.info.virtualAddress;
var vaLast = vaStart + sec_1.info.virtualSize;
if (dd.virtualAddress >= vaStart &&
dd.virtualAddress < vaLast) {
this._sections.splice(i, 1);
// section count changed
this._nh.fileHeader.numberOfSections =
this._sections.length;
break;
}
}
}
}
else {
var rawSize = !sec.data ? 0 : sec.data.byteLength;
var fileAlign = this._nh.optionalHeader.fileAlignment;
var secAlign = this._nh.optionalHeader.sectionAlignment;
var alignedFileSize = !sec.data ? 0 : functions_js_1.roundUp(rawSize, fileAlign);
var alignedSecSize = !sec.data
? 0
: functions_js_1.roundUp(sec.info.virtualSize, secAlign);
if (sec.info.sizeOfRawData < alignedFileSize) {
sec.info.sizeOfRawData = alignedFileSize;
}
else {
alignedFileSize = sec.info.sizeOfRawData;
}
if (!hasEntry) {
var virtAddr_1 = 0;
var rawAddr_1 = functions_js_1.roundUp(this._headers.byteLength, fileAlign);
// get largest addresses
this._sections.forEach(function (secExist) {
if (secExist.info.pointerToRawData) {
if (rawAddr_1 <= secExist.info.pointerToRawData) {
rawAddr_1 =
secExist.info.pointerToRawData +
secExist.info.sizeOfRawData;
}
}
if (virtAddr_1 <= secExist.info.virtualAddress) {
virtAddr_1 =
secExist.info.virtualAddress +
secExist.info.virtualSize;
}
});
if (!alignedFileSize) {
rawAddr_1 = 0;
}
if (!virtAddr_1) {
virtAddr_1 = this.newHeader.optionalHeader.baseOfCode;
}
virtAddr_1 = functions_js_1.roundUp(virtAddr_1, secAlign);
sec.info.pointerToRawData = rawAddr_1;
sec.info.virtualAddress = virtAddr_1;
// add entry
this._dda.set(entry, {
size: rawSize,
virtualAddress: virtAddr_1,
});
this._sections.push(sec);
// section count changed
this._nh.fileHeader.numberOfSections = this._sections.length;
// change image size
this._nh.optionalHeader.sizeOfImage = functions_js_1.roundUp(virtAddr_1 + alignedSecSize, this._nh.optionalHeader.sectionAlignment);
}
else {
// replace entry
this.replaceSectionImpl(dd.virtualAddress, sec.info, sec.data);
}
}
};
/**
* Returns the extra data in the executable, or `null` if nothing.
* You can rewrite the returned buffer without using `setExtraData` if
* the size of the new data is equal to the old data.
*/
NtExecutable.prototype.getExtraData = function () {
return this._ex;
};
/**
* Specifies the new extra data in the executable.
* The specified buffer will be cloned and you can release it after calling this method.
* @param bin buffer containing the new data
* @note
* The extra data will not be aligned by `NtExecutable`.
*/
NtExecutable.prototype.setExtraData = function (bin) {
if (bin === null) {
this._ex = null;
}
else {
this._ex = functions_js_1.cloneToArrayBuffer(bin);
}
};
/**
* Generates the executable binary data.
*/
NtExecutable.prototype.generate = function (paddingSize) {
// calculate binary size
var dh = this._dh;
var nh = this._nh;
var secOff = dh.newHeaderAddress + nh.getSectionHeaderOffset();
var size = secOff;
size += this._sections.length * ImageSectionHeaderArray_js_1.default.itemSize;
var align = nh.optionalHeader.fileAlignment;
size = functions_js_1.roundUp(size, align);
this._sections.forEach(function (sec) {
if (!sec.info.pointerToRawData) {
return;
}
var lastOff = sec.info.pointerToRawData + sec.info.sizeOfRawData;
if (size < lastOff) {
size = lastOff;
size = functions_js_1.roundUp(size, align);
}
});
var lastPosition = size;
if (this._ex !== null) {
size += this._ex.byteLength;
}
if (typeof paddingSize === 'number') {
size += paddingSize;
}
// make buffer
var bin = new ArrayBuffer(size);
var u8bin = new Uint8Array(bin);
u8bin.set(new Uint8Array(this._headers, 0, secOff));
// reset Security section offset (eliminate it)
ImageDataDirectoryArray_js_1.default.from(bin, dh.newHeaderAddress + nh.getDataDirectoryOffset()).set(ImageDirectoryEntry_js_1.default.Certificate, {
size: 0,
virtualAddress: 0,
});
var secArray = ImageSectionHeaderArray_js_1.default.from(bin, this._sections.length, secOff);
this._sections.forEach(function (sec, i) {
if (!sec.data) {
sec.info.pointerToRawData = 0;
sec.info.sizeOfRawData = 0;
}
secArray.set(i, sec.info);
if (!sec.data || !sec.info.pointerToRawData) {
return;
}
u8bin.set(new Uint8Array(sec.data), sec.info.pointerToRawData);
});
if (this._ex !== null) {
u8bin.set(new Uint8Array(this._ex), lastPosition);
}
// re-calc checksum
if (nh.optionalHeader.checkSum !== 0) {
functions_js_1.calculateCheckSumForPE(bin, true);
}
return bin;
};
NtExecutable.prototype.rearrangeSections = function (rawAddressStart, rawDiff, virtualAddressStart, virtualDiff) {
if (!rawDiff && !virtualDiff) {
return;
}
var nh = this._nh;
var secAlign = nh.optionalHeader.sectionAlignment;
var dirs = this._dda;
var len = this._sections.length;
var lastVirtAddress = 0;
for (var i = 0; i < len; ++i) {
var sec = this._sections[i];
var virtAddr = sec.info.virtualAddress;
if (virtualDiff && virtAddr >= virtualAddressStart) {
var iDir = dirs.findIndexByVirtualAddress(virtAddr);
virtAddr += virtualDiff;
if (iDir !== null) {
dirs.set(iDir, {
virtualAddress: virtAddr,
size: sec.info.virtualSize,
});
}
sec.info.virtualAddress = virtAddr;
}
var fileAddr = sec.info.pointerToRawData;
if (rawDiff && fileAddr >= rawAddressStart) {
sec.info.pointerToRawData = fileAddr + rawDiff;
}
lastVirtAddress = functions_js_1.roundUp(sec.info.virtualAddress + sec.info.virtualSize, secAlign);
}
// fix image size from last virtual address
nh.optionalHeader.sizeOfImage = lastVirtAddress;
};
// NOTE: info.virtualSize must be valid
NtExecutable.prototype.replaceSectionImpl = function (virtualAddress, info, data) {
var len = this._sections.length;
for (var i = 0; i < len; ++i) {
var s = this._sections[i];
// console.log(`replaceSectionImpl: ${virtualAddress} <--> ${s.info.virtualAddress}`);
if (s.info.virtualAddress === virtualAddress) {
// console.log(` found`);
var secAlign = this._nh.optionalHeader.sectionAlignment;
var fileAddr = s.info.pointerToRawData;
var oldFileAddr = fileAddr + s.info.sizeOfRawData;
var oldVirtAddr = virtualAddress + functions_js_1.roundUp(s.info.virtualSize, secAlign);
s.info = functions_js_1.cloneObject(info);
s.info.virtualAddress = virtualAddress;
s.info.pointerToRawData = fileAddr;
s.data = data;
// shift addresses
var newFileAddr = fileAddr + info.sizeOfRawData;
var newVirtAddr = virtualAddress + functions_js_1.roundUp(info.virtualSize, secAlign);
this.rearrangeSections(oldFileAddr, newFileAddr - oldFileAddr, oldVirtAddr, newVirtAddr - oldVirtAddr);
// BLOCK: rewrite DataDirectory entry for specified virtualAddress
{
var dirs = this._dda;
var iDir = dirs.findIndexByVirtualAddress(virtualAddress);
if (iDir !== null) {
dirs.set(iDir, {
virtualAddress: virtualAddress,
size: info.virtualSize,
});
}
}
break;
}
}
};
return NtExecutable;
}());
exports.default = NtExecutable;

View File

@@ -0,0 +1,75 @@
import NtExecutable from './NtExecutable.js';
import { ImageSectionHeader } from './format/ImageSectionHeaderArray.js';
import ResourceEntry from './type/ResourceEntry.js';
/** Manages resource data for NtExecutable */
export default class NtExecutableResource {
/** The timestamp for resource */
dateTime: number;
/** The major version data for resource */
majorVersion: number;
/** The minor version data for resource */
minorVersion: number;
/** Resource entries */
entries: ResourceEntry[];
/**
* The section data header of resource data (used by outputResource method).
* This instance will be null if the base executable does not contain resource data.
* You can override this field before calling outputResource method.
* (Note that the addresses and sizes are ignored for output)
*/
sectionDataHeader: ImageSectionHeader | null;
private originalSize;
private constructor();
private parse;
/**
* Parses resource data for `NtExecutable`.
* This function returns valid instance even if
* the executable does not have resource data.
* @param exe `NtExecutable` instance
* @param ignoreUnparsableData (default: false) specify true if skipping 'unparsable' (e.g. unusual format) data.
* When true, the resource data may break on write operation.
*/
static from(exe: NtExecutable, ignoreUnparsableData?: boolean): NtExecutableResource;
/**
* Add or replace the resource entry.
* This method replaces the entry only if there is an entry with `type`, `id` and `lang` equal.
*/
replaceResourceEntry(entry: ResourceEntry): void;
/**
* Returns all resource entries, which has specified type and id, as UTF-8 string data.
* @param type Resource type
* @param id Resource id
* @returns an array of lang and value pair (tuple)
*/
getResourceEntriesAsString(type: string | number, id: string | number): Array<[lang: string | number, value: string]>;
/**
* Add or replace the resource entry with UTF-8 string data.
* This method is a wrapper of {@link NtExecutableResource.replaceResourceEntry}.
*/
replaceResourceEntryFromString(type: string | number, id: string | number, lang: string | number, value: string): void;
/**
* Removes resource entries which has specified type and id.
*/
removeResourceEntry(type: string | number, id: string | number, lang?: string | number): void;
/**
* Generates resource data binary for NtExecutable (not for .res file)
* @param virtualAddress The virtual address for the section
* @param alignment File alignment value of executable
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
generateResourceData(virtualAddress: number, alignment: number, noGrow?: boolean, allowShrink?: boolean): {
bin: ArrayBuffer;
rawSize: number;
dataOffset: number;
descEntryOffset: number;
descEntryCount: number;
};
/**
* Writes holding resource data to specified NtExecutable instance.
* @param exeDest An NtExecutable instance to write resource section to
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
outputResource(exeDest: NtExecutable, noGrow?: boolean, allowShrink?: boolean): void;
}

View File

@@ -0,0 +1,664 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ImageDirectoryEntry_js_1 = require("./format/ImageDirectoryEntry.js");
var functions_js_1 = require("./util/functions.js");
function removeDuplicates(a) {
return a.reduce(function (p, c) {
return p.indexOf(c) >= 0 ? p : p.concat(c);
}, []);
}
function readString(view, offset) {
var length = view.getUint16(offset, true);
var r = '';
offset += 2;
for (var i = 0; i < length; ++i) {
r += String.fromCharCode(view.getUint16(offset, true));
offset += 2;
}
return r;
}
function readLanguageTable(view, typeEntry, name, languageTable, cb) {
var off = languageTable;
var nameEntry = {
name: name,
languageTable: languageTable,
characteristics: view.getUint32(off, true),
dateTime: view.getUint32(off + 4, true),
majorVersion: view.getUint16(off + 8, true),
minorVersion: view.getUint16(off + 10, true),
};
var nameCount = view.getUint16(off + 12, true);
var idCount = view.getUint16(off + 14, true);
off += 16;
for (var i = 0; i < nameCount; ++i) {
var nameOffset = view.getUint32(off, true) & 0x7fffffff;
var dataOffset = view.getUint32(off + 4, true);
// ignore if the offset refers to the next table
if ((dataOffset & 0x80000000) !== 0) {
off += 8;
continue;
}
var name_1 = readString(view, nameOffset);
cb(typeEntry, nameEntry, { lang: name_1, dataOffset: dataOffset });
off += 8;
}
for (var i = 0; i < idCount; ++i) {
var id = view.getUint32(off, true) & 0x7fffffff;
var dataOffset = view.getUint32(off + 4, true);
// ignore if the offset refers to the next table
if ((dataOffset & 0x80000000) !== 0) {
off += 8;
continue;
}
cb(typeEntry, nameEntry, { lang: id, dataOffset: dataOffset });
off += 8;
}
}
function readNameTable(view, type, nameTable, cb) {
var off = nameTable;
var typeEntry = {
type: type,
nameTable: nameTable,
characteristics: view.getUint32(off, true),
dateTime: view.getUint32(off + 4, true),
majorVersion: view.getUint16(off + 8, true),
minorVersion: view.getUint16(off + 10, true),
};
var nameCount = view.getUint16(off + 12, true);
var idCount = view.getUint16(off + 14, true);
off += 16;
for (var i = 0; i < nameCount; ++i) {
var nameOffset = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
var name_2 = readString(view, nameOffset);
readLanguageTable(view, typeEntry, name_2, nextTable, cb);
off += 8;
}
for (var i = 0; i < idCount; ++i) {
var id = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
readLanguageTable(view, typeEntry, id, nextTable, cb);
off += 8;
}
}
function divideEntriesImplByID(r, names, entries) {
var entriesByString = {};
var entriesByNumber = {};
entries.forEach(function (e) {
if (typeof e.lang === 'string') {
entriesByString[e.lang] = e;
names.push(e.lang);
}
else {
entriesByNumber[e.lang] = e;
}
});
var strKeys = Object.keys(entriesByString);
strKeys.sort().forEach(function (type) {
r.s.push(entriesByString[type]);
});
var numKeys = Object.keys(entriesByNumber);
numKeys
.map(function (k) { return Number(k); })
.sort(function (a, b) { return a - b; })
.forEach(function (type) {
r.n.push(entriesByNumber[type]);
});
return 16 + 8 * (strKeys.length + numKeys.length);
}
function divideEntriesImplByName(r, names, entries) {
var entriesByString = {};
var entriesByNumber = {};
entries.forEach(function (e) {
var _a, _b;
if (typeof e.id === 'string') {
var a = (_a = entriesByString[e.id]) !== null && _a !== void 0 ? _a : (entriesByString[e.id] = []);
names.push(e.id);
a.push(e);
}
else {
var a = (_b = entriesByNumber[e.id]) !== null && _b !== void 0 ? _b : (entriesByNumber[e.id] = []);
a.push(e);
}
});
var sSum = Object.keys(entriesByString)
.sort()
.map(function (id) {
var o = {
id: id,
s: [],
n: [],
};
r.s.push(o);
return divideEntriesImplByID(o, names, entriesByString[id]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
var nSum = Object.keys(entriesByNumber)
.map(function (k) { return Number(k); })
.sort(function (a, b) { return a - b; })
.map(function (id) {
var o = {
id: id,
s: [],
n: [],
};
r.n.push(o);
return divideEntriesImplByID(o, names, entriesByNumber[id]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
return 16 + sSum + nSum;
}
function divideEntriesImplByType(r, names, entries) {
var entriesByString = {};
var entriesByNumber = {};
entries.forEach(function (e) {
var _a, _b;
if (typeof e.type === 'string') {
var a = (_a = entriesByString[e.type]) !== null && _a !== void 0 ? _a : (entriesByString[e.type] = []);
names.push(e.type);
a.push(e);
}
else {
var a = (_b = entriesByNumber[e.type]) !== null && _b !== void 0 ? _b : (entriesByNumber[e.type] = []);
a.push(e);
}
});
var sSum = Object.keys(entriesByString)
.sort()
.map(function (type) {
var o = { type: type, s: [], n: [] };
r.s.push(o);
return divideEntriesImplByName(o, names, entriesByString[type]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
var nSum = Object.keys(entriesByNumber)
.map(function (k) { return Number(k); })
.sort(function (a, b) { return a - b; })
.map(function (type) {
var o = { type: type, s: [], n: [] };
r.n.push(o);
return divideEntriesImplByName(o, names, entriesByNumber[type]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
return 16 + sSum + nSum;
}
function calculateStringLengthForWrite(text) {
var length = text.length;
// limit to 65535 because the 'length' field is uint16
return length > 65535 ? 65535 : length;
}
function getStringOffset(target, strings) {
var l = strings.length;
for (var i = 0; i < l; ++i) {
var s = strings[i];
if (s.text === target) {
return s.offset;
}
}
throw new Error('Unexpected');
}
/** (returns offset just after the written text) */
function writeString(view, offset, text) {
var length = calculateStringLengthForWrite(text);
view.setUint16(offset, length, true);
offset += 2;
for (var i = 0; i < length; ++i) {
view.setUint16(offset, text.charCodeAt(i), true);
offset += 2;
}
return offset;
}
function writeLanguageTable(view, offset, strings, data) {
// characteristics
view.setUint32(offset, 0, true);
// timestamp
view.setUint32(offset + 4, 0, true);
// major version / minor version
view.setUint32(offset + 8, 0, true);
// name entries
view.setUint16(offset + 12, data.s.length, true);
// id entries
view.setUint16(offset + 14, data.n.length, true);
offset += 16;
// name entries (not in specification)
data.s.forEach(function (e) {
var strOff = getStringOffset(e.lang, strings);
view.setUint32(offset, strOff, true);
view.setUint32(offset + 4, e.offset, true);
offset += 8;
});
// id entries
data.n.forEach(function (e) {
view.setUint32(offset, e.lang, true);
view.setUint32(offset + 4, e.offset, true);
offset += 8;
});
return offset;
}
function writeNameTable(view, offset, leafOffset, strings, data) {
// characteristics
view.setUint32(offset, 0, true);
// timestamp
view.setUint32(offset + 4, 0, true);
// major version / minor version
view.setUint32(offset + 8, 0, true);
// name entries
view.setUint16(offset + 12, data.s.length, true);
// id entries
view.setUint16(offset + 14, data.n.length, true);
offset += 16;
data.s.forEach(function (e) {
e.offset = leafOffset;
leafOffset = writeLanguageTable(view, leafOffset, strings, e);
});
data.n.forEach(function (e) {
e.offset = leafOffset;
leafOffset = writeLanguageTable(view, leafOffset, strings, e);
});
data.s.forEach(function (e) {
var strOff = getStringOffset(e.id, strings);
view.setUint32(offset, strOff + 0x80000000, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
});
data.n.forEach(function (e) {
view.setUint32(offset, e.id, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
});
return leafOffset;
}
function writeTypeTable(view, offset, strings, data) {
// characteristics
view.setUint32(offset, 0, true);
// timestamp
view.setUint32(offset + 4, 0, true);
// major version / minor version
view.setUint32(offset + 8, 0, true);
// name entries
view.setUint16(offset + 12, data.s.length, true);
// id entries
view.setUint16(offset + 14, data.n.length, true);
offset += 16;
var nextTableOffset = offset + 8 * (data.s.length + data.n.length);
data.s.forEach(function (e) {
e.offset = nextTableOffset;
nextTableOffset += 16 + 8 * (e.s.length + e.n.length);
});
data.n.forEach(function (e) {
e.offset = nextTableOffset;
nextTableOffset += 16 + 8 * (e.s.length + e.n.length);
});
data.s.forEach(function (e) {
var strOff = getStringOffset(e.type, strings);
view.setUint32(offset, strOff + 0x80000000, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
nextTableOffset = writeNameTable(view, e.offset, nextTableOffset, strings, e);
});
data.n.forEach(function (e) {
view.setUint32(offset, e.type, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
nextTableOffset = writeNameTable(view, e.offset, nextTableOffset, strings, e);
});
return nextTableOffset;
}
////////////////////////////////////////////////////////////////////////////////
/** Manages resource data for NtExecutable */
var NtExecutableResource = /** @class */ (function () {
function NtExecutableResource() {
/** The timestamp for resource */
this.dateTime = 0;
/** The major version data for resource */
this.majorVersion = 0;
/** The minor version data for resource */
this.minorVersion = 0;
/** Resource entries */
this.entries = [];
/**
* The section data header of resource data (used by outputResource method).
* This instance will be null if the base executable does not contain resource data.
* You can override this field before calling outputResource method.
* (Note that the addresses and sizes are ignored for output)
*/
this.sectionDataHeader = null;
this.originalSize = 0;
}
NtExecutableResource.prototype.parse = function (section, ignoreUnparsableData) {
if (!section.data) {
return;
}
var view = new DataView(section.data);
// --- First: Resource Directory Table ---
// (off: 0 -- Characteristics (uint32))
this.dateTime = view.getUint32(4, true);
this.majorVersion = view.getUint16(8, true);
this.minorVersion = view.getUint16(10, true);
var nameCount = view.getUint16(12, true);
var idCount = view.getUint16(14, true);
var off = 16;
var res = [];
var cb = function (t, n, l) {
var off = view.getUint32(l.dataOffset, true) -
section.info.virtualAddress;
var size = view.getUint32(l.dataOffset + 4, true);
var cp = view.getUint32(l.dataOffset + 8, true);
if (off >= 0) {
var bin = new Uint8Array(size);
bin.set(new Uint8Array(section.data, off, size));
res.push({
type: t.type,
id: n.name,
lang: l.lang,
codepage: cp,
bin: bin.buffer,
});
}
else {
if (!ignoreUnparsableData) {
throw new Error('Cannot parse resource directory entry; RVA seems to be invalid.');
}
res.push({
type: t.type,
id: n.name,
lang: l.lang,
codepage: cp,
bin: new ArrayBuffer(0),
rva: l.dataOffset,
});
}
};
for (var i = 0; i < nameCount; ++i) {
var nameOffset = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
var name_3 = readString(view, nameOffset);
readNameTable(view, name_3, nextTable, cb);
off += 8;
}
for (var i = 0; i < idCount; ++i) {
var typeId = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
readNameTable(view, typeId, nextTable, cb);
off += 8;
}
this.entries = res;
this.originalSize = section.data.byteLength;
};
/**
* Parses resource data for `NtExecutable`.
* This function returns valid instance even if
* the executable does not have resource data.
* @param exe `NtExecutable` instance
* @param ignoreUnparsableData (default: false) specify true if skipping 'unparsable' (e.g. unusual format) data.
* When true, the resource data may break on write operation.
*/
NtExecutableResource.from = function (exe, ignoreUnparsableData) {
if (ignoreUnparsableData === void 0) { ignoreUnparsableData = false; }
var secs = []
.concat(exe.getAllSections())
.sort(function (a, b) { return a.info.virtualAddress - b.info.virtualAddress; });
var entry = exe.getSectionByEntry(ImageDirectoryEntry_js_1.default.Resource);
// check if the section order is supported
// (not supported if any other sections except 'relocation' is available,
// because the recalculation of virtual address is not simple)
if (entry) {
var reloc = exe.getSectionByEntry(ImageDirectoryEntry_js_1.default.BaseRelocation);
for (var i = 0; i < secs.length; ++i) {
var s = secs[i];
if (s === entry) {
for (var j = i + 1; j < secs.length; ++j) {
if (!reloc || secs[j] !== reloc) {
throw new Error('After Resource section, sections except for relocation are not supported');
}
}
break;
}
}
}
var r = new NtExecutableResource();
r.sectionDataHeader = entry ? functions_js_1.cloneObject(entry.info) : null;
if (entry) {
r.parse(entry, ignoreUnparsableData);
}
return r;
};
/**
* Add or replace the resource entry.
* This method replaces the entry only if there is an entry with `type`, `id` and `lang` equal.
*/
NtExecutableResource.prototype.replaceResourceEntry = function (entry) {
for (var len = this.entries.length, i = 0; i < len; ++i) {
var e = this.entries[i];
if (e.type === entry.type &&
e.id === entry.id &&
e.lang === entry.lang) {
this.entries[i] = entry;
return;
}
}
this.entries.push(entry);
};
/**
* Returns all resource entries, which has specified type and id, as UTF-8 string data.
* @param type Resource type
* @param id Resource id
* @returns an array of lang and value pair (tuple)
*/
NtExecutableResource.prototype.getResourceEntriesAsString = function (type, id) {
return this.entries
.filter(function (entry) { return entry.type === type && entry.id === id; })
.map(function (entry) { return [entry.lang, functions_js_1.binaryToString(entry.bin)]; });
};
/**
* Add or replace the resource entry with UTF-8 string data.
* This method is a wrapper of {@link NtExecutableResource.replaceResourceEntry}.
*/
NtExecutableResource.prototype.replaceResourceEntryFromString = function (type, id, lang, value) {
var entry = {
type: type,
id: id,
lang: lang,
codepage: 1200,
bin: functions_js_1.stringToBinary(value),
};
this.replaceResourceEntry(entry);
};
/**
* Removes resource entries which has specified type and id.
*/
NtExecutableResource.prototype.removeResourceEntry = function (type, id, lang) {
this.entries = this.entries.filter(function (entry) {
return !(entry.type === type &&
entry.id === id &&
(typeof lang === 'undefined' || entry.lang === lang));
});
};
/**
* Generates resource data binary for NtExecutable (not for .res file)
* @param virtualAddress The virtual address for the section
* @param alignment File alignment value of executable
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
NtExecutableResource.prototype.generateResourceData = function (virtualAddress, alignment, noGrow, allowShrink) {
if (noGrow === void 0) { noGrow = false; }
if (allowShrink === void 0) { allowShrink = false; }
// estimate data size and divide to output table
var r = {
s: [],
n: [],
};
var strings = [];
var size = divideEntriesImplByType(r, strings, this.entries);
strings = removeDuplicates(strings);
var stringsOffset = size;
size += strings.reduce(function (prev, cur) {
return prev + 2 + calculateStringLengthForWrite(cur) * 2;
}, 0);
size = functions_js_1.roundUp(size, 8);
var descOffset = size;
size = this.entries.reduce(function (p, e) {
e.offset = p;
return p + 16;
}, descOffset);
var dataOffset = size;
size = this.entries.reduce(function (p, e) {
return functions_js_1.roundUp(p, 8) + e.bin.byteLength;
}, dataOffset);
var alignedSize = functions_js_1.roundUp(size, alignment);
var originalAlignedSize = functions_js_1.roundUp(this.originalSize, alignment);
if (noGrow) {
if (alignedSize > originalAlignedSize) {
throw new Error('New resource data is larger than original');
}
}
if (!allowShrink) {
if (alignedSize < originalAlignedSize) {
alignedSize = originalAlignedSize;
}
}
// generate binary
var bin = new ArrayBuffer(alignedSize);
var view = new DataView(bin);
var o = descOffset;
var va = virtualAddress + dataOffset;
this.entries.forEach(function (e) {
var len = e.bin.byteLength;
if (typeof e.rva !== 'undefined') {
// RVA
view.setUint32(o, e.rva, true);
}
else {
va = functions_js_1.roundUp(va, 8);
// RVA
view.setUint32(o, va, true);
va += len;
}
// size
view.setUint32(o + 4, len, true);
// codepage
view.setUint32(o + 8, e.codepage, true);
// (zero)
view.setUint32(o + 12, 0, true);
o += 16;
});
o = dataOffset;
this.entries.forEach(function (e) {
var len = e.bin.byteLength;
functions_js_1.copyBuffer(bin, o, e.bin, 0, len);
o += functions_js_1.roundUp(len, 8);
});
var stringsData = [];
o = stringsOffset;
strings.forEach(function (s) {
stringsData.push({
offset: o,
text: s,
});
o = writeString(view, o, s);
});
writeTypeTable(view, 0, stringsData, r);
// fill with 'PADDINGX'
if (alignedSize > size) {
var pad = 'PADDINGX';
for (var i = size, j = 0; i < alignedSize; ++i, ++j) {
if (j === 8) {
j = 0;
}
view.setUint8(i, pad.charCodeAt(j));
}
}
return {
bin: bin,
rawSize: size,
dataOffset: dataOffset,
descEntryOffset: descOffset,
descEntryCount: this.entries.length,
};
};
/**
* Writes holding resource data to specified NtExecutable instance.
* @param exeDest An NtExecutable instance to write resource section to
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
NtExecutableResource.prototype.outputResource = function (exeDest, noGrow, allowShrink) {
if (noGrow === void 0) { noGrow = false; }
if (allowShrink === void 0) { allowShrink = false; }
// make section data
var fileAlign = exeDest.getFileAlignment();
var sectionData;
if (this.sectionDataHeader) {
sectionData = {
data: null,
info: functions_js_1.cloneObject(this.sectionDataHeader),
};
}
else {
sectionData = {
data: null,
info: {
name: '.rsrc',
virtualSize: 0,
virtualAddress: 0,
sizeOfRawData: 0,
pointerToRawData: 0,
pointerToRelocations: 0,
pointerToLineNumbers: 0,
numberOfRelocations: 0,
numberOfLineNumbers: 0,
characteristics: 0x40000040, // read access and initialized data
},
};
}
// first, set virtualAddress to 0 because
// the virtual address is not determined now
var data = this.generateResourceData(0, fileAlign, noGrow, allowShrink);
sectionData.data = data.bin;
sectionData.info.sizeOfRawData = data.bin.byteLength;
sectionData.info.virtualSize = data.rawSize;
// write as section
exeDest.setSectionByEntry(ImageDirectoryEntry_js_1.default.Resource, sectionData);
// rewrite section raw-data
var generatedSection = exeDest.getSectionByEntry(ImageDirectoryEntry_js_1.default.Resource);
var view = new DataView(generatedSection.data);
// set RVA
var o = data.descEntryOffset;
var va = generatedSection.info.virtualAddress + data.dataOffset;
for (var i = 0; i < data.descEntryCount; ++i) {
var len = view.getUint32(o + 4, true);
va = functions_js_1.roundUp(va, 8);
// RVA
view.setUint32(o, va, true);
va += len;
o += 16;
}
};
return NtExecutableResource;
}());
exports.default = NtExecutableResource;

View File

@@ -0,0 +1,90 @@
import ImageDirectoryEntry from './format/ImageDirectoryEntry.js';
import ImageDosHeader from './format/ImageDosHeader.js';
import ImageNtHeaders from './format/ImageNtHeaders.js';
import { ImageSectionHeader } from './format/ImageSectionHeaderArray.js';
export interface NtExecutableFromOptions {
/** true to parse binary even if the binary contains Certificate data (i.e. 'signed') */
ignoreCert?: boolean;
}
export interface NtExecutableSection {
info: ImageSectionHeader;
data: ArrayBuffer | null;
}
export default class NtExecutable {
private readonly _headers;
private readonly _sections;
private _ex;
private readonly _dh;
private readonly _nh;
private readonly _dda;
private constructor();
/**
* Creates an NtExecutable instance with an 'empty' executable binary.
* @param is32Bit set true if the binary is for 32-bit (default: false)
* @param isDLL set true if the binary is DLL (default: true)
* @return NtExecutable instance
*/
static createEmpty(is32Bit?: boolean, isDLL?: boolean): NtExecutable;
/**
* Parse the binary and create NtExecutable instance.
* An error will be thrown if the binary data is invalid
* @param bin binary data
* @param options additional option for parsing
* @return NtExecutable instance
*/
static from(bin: ArrayBuffer | ArrayBufferView, options?: NtExecutableFromOptions): NtExecutable;
/**
* Returns whether the executable is for 32-bit architecture
*/
is32bit(): boolean;
getTotalHeaderSize(): number;
get dosHeader(): ImageDosHeader;
get newHeader(): ImageNtHeaders;
getRawHeader(): ArrayBuffer;
getImageBase(): number;
getFileAlignment(): number;
getSectionAlignment(): number;
/**
* Return all sections. The returned array is sorted by raw address.
*/
getAllSections(): readonly NtExecutableSection[];
/**
* Return the section data from ImageDirectoryEntry enum value.
* @note
* The returned instance is equal to the value in {@link getAllSections}'s return value.
*/
getSectionByEntry(entry: ImageDirectoryEntry): Readonly<NtExecutableSection> | null;
/**
* Set the section data from ImageDirectoryEntry enum value.
* If entry is found, then replaces the secion data. If not found, then adds the section data.
*
* NOTE: 'virtualAddress' and 'pointerToRawData' of section object is ignored
* and calculated automatically. 'virtualSize' and 'sizeOfRawData' are used, but
* if the 'section.data.byteLength' is larger than 'sizeOfRawData', then
* these members are replaced.
*
* @param entry ImageDirectoryEntry enum value for the section
* @param section the section data, or null to remove the section
*/
setSectionByEntry(entry: ImageDirectoryEntry, section: Readonly<NtExecutableSection> | null): void;
/**
* Returns the extra data in the executable, or `null` if nothing.
* You can rewrite the returned buffer without using `setExtraData` if
* the size of the new data is equal to the old data.
*/
getExtraData(): ArrayBuffer | null;
/**
* Specifies the new extra data in the executable.
* The specified buffer will be cloned and you can release it after calling this method.
* @param bin buffer containing the new data
* @note
* The extra data will not be aligned by `NtExecutable`.
*/
setExtraData(bin: ArrayBuffer | ArrayBufferView | null): void;
/**
* Generates the executable binary data.
*/
generate(paddingSize?: number): ArrayBuffer;
private rearrangeSections;
private replaceSectionImpl;
}

View File

@@ -0,0 +1,418 @@
import ImageDataDirectoryArray from './format/ImageDataDirectoryArray.js';
import ImageDirectoryEntry from './format/ImageDirectoryEntry.js';
import ImageDosHeader from './format/ImageDosHeader.js';
import ImageNtHeaders from './format/ImageNtHeaders.js';
import ImageSectionHeaderArray from './format/ImageSectionHeaderArray.js';
import { allocatePartialBinary, calculateCheckSumForPE, cloneObject, cloneToArrayBuffer, roundUp, } from './util/functions.js';
import { makeEmptyNtExecutableBinary } from './util/generate.js';
var NtExecutable = /** @class */ (function () {
function NtExecutable(_headers, _sections, _ex) {
this._headers = _headers;
this._sections = _sections;
this._ex = _ex;
var dh = ImageDosHeader.from(_headers);
var nh = ImageNtHeaders.from(_headers, dh.newHeaderAddress);
this._dh = dh;
this._nh = nh;
this._dda = nh.optionalHeaderDataDirectory;
_sections.sort(function (a, b) {
var ra = a.info.pointerToRawData;
var rb = a.info.pointerToRawData;
if (ra !== rb) {
return ra - rb;
}
var va = a.info.virtualAddress;
var vb = b.info.virtualAddress;
if (va === vb) {
return a.info.virtualSize - b.info.virtualSize;
}
return va - vb;
});
}
/**
* Creates an NtExecutable instance with an 'empty' executable binary.
* @param is32Bit set true if the binary is for 32-bit (default: false)
* @param isDLL set true if the binary is DLL (default: true)
* @return NtExecutable instance
*/
NtExecutable.createEmpty = function (is32Bit, isDLL) {
if (is32Bit === void 0) { is32Bit = false; }
if (isDLL === void 0) { isDLL = true; }
return this.from(makeEmptyNtExecutableBinary(is32Bit, isDLL));
};
/**
* Parse the binary and create NtExecutable instance.
* An error will be thrown if the binary data is invalid
* @param bin binary data
* @param options additional option for parsing
* @return NtExecutable instance
*/
NtExecutable.from = function (bin, options) {
var dh = ImageDosHeader.from(bin);
var nh = ImageNtHeaders.from(bin, dh.newHeaderAddress);
if (!dh.isValid() || !nh.isValid()) {
throw new TypeError('Invalid binary format');
}
if (nh.fileHeader.numberOfSymbols > 0) {
throw new Error('Binary with symbols is not supported now');
}
var fileAlignment = nh.optionalHeader.fileAlignment;
var securityEntry = nh.optionalHeaderDataDirectory.get(ImageDirectoryEntry.Certificate);
if (securityEntry.size > 0) {
// Signed executables should be parsed only when `ignoreCert` is true
if (!(options === null || options === void 0 ? void 0 : options.ignoreCert)) {
throw new Error('Parsing signed executable binary is not allowed by default.');
}
}
var secOff = dh.newHeaderAddress + nh.getSectionHeaderOffset();
var secCount = nh.fileHeader.numberOfSections;
var sections = [];
var tempSectionHeaderBinary = allocatePartialBinary(bin, secOff, secCount * ImageSectionHeaderArray.itemSize);
var secArray = ImageSectionHeaderArray.from(tempSectionHeaderBinary, secCount, 0);
var lastOffset = roundUp(secOff + secCount * ImageSectionHeaderArray.itemSize, fileAlignment);
// console.log(`from data size 0x${bin.byteLength.toString(16)}:`);
secArray.forEach(function (info) {
if (!info.pointerToRawData || !info.sizeOfRawData) {
info.pointerToRawData = 0;
info.sizeOfRawData = 0;
sections.push({
info: info,
data: null,
});
}
else {
// console.log(` section ${info.name}: 0x${info.pointerToRawData.toString(16)}, size = 0x${info.sizeOfRawData.toString(16)}`);
var secBin = allocatePartialBinary(bin, info.pointerToRawData, info.sizeOfRawData);
sections.push({
info: info,
data: secBin,
});
var secEndOffset = roundUp(info.pointerToRawData + info.sizeOfRawData, fileAlignment);
if (secEndOffset > lastOffset) {
lastOffset = secEndOffset;
}
}
});
// the size of DOS and NT headers is equal to section offset
var headers = allocatePartialBinary(bin, 0, secOff);
// extra data
var exData = null;
var lastExDataOffset = bin.byteLength;
// It may contain that both extra data and certificate data are available.
// In this case the extra data is followed by the certificate data.
if (securityEntry.size > 0) {
lastExDataOffset = securityEntry.virtualAddress;
}
if (lastOffset < lastExDataOffset) {
exData = allocatePartialBinary(bin, lastOffset, lastExDataOffset - lastOffset);
}
return new NtExecutable(headers, sections, exData);
};
/**
* Returns whether the executable is for 32-bit architecture
*/
NtExecutable.prototype.is32bit = function () {
return this._nh.is32bit();
};
NtExecutable.prototype.getTotalHeaderSize = function () {
return this._headers.byteLength;
};
Object.defineProperty(NtExecutable.prototype, "dosHeader", {
get: function () {
return this._dh;
},
enumerable: false,
configurable: true
});
Object.defineProperty(NtExecutable.prototype, "newHeader", {
get: function () {
return this._nh;
},
enumerable: false,
configurable: true
});
NtExecutable.prototype.getRawHeader = function () {
return this._headers;
};
NtExecutable.prototype.getImageBase = function () {
return this._nh.optionalHeader.imageBase;
};
NtExecutable.prototype.getFileAlignment = function () {
return this._nh.optionalHeader.fileAlignment;
};
NtExecutable.prototype.getSectionAlignment = function () {
return this._nh.optionalHeader.sectionAlignment;
};
/**
* Return all sections. The returned array is sorted by raw address.
*/
NtExecutable.prototype.getAllSections = function () {
return this._sections;
};
/**
* Return the section data from ImageDirectoryEntry enum value.
* @note
* The returned instance is equal to the value in {@link getAllSections}'s return value.
*/
NtExecutable.prototype.getSectionByEntry = function (entry) {
var dd = this._dda.get(entry);
var r = this._sections
.filter(function (sec) {
var vaEnd = sec.info.virtualAddress + sec.info.virtualSize;
return (dd.virtualAddress >= sec.info.virtualAddress &&
dd.virtualAddress < vaEnd);
})
.shift();
return r !== undefined ? r : null;
};
/**
* Set the section data from ImageDirectoryEntry enum value.
* If entry is found, then replaces the secion data. If not found, then adds the section data.
*
* NOTE: 'virtualAddress' and 'pointerToRawData' of section object is ignored
* and calculated automatically. 'virtualSize' and 'sizeOfRawData' are used, but
* if the 'section.data.byteLength' is larger than 'sizeOfRawData', then
* these members are replaced.
*
* @param entry ImageDirectoryEntry enum value for the section
* @param section the section data, or null to remove the section
*/
NtExecutable.prototype.setSectionByEntry = function (entry, section) {
var sec = section
? { data: section.data, info: section.info }
: null;
var dd = this._dda.get(entry);
var hasEntry = dd.size > 0;
if (!sec) {
if (!hasEntry) {
// no need to replace
}
else {
// clear entry
this._dda.set(entry, { size: 0, virtualAddress: 0 });
var len = this._sections.length;
for (var i = 0; i < len; ++i) {
var sec_1 = this._sections[i];
var vaStart = sec_1.info.virtualAddress;
var vaLast = vaStart + sec_1.info.virtualSize;
if (dd.virtualAddress >= vaStart &&
dd.virtualAddress < vaLast) {
this._sections.splice(i, 1);
// section count changed
this._nh.fileHeader.numberOfSections =
this._sections.length;
break;
}
}
}
}
else {
var rawSize = !sec.data ? 0 : sec.data.byteLength;
var fileAlign = this._nh.optionalHeader.fileAlignment;
var secAlign = this._nh.optionalHeader.sectionAlignment;
var alignedFileSize = !sec.data ? 0 : roundUp(rawSize, fileAlign);
var alignedSecSize = !sec.data
? 0
: roundUp(sec.info.virtualSize, secAlign);
if (sec.info.sizeOfRawData < alignedFileSize) {
sec.info.sizeOfRawData = alignedFileSize;
}
else {
alignedFileSize = sec.info.sizeOfRawData;
}
if (!hasEntry) {
var virtAddr_1 = 0;
var rawAddr_1 = roundUp(this._headers.byteLength, fileAlign);
// get largest addresses
this._sections.forEach(function (secExist) {
if (secExist.info.pointerToRawData) {
if (rawAddr_1 <= secExist.info.pointerToRawData) {
rawAddr_1 =
secExist.info.pointerToRawData +
secExist.info.sizeOfRawData;
}
}
if (virtAddr_1 <= secExist.info.virtualAddress) {
virtAddr_1 =
secExist.info.virtualAddress +
secExist.info.virtualSize;
}
});
if (!alignedFileSize) {
rawAddr_1 = 0;
}
if (!virtAddr_1) {
virtAddr_1 = this.newHeader.optionalHeader.baseOfCode;
}
virtAddr_1 = roundUp(virtAddr_1, secAlign);
sec.info.pointerToRawData = rawAddr_1;
sec.info.virtualAddress = virtAddr_1;
// add entry
this._dda.set(entry, {
size: rawSize,
virtualAddress: virtAddr_1,
});
this._sections.push(sec);
// section count changed
this._nh.fileHeader.numberOfSections = this._sections.length;
// change image size
this._nh.optionalHeader.sizeOfImage = roundUp(virtAddr_1 + alignedSecSize, this._nh.optionalHeader.sectionAlignment);
}
else {
// replace entry
this.replaceSectionImpl(dd.virtualAddress, sec.info, sec.data);
}
}
};
/**
* Returns the extra data in the executable, or `null` if nothing.
* You can rewrite the returned buffer without using `setExtraData` if
* the size of the new data is equal to the old data.
*/
NtExecutable.prototype.getExtraData = function () {
return this._ex;
};
/**
* Specifies the new extra data in the executable.
* The specified buffer will be cloned and you can release it after calling this method.
* @param bin buffer containing the new data
* @note
* The extra data will not be aligned by `NtExecutable`.
*/
NtExecutable.prototype.setExtraData = function (bin) {
if (bin === null) {
this._ex = null;
}
else {
this._ex = cloneToArrayBuffer(bin);
}
};
/**
* Generates the executable binary data.
*/
NtExecutable.prototype.generate = function (paddingSize) {
// calculate binary size
var dh = this._dh;
var nh = this._nh;
var secOff = dh.newHeaderAddress + nh.getSectionHeaderOffset();
var size = secOff;
size += this._sections.length * ImageSectionHeaderArray.itemSize;
var align = nh.optionalHeader.fileAlignment;
size = roundUp(size, align);
this._sections.forEach(function (sec) {
if (!sec.info.pointerToRawData) {
return;
}
var lastOff = sec.info.pointerToRawData + sec.info.sizeOfRawData;
if (size < lastOff) {
size = lastOff;
size = roundUp(size, align);
}
});
var lastPosition = size;
if (this._ex !== null) {
size += this._ex.byteLength;
}
if (typeof paddingSize === 'number') {
size += paddingSize;
}
// make buffer
var bin = new ArrayBuffer(size);
var u8bin = new Uint8Array(bin);
u8bin.set(new Uint8Array(this._headers, 0, secOff));
// reset Security section offset (eliminate it)
ImageDataDirectoryArray.from(bin, dh.newHeaderAddress + nh.getDataDirectoryOffset()).set(ImageDirectoryEntry.Certificate, {
size: 0,
virtualAddress: 0,
});
var secArray = ImageSectionHeaderArray.from(bin, this._sections.length, secOff);
this._sections.forEach(function (sec, i) {
if (!sec.data) {
sec.info.pointerToRawData = 0;
sec.info.sizeOfRawData = 0;
}
secArray.set(i, sec.info);
if (!sec.data || !sec.info.pointerToRawData) {
return;
}
u8bin.set(new Uint8Array(sec.data), sec.info.pointerToRawData);
});
if (this._ex !== null) {
u8bin.set(new Uint8Array(this._ex), lastPosition);
}
// re-calc checksum
if (nh.optionalHeader.checkSum !== 0) {
calculateCheckSumForPE(bin, true);
}
return bin;
};
NtExecutable.prototype.rearrangeSections = function (rawAddressStart, rawDiff, virtualAddressStart, virtualDiff) {
if (!rawDiff && !virtualDiff) {
return;
}
var nh = this._nh;
var secAlign = nh.optionalHeader.sectionAlignment;
var dirs = this._dda;
var len = this._sections.length;
var lastVirtAddress = 0;
for (var i = 0; i < len; ++i) {
var sec = this._sections[i];
var virtAddr = sec.info.virtualAddress;
if (virtualDiff && virtAddr >= virtualAddressStart) {
var iDir = dirs.findIndexByVirtualAddress(virtAddr);
virtAddr += virtualDiff;
if (iDir !== null) {
dirs.set(iDir, {
virtualAddress: virtAddr,
size: sec.info.virtualSize,
});
}
sec.info.virtualAddress = virtAddr;
}
var fileAddr = sec.info.pointerToRawData;
if (rawDiff && fileAddr >= rawAddressStart) {
sec.info.pointerToRawData = fileAddr + rawDiff;
}
lastVirtAddress = roundUp(sec.info.virtualAddress + sec.info.virtualSize, secAlign);
}
// fix image size from last virtual address
nh.optionalHeader.sizeOfImage = lastVirtAddress;
};
// NOTE: info.virtualSize must be valid
NtExecutable.prototype.replaceSectionImpl = function (virtualAddress, info, data) {
var len = this._sections.length;
for (var i = 0; i < len; ++i) {
var s = this._sections[i];
// console.log(`replaceSectionImpl: ${virtualAddress} <--> ${s.info.virtualAddress}`);
if (s.info.virtualAddress === virtualAddress) {
// console.log(` found`);
var secAlign = this._nh.optionalHeader.sectionAlignment;
var fileAddr = s.info.pointerToRawData;
var oldFileAddr = fileAddr + s.info.sizeOfRawData;
var oldVirtAddr = virtualAddress + roundUp(s.info.virtualSize, secAlign);
s.info = cloneObject(info);
s.info.virtualAddress = virtualAddress;
s.info.pointerToRawData = fileAddr;
s.data = data;
// shift addresses
var newFileAddr = fileAddr + info.sizeOfRawData;
var newVirtAddr = virtualAddress + roundUp(info.virtualSize, secAlign);
this.rearrangeSections(oldFileAddr, newFileAddr - oldFileAddr, oldVirtAddr, newVirtAddr - oldVirtAddr);
// BLOCK: rewrite DataDirectory entry for specified virtualAddress
{
var dirs = this._dda;
var iDir = dirs.findIndexByVirtualAddress(virtualAddress);
if (iDir !== null) {
dirs.set(iDir, {
virtualAddress: virtualAddress,
size: info.virtualSize,
});
}
}
break;
}
}
};
return NtExecutable;
}());
export default NtExecutable;

View File

@@ -0,0 +1,75 @@
import NtExecutable from './NtExecutable.js';
import { ImageSectionHeader } from './format/ImageSectionHeaderArray.js';
import ResourceEntry from './type/ResourceEntry.js';
/** Manages resource data for NtExecutable */
export default class NtExecutableResource {
/** The timestamp for resource */
dateTime: number;
/** The major version data for resource */
majorVersion: number;
/** The minor version data for resource */
minorVersion: number;
/** Resource entries */
entries: ResourceEntry[];
/**
* The section data header of resource data (used by outputResource method).
* This instance will be null if the base executable does not contain resource data.
* You can override this field before calling outputResource method.
* (Note that the addresses and sizes are ignored for output)
*/
sectionDataHeader: ImageSectionHeader | null;
private originalSize;
private constructor();
private parse;
/**
* Parses resource data for `NtExecutable`.
* This function returns valid instance even if
* the executable does not have resource data.
* @param exe `NtExecutable` instance
* @param ignoreUnparsableData (default: false) specify true if skipping 'unparsable' (e.g. unusual format) data.
* When true, the resource data may break on write operation.
*/
static from(exe: NtExecutable, ignoreUnparsableData?: boolean): NtExecutableResource;
/**
* Add or replace the resource entry.
* This method replaces the entry only if there is an entry with `type`, `id` and `lang` equal.
*/
replaceResourceEntry(entry: ResourceEntry): void;
/**
* Returns all resource entries, which has specified type and id, as UTF-8 string data.
* @param type Resource type
* @param id Resource id
* @returns an array of lang and value pair (tuple)
*/
getResourceEntriesAsString(type: string | number, id: string | number): Array<[lang: string | number, value: string]>;
/**
* Add or replace the resource entry with UTF-8 string data.
* This method is a wrapper of {@link NtExecutableResource.replaceResourceEntry}.
*/
replaceResourceEntryFromString(type: string | number, id: string | number, lang: string | number, value: string): void;
/**
* Removes resource entries which has specified type and id.
*/
removeResourceEntry(type: string | number, id: string | number, lang?: string | number): void;
/**
* Generates resource data binary for NtExecutable (not for .res file)
* @param virtualAddress The virtual address for the section
* @param alignment File alignment value of executable
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
generateResourceData(virtualAddress: number, alignment: number, noGrow?: boolean, allowShrink?: boolean): {
bin: ArrayBuffer;
rawSize: number;
dataOffset: number;
descEntryOffset: number;
descEntryCount: number;
};
/**
* Writes holding resource data to specified NtExecutable instance.
* @param exeDest An NtExecutable instance to write resource section to
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
outputResource(exeDest: NtExecutable, noGrow?: boolean, allowShrink?: boolean): void;
}

View File

@@ -0,0 +1,662 @@
import ImageDirectoryEntry from './format/ImageDirectoryEntry.js';
import { binaryToString, cloneObject, copyBuffer, roundUp, stringToBinary, } from './util/functions.js';
function removeDuplicates(a) {
return a.reduce(function (p, c) {
return p.indexOf(c) >= 0 ? p : p.concat(c);
}, []);
}
function readString(view, offset) {
var length = view.getUint16(offset, true);
var r = '';
offset += 2;
for (var i = 0; i < length; ++i) {
r += String.fromCharCode(view.getUint16(offset, true));
offset += 2;
}
return r;
}
function readLanguageTable(view, typeEntry, name, languageTable, cb) {
var off = languageTable;
var nameEntry = {
name: name,
languageTable: languageTable,
characteristics: view.getUint32(off, true),
dateTime: view.getUint32(off + 4, true),
majorVersion: view.getUint16(off + 8, true),
minorVersion: view.getUint16(off + 10, true),
};
var nameCount = view.getUint16(off + 12, true);
var idCount = view.getUint16(off + 14, true);
off += 16;
for (var i = 0; i < nameCount; ++i) {
var nameOffset = view.getUint32(off, true) & 0x7fffffff;
var dataOffset = view.getUint32(off + 4, true);
// ignore if the offset refers to the next table
if ((dataOffset & 0x80000000) !== 0) {
off += 8;
continue;
}
var name_1 = readString(view, nameOffset);
cb(typeEntry, nameEntry, { lang: name_1, dataOffset: dataOffset });
off += 8;
}
for (var i = 0; i < idCount; ++i) {
var id = view.getUint32(off, true) & 0x7fffffff;
var dataOffset = view.getUint32(off + 4, true);
// ignore if the offset refers to the next table
if ((dataOffset & 0x80000000) !== 0) {
off += 8;
continue;
}
cb(typeEntry, nameEntry, { lang: id, dataOffset: dataOffset });
off += 8;
}
}
function readNameTable(view, type, nameTable, cb) {
var off = nameTable;
var typeEntry = {
type: type,
nameTable: nameTable,
characteristics: view.getUint32(off, true),
dateTime: view.getUint32(off + 4, true),
majorVersion: view.getUint16(off + 8, true),
minorVersion: view.getUint16(off + 10, true),
};
var nameCount = view.getUint16(off + 12, true);
var idCount = view.getUint16(off + 14, true);
off += 16;
for (var i = 0; i < nameCount; ++i) {
var nameOffset = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
var name_2 = readString(view, nameOffset);
readLanguageTable(view, typeEntry, name_2, nextTable, cb);
off += 8;
}
for (var i = 0; i < idCount; ++i) {
var id = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
readLanguageTable(view, typeEntry, id, nextTable, cb);
off += 8;
}
}
function divideEntriesImplByID(r, names, entries) {
var entriesByString = {};
var entriesByNumber = {};
entries.forEach(function (e) {
if (typeof e.lang === 'string') {
entriesByString[e.lang] = e;
names.push(e.lang);
}
else {
entriesByNumber[e.lang] = e;
}
});
var strKeys = Object.keys(entriesByString);
strKeys.sort().forEach(function (type) {
r.s.push(entriesByString[type]);
});
var numKeys = Object.keys(entriesByNumber);
numKeys
.map(function (k) { return Number(k); })
.sort(function (a, b) { return a - b; })
.forEach(function (type) {
r.n.push(entriesByNumber[type]);
});
return 16 + 8 * (strKeys.length + numKeys.length);
}
function divideEntriesImplByName(r, names, entries) {
var entriesByString = {};
var entriesByNumber = {};
entries.forEach(function (e) {
var _a, _b;
if (typeof e.id === 'string') {
var a = (_a = entriesByString[e.id]) !== null && _a !== void 0 ? _a : (entriesByString[e.id] = []);
names.push(e.id);
a.push(e);
}
else {
var a = (_b = entriesByNumber[e.id]) !== null && _b !== void 0 ? _b : (entriesByNumber[e.id] = []);
a.push(e);
}
});
var sSum = Object.keys(entriesByString)
.sort()
.map(function (id) {
var o = {
id: id,
s: [],
n: [],
};
r.s.push(o);
return divideEntriesImplByID(o, names, entriesByString[id]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
var nSum = Object.keys(entriesByNumber)
.map(function (k) { return Number(k); })
.sort(function (a, b) { return a - b; })
.map(function (id) {
var o = {
id: id,
s: [],
n: [],
};
r.n.push(o);
return divideEntriesImplByID(o, names, entriesByNumber[id]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
return 16 + sSum + nSum;
}
function divideEntriesImplByType(r, names, entries) {
var entriesByString = {};
var entriesByNumber = {};
entries.forEach(function (e) {
var _a, _b;
if (typeof e.type === 'string') {
var a = (_a = entriesByString[e.type]) !== null && _a !== void 0 ? _a : (entriesByString[e.type] = []);
names.push(e.type);
a.push(e);
}
else {
var a = (_b = entriesByNumber[e.type]) !== null && _b !== void 0 ? _b : (entriesByNumber[e.type] = []);
a.push(e);
}
});
var sSum = Object.keys(entriesByString)
.sort()
.map(function (type) {
var o = { type: type, s: [], n: [] };
r.s.push(o);
return divideEntriesImplByName(o, names, entriesByString[type]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
var nSum = Object.keys(entriesByNumber)
.map(function (k) { return Number(k); })
.sort(function (a, b) { return a - b; })
.map(function (type) {
var o = { type: type, s: [], n: [] };
r.n.push(o);
return divideEntriesImplByName(o, names, entriesByNumber[type]);
})
.reduce(function (p, c) { return p + 8 + c; }, 0);
return 16 + sSum + nSum;
}
function calculateStringLengthForWrite(text) {
var length = text.length;
// limit to 65535 because the 'length' field is uint16
return length > 65535 ? 65535 : length;
}
function getStringOffset(target, strings) {
var l = strings.length;
for (var i = 0; i < l; ++i) {
var s = strings[i];
if (s.text === target) {
return s.offset;
}
}
throw new Error('Unexpected');
}
/** (returns offset just after the written text) */
function writeString(view, offset, text) {
var length = calculateStringLengthForWrite(text);
view.setUint16(offset, length, true);
offset += 2;
for (var i = 0; i < length; ++i) {
view.setUint16(offset, text.charCodeAt(i), true);
offset += 2;
}
return offset;
}
function writeLanguageTable(view, offset, strings, data) {
// characteristics
view.setUint32(offset, 0, true);
// timestamp
view.setUint32(offset + 4, 0, true);
// major version / minor version
view.setUint32(offset + 8, 0, true);
// name entries
view.setUint16(offset + 12, data.s.length, true);
// id entries
view.setUint16(offset + 14, data.n.length, true);
offset += 16;
// name entries (not in specification)
data.s.forEach(function (e) {
var strOff = getStringOffset(e.lang, strings);
view.setUint32(offset, strOff, true);
view.setUint32(offset + 4, e.offset, true);
offset += 8;
});
// id entries
data.n.forEach(function (e) {
view.setUint32(offset, e.lang, true);
view.setUint32(offset + 4, e.offset, true);
offset += 8;
});
return offset;
}
function writeNameTable(view, offset, leafOffset, strings, data) {
// characteristics
view.setUint32(offset, 0, true);
// timestamp
view.setUint32(offset + 4, 0, true);
// major version / minor version
view.setUint32(offset + 8, 0, true);
// name entries
view.setUint16(offset + 12, data.s.length, true);
// id entries
view.setUint16(offset + 14, data.n.length, true);
offset += 16;
data.s.forEach(function (e) {
e.offset = leafOffset;
leafOffset = writeLanguageTable(view, leafOffset, strings, e);
});
data.n.forEach(function (e) {
e.offset = leafOffset;
leafOffset = writeLanguageTable(view, leafOffset, strings, e);
});
data.s.forEach(function (e) {
var strOff = getStringOffset(e.id, strings);
view.setUint32(offset, strOff + 0x80000000, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
});
data.n.forEach(function (e) {
view.setUint32(offset, e.id, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
});
return leafOffset;
}
function writeTypeTable(view, offset, strings, data) {
// characteristics
view.setUint32(offset, 0, true);
// timestamp
view.setUint32(offset + 4, 0, true);
// major version / minor version
view.setUint32(offset + 8, 0, true);
// name entries
view.setUint16(offset + 12, data.s.length, true);
// id entries
view.setUint16(offset + 14, data.n.length, true);
offset += 16;
var nextTableOffset = offset + 8 * (data.s.length + data.n.length);
data.s.forEach(function (e) {
e.offset = nextTableOffset;
nextTableOffset += 16 + 8 * (e.s.length + e.n.length);
});
data.n.forEach(function (e) {
e.offset = nextTableOffset;
nextTableOffset += 16 + 8 * (e.s.length + e.n.length);
});
data.s.forEach(function (e) {
var strOff = getStringOffset(e.type, strings);
view.setUint32(offset, strOff + 0x80000000, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
nextTableOffset = writeNameTable(view, e.offset, nextTableOffset, strings, e);
});
data.n.forEach(function (e) {
view.setUint32(offset, e.type, true);
view.setUint32(offset + 4, e.offset + 0x80000000, true);
offset += 8;
nextTableOffset = writeNameTable(view, e.offset, nextTableOffset, strings, e);
});
return nextTableOffset;
}
////////////////////////////////////////////////////////////////////////////////
/** Manages resource data for NtExecutable */
var NtExecutableResource = /** @class */ (function () {
function NtExecutableResource() {
/** The timestamp for resource */
this.dateTime = 0;
/** The major version data for resource */
this.majorVersion = 0;
/** The minor version data for resource */
this.minorVersion = 0;
/** Resource entries */
this.entries = [];
/**
* The section data header of resource data (used by outputResource method).
* This instance will be null if the base executable does not contain resource data.
* You can override this field before calling outputResource method.
* (Note that the addresses and sizes are ignored for output)
*/
this.sectionDataHeader = null;
this.originalSize = 0;
}
NtExecutableResource.prototype.parse = function (section, ignoreUnparsableData) {
if (!section.data) {
return;
}
var view = new DataView(section.data);
// --- First: Resource Directory Table ---
// (off: 0 -- Characteristics (uint32))
this.dateTime = view.getUint32(4, true);
this.majorVersion = view.getUint16(8, true);
this.minorVersion = view.getUint16(10, true);
var nameCount = view.getUint16(12, true);
var idCount = view.getUint16(14, true);
var off = 16;
var res = [];
var cb = function (t, n, l) {
var off = view.getUint32(l.dataOffset, true) -
section.info.virtualAddress;
var size = view.getUint32(l.dataOffset + 4, true);
var cp = view.getUint32(l.dataOffset + 8, true);
if (off >= 0) {
var bin = new Uint8Array(size);
bin.set(new Uint8Array(section.data, off, size));
res.push({
type: t.type,
id: n.name,
lang: l.lang,
codepage: cp,
bin: bin.buffer,
});
}
else {
if (!ignoreUnparsableData) {
throw new Error('Cannot parse resource directory entry; RVA seems to be invalid.');
}
res.push({
type: t.type,
id: n.name,
lang: l.lang,
codepage: cp,
bin: new ArrayBuffer(0),
rva: l.dataOffset,
});
}
};
for (var i = 0; i < nameCount; ++i) {
var nameOffset = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
var name_3 = readString(view, nameOffset);
readNameTable(view, name_3, nextTable, cb);
off += 8;
}
for (var i = 0; i < idCount; ++i) {
var typeId = view.getUint32(off, true) & 0x7fffffff;
var nextTable = view.getUint32(off + 4, true);
// ignore if no next table is available
if (!(nextTable & 0x80000000)) {
off += 8;
continue;
}
nextTable &= 0x7fffffff;
readNameTable(view, typeId, nextTable, cb);
off += 8;
}
this.entries = res;
this.originalSize = section.data.byteLength;
};
/**
* Parses resource data for `NtExecutable`.
* This function returns valid instance even if
* the executable does not have resource data.
* @param exe `NtExecutable` instance
* @param ignoreUnparsableData (default: false) specify true if skipping 'unparsable' (e.g. unusual format) data.
* When true, the resource data may break on write operation.
*/
NtExecutableResource.from = function (exe, ignoreUnparsableData) {
if (ignoreUnparsableData === void 0) { ignoreUnparsableData = false; }
var secs = []
.concat(exe.getAllSections())
.sort(function (a, b) { return a.info.virtualAddress - b.info.virtualAddress; });
var entry = exe.getSectionByEntry(ImageDirectoryEntry.Resource);
// check if the section order is supported
// (not supported if any other sections except 'relocation' is available,
// because the recalculation of virtual address is not simple)
if (entry) {
var reloc = exe.getSectionByEntry(ImageDirectoryEntry.BaseRelocation);
for (var i = 0; i < secs.length; ++i) {
var s = secs[i];
if (s === entry) {
for (var j = i + 1; j < secs.length; ++j) {
if (!reloc || secs[j] !== reloc) {
throw new Error('After Resource section, sections except for relocation are not supported');
}
}
break;
}
}
}
var r = new NtExecutableResource();
r.sectionDataHeader = entry ? cloneObject(entry.info) : null;
if (entry) {
r.parse(entry, ignoreUnparsableData);
}
return r;
};
/**
* Add or replace the resource entry.
* This method replaces the entry only if there is an entry with `type`, `id` and `lang` equal.
*/
NtExecutableResource.prototype.replaceResourceEntry = function (entry) {
for (var len = this.entries.length, i = 0; i < len; ++i) {
var e = this.entries[i];
if (e.type === entry.type &&
e.id === entry.id &&
e.lang === entry.lang) {
this.entries[i] = entry;
return;
}
}
this.entries.push(entry);
};
/**
* Returns all resource entries, which has specified type and id, as UTF-8 string data.
* @param type Resource type
* @param id Resource id
* @returns an array of lang and value pair (tuple)
*/
NtExecutableResource.prototype.getResourceEntriesAsString = function (type, id) {
return this.entries
.filter(function (entry) { return entry.type === type && entry.id === id; })
.map(function (entry) { return [entry.lang, binaryToString(entry.bin)]; });
};
/**
* Add or replace the resource entry with UTF-8 string data.
* This method is a wrapper of {@link NtExecutableResource.replaceResourceEntry}.
*/
NtExecutableResource.prototype.replaceResourceEntryFromString = function (type, id, lang, value) {
var entry = {
type: type,
id: id,
lang: lang,
codepage: 1200,
bin: stringToBinary(value),
};
this.replaceResourceEntry(entry);
};
/**
* Removes resource entries which has specified type and id.
*/
NtExecutableResource.prototype.removeResourceEntry = function (type, id, lang) {
this.entries = this.entries.filter(function (entry) {
return !(entry.type === type &&
entry.id === id &&
(typeof lang === 'undefined' || entry.lang === lang));
});
};
/**
* Generates resource data binary for NtExecutable (not for .res file)
* @param virtualAddress The virtual address for the section
* @param alignment File alignment value of executable
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
NtExecutableResource.prototype.generateResourceData = function (virtualAddress, alignment, noGrow, allowShrink) {
if (noGrow === void 0) { noGrow = false; }
if (allowShrink === void 0) { allowShrink = false; }
// estimate data size and divide to output table
var r = {
s: [],
n: [],
};
var strings = [];
var size = divideEntriesImplByType(r, strings, this.entries);
strings = removeDuplicates(strings);
var stringsOffset = size;
size += strings.reduce(function (prev, cur) {
return prev + 2 + calculateStringLengthForWrite(cur) * 2;
}, 0);
size = roundUp(size, 8);
var descOffset = size;
size = this.entries.reduce(function (p, e) {
e.offset = p;
return p + 16;
}, descOffset);
var dataOffset = size;
size = this.entries.reduce(function (p, e) {
return roundUp(p, 8) + e.bin.byteLength;
}, dataOffset);
var alignedSize = roundUp(size, alignment);
var originalAlignedSize = roundUp(this.originalSize, alignment);
if (noGrow) {
if (alignedSize > originalAlignedSize) {
throw new Error('New resource data is larger than original');
}
}
if (!allowShrink) {
if (alignedSize < originalAlignedSize) {
alignedSize = originalAlignedSize;
}
}
// generate binary
var bin = new ArrayBuffer(alignedSize);
var view = new DataView(bin);
var o = descOffset;
var va = virtualAddress + dataOffset;
this.entries.forEach(function (e) {
var len = e.bin.byteLength;
if (typeof e.rva !== 'undefined') {
// RVA
view.setUint32(o, e.rva, true);
}
else {
va = roundUp(va, 8);
// RVA
view.setUint32(o, va, true);
va += len;
}
// size
view.setUint32(o + 4, len, true);
// codepage
view.setUint32(o + 8, e.codepage, true);
// (zero)
view.setUint32(o + 12, 0, true);
o += 16;
});
o = dataOffset;
this.entries.forEach(function (e) {
var len = e.bin.byteLength;
copyBuffer(bin, o, e.bin, 0, len);
o += roundUp(len, 8);
});
var stringsData = [];
o = stringsOffset;
strings.forEach(function (s) {
stringsData.push({
offset: o,
text: s,
});
o = writeString(view, o, s);
});
writeTypeTable(view, 0, stringsData, r);
// fill with 'PADDINGX'
if (alignedSize > size) {
var pad = 'PADDINGX';
for (var i = size, j = 0; i < alignedSize; ++i, ++j) {
if (j === 8) {
j = 0;
}
view.setUint8(i, pad.charCodeAt(j));
}
}
return {
bin: bin,
rawSize: size,
dataOffset: dataOffset,
descEntryOffset: descOffset,
descEntryCount: this.entries.length,
};
};
/**
* Writes holding resource data to specified NtExecutable instance.
* @param exeDest An NtExecutable instance to write resource section to
* @param noGrow Set true to disallow growing resource section (throw errors if data exceeds)
* @param allowShrink Set true to allow shrinking resource section (if the data size is less than original)
*/
NtExecutableResource.prototype.outputResource = function (exeDest, noGrow, allowShrink) {
if (noGrow === void 0) { noGrow = false; }
if (allowShrink === void 0) { allowShrink = false; }
// make section data
var fileAlign = exeDest.getFileAlignment();
var sectionData;
if (this.sectionDataHeader) {
sectionData = {
data: null,
info: cloneObject(this.sectionDataHeader),
};
}
else {
sectionData = {
data: null,
info: {
name: '.rsrc',
virtualSize: 0,
virtualAddress: 0,
sizeOfRawData: 0,
pointerToRawData: 0,
pointerToRelocations: 0,
pointerToLineNumbers: 0,
numberOfRelocations: 0,
numberOfLineNumbers: 0,
characteristics: 0x40000040, // read access and initialized data
},
};
}
// first, set virtualAddress to 0 because
// the virtual address is not determined now
var data = this.generateResourceData(0, fileAlign, noGrow, allowShrink);
sectionData.data = data.bin;
sectionData.info.sizeOfRawData = data.bin.byteLength;
sectionData.info.virtualSize = data.rawSize;
// write as section
exeDest.setSectionByEntry(ImageDirectoryEntry.Resource, sectionData);
// rewrite section raw-data
var generatedSection = exeDest.getSectionByEntry(ImageDirectoryEntry.Resource);
var view = new DataView(generatedSection.data);
// set RVA
var o = data.descEntryOffset;
var va = generatedSection.info.virtualAddress + data.dataOffset;
for (var i = 0; i < data.descEntryCount; ++i) {
var len = view.getUint32(o + 4, true);
va = roundUp(va, 8);
// RVA
view.setUint32(o, va, true);
va += len;
o += 16;
}
};
return NtExecutableResource;
}());
export default NtExecutableResource;

View File

@@ -0,0 +1,14 @@
import FormatBase from './FormatBase.js';
/** abstract class that support array-like methods and 'for...of' operation */
declare abstract class ArrayFormatBase<T> extends FormatBase {
protected constructor(view: DataView);
abstract readonly length: number;
abstract get(index: number): Readonly<T>;
abstract set(index: number, data: T): void;
forEach(callback: (value: T, index: number, base: this) => void): void;
_iterator(): Iterator<Readonly<T>>;
}
interface ArrayFormatBase<T> {
[Symbol.iterator]: () => Iterator<Readonly<T>>;
}
export default ArrayFormatBase;

View File

@@ -0,0 +1,64 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import FormatBase from './FormatBase.js';
/** abstract class that support array-like methods and 'for...of' operation */
var ArrayFormatBase = /** @class */ (function (_super) {
__extends(ArrayFormatBase, _super);
function ArrayFormatBase(view) {
return _super.call(this, view) || this;
}
ArrayFormatBase.prototype.forEach = function (callback) {
var len = this.length;
var a = [];
a.length = len;
for (var i = 0; i < len; ++i) {
a[i] = this.get(i);
}
for (var i = 0; i < len; ++i) {
callback(a[i], i, this);
}
};
ArrayFormatBase.prototype._iterator = function () {
return new (/** @class */ (function () {
function class_1(base) {
this.base = base;
this.i = 0;
}
class_1.prototype.next = function () {
if (this.i === this.base.length) {
return {
value: undefined,
done: true,
};
}
else {
return {
value: this.base.get(this.i++),
done: false,
};
}
};
return class_1;
}()))(this);
};
return ArrayFormatBase;
}(FormatBase));
/* istanbul ignore else */
if (typeof Symbol !== 'undefined') {
ArrayFormatBase.prototype[Symbol.iterator] =
ArrayFormatBase.prototype._iterator;
}
export default ArrayFormatBase;

View File

@@ -0,0 +1,6 @@
export default abstract class FormatBase {
protected readonly view: DataView;
protected constructor(view: DataView);
copyTo(bin: ArrayBuffer, offset: number): void;
get byteLength(): number;
}

View File

@@ -0,0 +1,17 @@
var FormatBase = /** @class */ (function () {
function FormatBase(view) {
this.view = view;
}
FormatBase.prototype.copyTo = function (bin, offset) {
new Uint8Array(bin, offset, this.view.byteLength).set(new Uint8Array(this.view.buffer, this.view.byteOffset, this.view.byteLength));
};
Object.defineProperty(FormatBase.prototype, "byteLength", {
get: function () {
return this.view.byteLength;
},
enumerable: false,
configurable: true
});
return FormatBase;
}());
export default FormatBase;

View File

@@ -0,0 +1,16 @@
import ArrayFormatBase from './ArrayFormatBase.js';
export interface ImageDataDirectory {
virtualAddress: number;
size: number;
}
export default class ImageDataDirectoryArray extends ArrayFormatBase<ImageDataDirectory> {
static readonly size = 128;
static readonly itemSize = 8;
readonly length = 16;
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;
get(index: number): Readonly<ImageDataDirectory>;
set(index: number, data: ImageDataDirectory): void;
findIndexByVirtualAddress(virtualAddress: number): number | null;
}

View File

@@ -0,0 +1,53 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import ArrayFormatBase from './ArrayFormatBase.js';
var ImageDataDirectoryArray = /** @class */ (function (_super) {
__extends(ImageDataDirectoryArray, _super);
function ImageDataDirectoryArray(view) {
var _this = _super.call(this, view) || this;
_this.length = 16;
return _this;
}
/** @note This does not clone binary data; the changes to the array will modify the specified buffer `bin` */
ImageDataDirectoryArray.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageDataDirectoryArray(new DataView(bin, offset, 128));
};
ImageDataDirectoryArray.prototype.get = function (index) {
return {
virtualAddress: this.view.getUint32(index * 8, true),
size: this.view.getUint32(4 + index * 8, true),
};
};
ImageDataDirectoryArray.prototype.set = function (index, data) {
this.view.setUint32(index * 8, data.virtualAddress, true);
this.view.setUint32(4 + index * 8, data.size, true);
};
ImageDataDirectoryArray.prototype.findIndexByVirtualAddress = function (virtualAddress) {
for (var i = 0; i < 16; ++i) {
var va = this.view.getUint32(i * 8, true);
var vs = this.view.getUint32(4 + i * 8, true);
if (virtualAddress >= va && virtualAddress < va + vs) {
return i;
}
}
return null;
};
ImageDataDirectoryArray.size = 128; // 16 * 8
ImageDataDirectoryArray.itemSize = 8;
return ImageDataDirectoryArray;
}(ArrayFormatBase));
export default ImageDataDirectoryArray;

View File

@@ -0,0 +1,22 @@
declare enum ImageDirectoryEntry {
Export = 0,
Import = 1,
Resource = 2,
Exception = 3,
Certificate = 4,
Security = 4,
BaseRelocation = 5,
Debug = 6,
Architecture = 7,
GlobalPointer = 8,
Tls = 9,
TLS = 9,
LoadConfig = 10,
BoundImport = 11,
Iat = 12,
IAT = 12,
DelayImport = 13,
ComDescriptor = 14,
COMDescriptor = 14
}
export default ImageDirectoryEntry;

View File

@@ -0,0 +1,24 @@
var ImageDirectoryEntry;
(function (ImageDirectoryEntry) {
ImageDirectoryEntry[ImageDirectoryEntry["Export"] = 0] = "Export";
ImageDirectoryEntry[ImageDirectoryEntry["Import"] = 1] = "Import";
ImageDirectoryEntry[ImageDirectoryEntry["Resource"] = 2] = "Resource";
ImageDirectoryEntry[ImageDirectoryEntry["Exception"] = 3] = "Exception";
ImageDirectoryEntry[ImageDirectoryEntry["Certificate"] = 4] = "Certificate";
// alias
ImageDirectoryEntry[ImageDirectoryEntry["Security"] = 4] = "Security";
ImageDirectoryEntry[ImageDirectoryEntry["BaseRelocation"] = 5] = "BaseRelocation";
ImageDirectoryEntry[ImageDirectoryEntry["Debug"] = 6] = "Debug";
ImageDirectoryEntry[ImageDirectoryEntry["Architecture"] = 7] = "Architecture";
ImageDirectoryEntry[ImageDirectoryEntry["GlobalPointer"] = 8] = "GlobalPointer";
ImageDirectoryEntry[ImageDirectoryEntry["Tls"] = 9] = "Tls";
ImageDirectoryEntry[ImageDirectoryEntry["TLS"] = 9] = "TLS";
ImageDirectoryEntry[ImageDirectoryEntry["LoadConfig"] = 10] = "LoadConfig";
ImageDirectoryEntry[ImageDirectoryEntry["BoundImport"] = 11] = "BoundImport";
ImageDirectoryEntry[ImageDirectoryEntry["Iat"] = 12] = "Iat";
ImageDirectoryEntry[ImageDirectoryEntry["IAT"] = 12] = "IAT";
ImageDirectoryEntry[ImageDirectoryEntry["DelayImport"] = 13] = "DelayImport";
ImageDirectoryEntry[ImageDirectoryEntry["ComDescriptor"] = 14] = "ComDescriptor";
ImageDirectoryEntry[ImageDirectoryEntry["COMDescriptor"] = 14] = "COMDescriptor";
})(ImageDirectoryEntry || (ImageDirectoryEntry = {}));
export default ImageDirectoryEntry;

View File

@@ -0,0 +1,42 @@
import FormatBase from './FormatBase.js';
export default class ImageDosHeader extends FormatBase {
static readonly size = 64;
static readonly DEFAULT_MAGIC = 23117;
private constructor();
static from(bin: ArrayBuffer | ArrayBufferView, offset?: number): ImageDosHeader;
isValid(): boolean;
get magic(): number;
set magic(val: number);
get lastPageSize(): number;
set lastPageSize(val: number);
get pages(): number;
set pages(val: number);
get relocations(): number;
set relocations(val: number);
get headerSizeInParagraph(): number;
set headerSizeInParagraph(val: number);
get minAllocParagraphs(): number;
set minAllocParagraphs(val: number);
get maxAllocParagraphs(): number;
set maxAllocParagraphs(val: number);
get initialSS(): number;
set initialSS(val: number);
get initialSP(): number;
set initialSP(val: number);
get checkSum(): number;
set checkSum(val: number);
get initialIP(): number;
set initialIP(val: number);
get initialCS(): number;
set initialCS(val: number);
get relocationTableAddress(): number;
set relocationTableAddress(val: number);
get overlayNum(): number;
set overlayNum(val: number);
get oemId(): number;
set oemId(val: number);
get oemInfo(): number;
set oemInfo(val: number);
get newHeaderAddress(): number;
set newHeaderAddress(val: number);
}

View File

@@ -0,0 +1,206 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import FormatBase from './FormatBase.js';
import { createDataView } from '../util/functions.js';
var ImageDosHeader = /** @class */ (function (_super) {
__extends(ImageDosHeader, _super);
function ImageDosHeader(view) {
return _super.call(this, view) || this;
}
ImageDosHeader.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageDosHeader(createDataView(bin, offset, 64));
};
ImageDosHeader.prototype.isValid = function () {
return this.magic === ImageDosHeader.DEFAULT_MAGIC;
};
Object.defineProperty(ImageDosHeader.prototype, "magic", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "lastPageSize", {
get: function () {
return this.view.getUint16(2, true);
},
set: function (val) {
this.view.setUint16(2, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "pages", {
get: function () {
return this.view.getUint16(4, true);
},
set: function (val) {
this.view.setUint16(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "relocations", {
get: function () {
return this.view.getUint16(6, true);
},
set: function (val) {
this.view.setUint16(6, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "headerSizeInParagraph", {
get: function () {
return this.view.getUint16(8, true);
},
set: function (val) {
this.view.setUint16(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "minAllocParagraphs", {
get: function () {
return this.view.getUint16(10, true);
},
set: function (val) {
this.view.setUint16(10, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "maxAllocParagraphs", {
get: function () {
return this.view.getUint16(12, true);
},
set: function (val) {
this.view.setUint16(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialSS", {
get: function () {
return this.view.getUint16(14, true);
},
set: function (val) {
this.view.setUint16(14, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialSP", {
get: function () {
return this.view.getUint16(16, true);
},
set: function (val) {
this.view.setUint16(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "checkSum", {
get: function () {
return this.view.getUint16(18, true);
},
set: function (val) {
this.view.setUint16(18, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialIP", {
get: function () {
return this.view.getUint16(20, true);
},
set: function (val) {
this.view.setUint16(20, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialCS", {
get: function () {
return this.view.getUint16(22, true);
},
set: function (val) {
this.view.setUint16(22, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "relocationTableAddress", {
get: function () {
return this.view.getUint16(24, true);
},
set: function (val) {
this.view.setUint16(24, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "overlayNum", {
get: function () {
return this.view.getUint16(26, true);
},
set: function (val) {
this.view.setUint16(26, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "oemId", {
// WORD e_res[4] (28,30,32,34)
get: function () {
return this.view.getUint16(36, true);
},
set: function (val) {
this.view.setUint16(36, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "oemInfo", {
get: function () {
return this.view.getUint16(38, true);
},
set: function (val) {
this.view.setUint16(38, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "newHeaderAddress", {
// WORD e_res2[10] (40,42,44,46,48,50,52,54,56,58)
get: function () {
return this.view.getUint32(60, true);
},
set: function (val) {
this.view.setUint32(60, val, true);
},
enumerable: false,
configurable: true
});
ImageDosHeader.size = 64;
ImageDosHeader.DEFAULT_MAGIC = 0x5a4d; // 'MZ'
return ImageDosHeader;
}(FormatBase));
export default ImageDosHeader;

View File

@@ -0,0 +1,20 @@
import FormatBase from './FormatBase.js';
export default class ImageFileHeader extends FormatBase {
static readonly size = 20;
private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageFileHeader;
get machine(): number;
set machine(val: number);
get numberOfSections(): number;
set numberOfSections(val: number);
get timeDateStamp(): number;
set timeDateStamp(val: number);
get pointerToSymbolTable(): number;
set pointerToSymbolTable(val: number);
get numberOfSymbols(): number;
set numberOfSymbols(val: number);
get sizeOfOptionalHeader(): number;
set sizeOfOptionalHeader(val: number);
get characteristics(): number;
set characteristics(val: number);
}

View File

@@ -0,0 +1,99 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import FormatBase from './FormatBase.js';
var ImageFileHeader = /** @class */ (function (_super) {
__extends(ImageFileHeader, _super);
function ImageFileHeader(view) {
return _super.call(this, view) || this;
}
ImageFileHeader.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageFileHeader(new DataView(bin, offset, 20));
};
Object.defineProperty(ImageFileHeader.prototype, "machine", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "numberOfSections", {
get: function () {
return this.view.getUint16(2, true);
},
set: function (val) {
this.view.setUint16(2, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "timeDateStamp", {
get: function () {
return this.view.getUint32(4, true);
},
set: function (val) {
this.view.setUint32(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "pointerToSymbolTable", {
get: function () {
return this.view.getUint32(8, true);
},
set: function (val) {
this.view.setUint32(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "numberOfSymbols", {
get: function () {
return this.view.getUint32(12, true);
},
set: function (val) {
this.view.setUint32(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "sizeOfOptionalHeader", {
get: function () {
return this.view.getUint16(16, true);
},
set: function (val) {
this.view.setUint16(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "characteristics", {
get: function () {
return this.view.getUint16(18, true);
},
set: function (val) {
this.view.setUint16(18, val, true);
},
enumerable: false,
configurable: true
});
ImageFileHeader.size = 20;
return ImageFileHeader;
}(FormatBase));
export default ImageFileHeader;

View File

@@ -0,0 +1,19 @@
import FormatBase from './FormatBase.js';
import ImageFileHeader from './ImageFileHeader.js';
import ImageOptionalHeader from './ImageOptionalHeader.js';
import ImageOptionalHeader64 from './ImageOptionalHeader64.js';
import ImageDataDirectoryArray from './ImageDataDirectoryArray.js';
export default class ImageNtHeaders extends FormatBase {
static readonly DEFAULT_SIGNATURE = 17744;
private constructor();
static from(bin: ArrayBuffer | ArrayBufferView, offset?: number): ImageNtHeaders;
isValid(): boolean;
is32bit(): boolean;
get signature(): number;
set signature(val: number);
get fileHeader(): ImageFileHeader;
get optionalHeader(): ImageOptionalHeader | ImageOptionalHeader64;
get optionalHeaderDataDirectory(): ImageDataDirectoryArray;
getDataDirectoryOffset(): number;
getSectionHeaderOffset(): number;
}

View File

@@ -0,0 +1,101 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import FormatBase from './FormatBase.js';
import ImageFileHeader from './ImageFileHeader.js';
import ImageOptionalHeader from './ImageOptionalHeader.js';
import ImageOptionalHeader64 from './ImageOptionalHeader64.js';
import ImageDataDirectoryArray from './ImageDataDirectoryArray.js';
import { createDataView } from '../util/functions.js';
var ImageNtHeaders = /** @class */ (function (_super) {
__extends(ImageNtHeaders, _super);
function ImageNtHeaders(view) {
return _super.call(this, view) || this;
}
ImageNtHeaders.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
var magic = createDataView(bin, offset + ImageFileHeader.size, 6).getUint16(4, true);
var len = 4 + ImageFileHeader.size + ImageDataDirectoryArray.size;
if (magic === ImageOptionalHeader64.DEFAULT_MAGIC) {
len += ImageOptionalHeader64.size;
}
else {
len += ImageOptionalHeader.size;
}
return new ImageNtHeaders(createDataView(bin, offset, len));
};
ImageNtHeaders.prototype.isValid = function () {
return this.signature === ImageNtHeaders.DEFAULT_SIGNATURE;
};
ImageNtHeaders.prototype.is32bit = function () {
return (this.view.getUint16(ImageFileHeader.size + 4, true) ===
ImageOptionalHeader.DEFAULT_MAGIC);
};
Object.defineProperty(ImageNtHeaders.prototype, "signature", {
get: function () {
return this.view.getUint32(0, true);
},
set: function (val) {
this.view.setUint32(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageNtHeaders.prototype, "fileHeader", {
get: function () {
return ImageFileHeader.from(this.view.buffer, this.view.byteOffset + 4);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageNtHeaders.prototype, "optionalHeader", {
get: function () {
var off = ImageFileHeader.size + 4;
var magic = this.view.getUint16(off, true);
if (magic === ImageOptionalHeader64.DEFAULT_MAGIC) {
return ImageOptionalHeader64.from(this.view.buffer, this.view.byteOffset + off);
}
else {
return ImageOptionalHeader.from(this.view.buffer, this.view.byteOffset + off);
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageNtHeaders.prototype, "optionalHeaderDataDirectory", {
get: function () {
return ImageDataDirectoryArray.from(this.view.buffer, this.view.byteOffset + this.getDataDirectoryOffset());
},
enumerable: false,
configurable: true
});
ImageNtHeaders.prototype.getDataDirectoryOffset = function () {
var off = ImageFileHeader.size + 4;
var magic = this.view.getUint16(off, true);
if (magic === ImageOptionalHeader64.DEFAULT_MAGIC) {
off += ImageOptionalHeader64.size;
}
else {
off += ImageOptionalHeader.size;
}
return off;
};
ImageNtHeaders.prototype.getSectionHeaderOffset = function () {
return this.getDataDirectoryOffset() + ImageDataDirectoryArray.size;
};
ImageNtHeaders.DEFAULT_SIGNATURE = 0x4550; // 'PE\x00\x00'
return ImageNtHeaders;
}(FormatBase));
export default ImageNtHeaders;

View File

@@ -0,0 +1,67 @@
import FormatBase from './FormatBase.js';
export default class ImageOptionalHeader extends FormatBase {
static readonly size = 96;
static readonly DEFAULT_MAGIC = 267;
private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageOptionalHeader;
get magic(): number;
set magic(val: number);
get majorLinkerVersion(): number;
set majorLinkerVersion(val: number);
get minorLinkerVersion(): number;
set minorLinkerVersion(val: number);
get sizeOfCode(): number;
set sizeOfCode(val: number);
get sizeOfInitializedData(): number;
set sizeOfInitializedData(val: number);
get sizeOfUninitializedData(): number;
set sizeOfUninitializedData(val: number);
get addressOfEntryPoint(): number;
set addressOfEntryPoint(val: number);
get baseOfCode(): number;
set baseOfCode(val: number);
get baseOfData(): number;
set baseOfData(val: number);
get imageBase(): number;
set imageBase(val: number);
get sectionAlignment(): number;
set sectionAlignment(val: number);
get fileAlignment(): number;
set fileAlignment(val: number);
get majorOperatingSystemVersion(): number;
set majorOperatingSystemVersion(val: number);
get minorOperatingSystemVersion(): number;
set minorOperatingSystemVersion(val: number);
get majorImageVersion(): number;
set majorImageVersion(val: number);
get minorImageVersion(): number;
set minorImageVersion(val: number);
get majorSubsystemVersion(): number;
set majorSubsystemVersion(val: number);
get minorSubsystemVersion(): number;
set minorSubsystemVersion(val: number);
get win32VersionValue(): number;
set win32VersionValue(val: number);
get sizeOfImage(): number;
set sizeOfImage(val: number);
get sizeOfHeaders(): number;
set sizeOfHeaders(val: number);
get checkSum(): number;
set checkSum(val: number);
get subsystem(): number;
set subsystem(val: number);
get dllCharacteristics(): number;
set dllCharacteristics(val: number);
get sizeOfStackReserve(): number;
set sizeOfStackReserve(val: number);
get sizeOfStackCommit(): number;
set sizeOfStackCommit(val: number);
get sizeOfHeapReserve(): number;
set sizeOfHeapReserve(val: number);
get sizeOfHeapCommit(): number;
set sizeOfHeapCommit(val: number);
get loaderFlags(): number;
set loaderFlags(val: number);
get numberOfRvaAndSizes(): number;
set numberOfRvaAndSizes(val: number);
}

View File

@@ -0,0 +1,330 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import FormatBase from './FormatBase.js';
var ImageOptionalHeader = /** @class */ (function (_super) {
__extends(ImageOptionalHeader, _super);
function ImageOptionalHeader(view) {
return _super.call(this, view) || this;
}
ImageOptionalHeader.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageOptionalHeader(new DataView(bin, offset, 96));
};
Object.defineProperty(ImageOptionalHeader.prototype, "magic", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorLinkerVersion", {
get: function () {
return this.view.getUint8(2);
},
set: function (val) {
this.view.setUint8(2, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorLinkerVersion", {
get: function () {
return this.view.getUint8(3);
},
set: function (val) {
this.view.setUint8(3, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfCode", {
get: function () {
return this.view.getUint32(4, true);
},
set: function (val) {
this.view.setUint32(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfInitializedData", {
get: function () {
return this.view.getUint32(8, true);
},
set: function (val) {
this.view.setUint32(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfUninitializedData", {
get: function () {
return this.view.getUint32(12, true);
},
set: function (val) {
this.view.setUint32(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "addressOfEntryPoint", {
get: function () {
return this.view.getUint32(16, true);
},
set: function (val) {
this.view.setUint32(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "baseOfCode", {
get: function () {
return this.view.getUint32(20, true);
},
set: function (val) {
this.view.setUint32(20, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "baseOfData", {
get: function () {
return this.view.getUint32(24, true);
},
set: function (val) {
this.view.setUint32(24, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "imageBase", {
get: function () {
return this.view.getUint32(28, true);
},
set: function (val) {
this.view.setUint32(28, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sectionAlignment", {
get: function () {
return this.view.getUint32(32, true);
},
set: function (val) {
this.view.setUint32(32, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "fileAlignment", {
get: function () {
return this.view.getUint32(36, true);
},
set: function (val) {
this.view.setUint32(36, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(40, true);
},
set: function (val) {
this.view.setUint16(40, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(42, true);
},
set: function (val) {
this.view.setUint16(42, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorImageVersion", {
get: function () {
return this.view.getUint16(44, true);
},
set: function (val) {
this.view.setUint16(44, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorImageVersion", {
get: function () {
return this.view.getUint16(46, true);
},
set: function (val) {
this.view.setUint16(46, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorSubsystemVersion", {
get: function () {
return this.view.getUint16(48, true);
},
set: function (val) {
this.view.setUint16(48, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorSubsystemVersion", {
get: function () {
return this.view.getUint16(50, true);
},
set: function (val) {
this.view.setUint16(50, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "win32VersionValue", {
get: function () {
return this.view.getUint32(52, true);
},
set: function (val) {
this.view.setUint32(52, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfImage", {
get: function () {
return this.view.getUint32(56, true);
},
set: function (val) {
this.view.setUint32(56, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfHeaders", {
get: function () {
return this.view.getUint32(60, true);
},
set: function (val) {
this.view.setUint32(60, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "checkSum", {
get: function () {
return this.view.getUint32(64, true);
},
set: function (val) {
this.view.setUint32(64, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "subsystem", {
get: function () {
return this.view.getUint16(68, true);
},
set: function (val) {
this.view.setUint16(68, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "dllCharacteristics", {
get: function () {
return this.view.getUint16(70, true);
},
set: function (val) {
this.view.setUint16(70, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfStackReserve", {
get: function () {
return this.view.getUint32(72, true);
},
set: function (val) {
this.view.setUint32(72, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfStackCommit", {
get: function () {
return this.view.getUint32(76, true);
},
set: function (val) {
this.view.setUint32(76, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfHeapReserve", {
get: function () {
return this.view.getUint32(80, true);
},
set: function (val) {
this.view.setUint32(80, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfHeapCommit", {
get: function () {
return this.view.getUint32(84, true);
},
set: function (val) {
this.view.setUint32(84, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "loaderFlags", {
get: function () {
return this.view.getUint32(88, true);
},
set: function (val) {
this.view.setUint32(88, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "numberOfRvaAndSizes", {
get: function () {
return this.view.getUint32(92, true);
},
set: function (val) {
this.view.setUint32(92, val, true);
},
enumerable: false,
configurable: true
});
ImageOptionalHeader.size = 96;
ImageOptionalHeader.DEFAULT_MAGIC = 0x10b;
return ImageOptionalHeader;
}(FormatBase));
export default ImageOptionalHeader;

View File

@@ -0,0 +1,75 @@
import FormatBase from './FormatBase.js';
export default class ImageOptionalHeader64 extends FormatBase {
static readonly size = 112;
static readonly DEFAULT_MAGIC = 523;
private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageOptionalHeader64;
get magic(): number;
set magic(val: number);
get majorLinkerVersion(): number;
set majorLinkerVersion(val: number);
get minorLinkerVersion(): number;
set minorLinkerVersion(val: number);
get sizeOfCode(): number;
set sizeOfCode(val: number);
get sizeOfInitializedData(): number;
set sizeOfInitializedData(val: number);
get sizeOfUninitializedData(): number;
set sizeOfUninitializedData(val: number);
get addressOfEntryPoint(): number;
set addressOfEntryPoint(val: number);
get baseOfCode(): number;
set baseOfCode(val: number);
get imageBase(): number;
set imageBase(val: number);
get imageBaseBigInt(): bigint;
set imageBaseBigInt(val: bigint);
get sectionAlignment(): number;
set sectionAlignment(val: number);
get fileAlignment(): number;
set fileAlignment(val: number);
get majorOperatingSystemVersion(): number;
set majorOperatingSystemVersion(val: number);
get minorOperatingSystemVersion(): number;
set minorOperatingSystemVersion(val: number);
get majorImageVersion(): number;
set majorImageVersion(val: number);
get minorImageVersion(): number;
set minorImageVersion(val: number);
get majorSubsystemVersion(): number;
set majorSubsystemVersion(val: number);
get minorSubsystemVersion(): number;
set minorSubsystemVersion(val: number);
get win32VersionValue(): number;
set win32VersionValue(val: number);
get sizeOfImage(): number;
set sizeOfImage(val: number);
get sizeOfHeaders(): number;
set sizeOfHeaders(val: number);
get checkSum(): number;
set checkSum(val: number);
get subsystem(): number;
set subsystem(val: number);
get dllCharacteristics(): number;
set dllCharacteristics(val: number);
get sizeOfStackReserve(): number;
set sizeOfStackReserve(val: number);
get sizeOfStackReserveBigInt(): bigint;
set sizeOfStackReserveBigInt(val: bigint);
get sizeOfStackCommit(): number;
set sizeOfStackCommit(val: number);
get sizeOfStackCommitBigInt(): bigint;
set sizeOfStackCommitBigInt(val: bigint);
get sizeOfHeapReserve(): number;
set sizeOfHeapReserve(val: number);
get sizeOfHeapReserveBigInt(): bigint;
set sizeOfHeapReserveBigInt(val: bigint);
get sizeOfHeapCommit(): number;
set sizeOfHeapCommit(val: number);
get sizeOfHeapCommitBigInt(): bigint;
set sizeOfHeapCommitBigInt(val: bigint);
get loaderFlags(): number;
set loaderFlags(val: number);
get numberOfRvaAndSizes(): number;
set numberOfRvaAndSizes(val: number);
}

View File

@@ -0,0 +1,394 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import FormatBase from './FormatBase.js';
function getUint64LE(view, offset) {
return (view.getUint32(offset + 4, true) * 0x100000000 +
view.getUint32(offset, true));
}
function setUint64LE(view, offset, val) {
view.setUint32(offset, val & 0xffffffff, true);
view.setUint32(offset + 4, Math.floor(val / 0x100000000), true);
}
function getUint64LEBigInt(view, offset) {
/* istanbul ignore if */
if (typeof BigInt === 'undefined') {
throw new Error('BigInt not supported');
}
return (BigInt(0x100000000) * BigInt(view.getUint32(offset + 4, true)) +
BigInt(view.getUint32(offset, true)));
}
function setUint64LEBigInt(view, offset, val) {
/* istanbul ignore if */
if (typeof BigInt === 'undefined') {
throw new Error('BigInt not supported');
}
view.setUint32(offset, Number(val & BigInt(0xffffffff)), true);
view.setUint32(offset + 4, Math.floor(Number((val / BigInt(0x100000000)) & BigInt(0xffffffff))), true);
}
var ImageOptionalHeader64 = /** @class */ (function (_super) {
__extends(ImageOptionalHeader64, _super);
function ImageOptionalHeader64(view) {
return _super.call(this, view) || this;
}
ImageOptionalHeader64.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageOptionalHeader64(new DataView(bin, offset, 112));
};
Object.defineProperty(ImageOptionalHeader64.prototype, "magic", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorLinkerVersion", {
get: function () {
return this.view.getUint8(2);
},
set: function (val) {
this.view.setUint8(2, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorLinkerVersion", {
get: function () {
return this.view.getUint8(3);
},
set: function (val) {
this.view.setUint8(3, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfCode", {
get: function () {
return this.view.getUint32(4, true);
},
set: function (val) {
this.view.setUint32(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfInitializedData", {
get: function () {
return this.view.getUint32(8, true);
},
set: function (val) {
this.view.setUint32(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfUninitializedData", {
get: function () {
return this.view.getUint32(12, true);
},
set: function (val) {
this.view.setUint32(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "addressOfEntryPoint", {
get: function () {
return this.view.getUint32(16, true);
},
set: function (val) {
this.view.setUint32(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "baseOfCode", {
get: function () {
return this.view.getUint32(20, true);
},
set: function (val) {
this.view.setUint32(20, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "imageBase", {
get: function () {
return getUint64LE(this.view, 24);
},
set: function (val) {
setUint64LE(this.view, 24, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "imageBaseBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 24);
},
set: function (val) {
setUint64LEBigInt(this.view, 24, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sectionAlignment", {
get: function () {
return this.view.getUint32(32, true);
},
set: function (val) {
this.view.setUint32(32, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "fileAlignment", {
get: function () {
return this.view.getUint32(36, true);
},
set: function (val) {
this.view.setUint32(36, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(40, true);
},
set: function (val) {
this.view.setUint16(40, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(42, true);
},
set: function (val) {
this.view.setUint16(42, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorImageVersion", {
get: function () {
return this.view.getUint16(44, true);
},
set: function (val) {
this.view.setUint16(44, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorImageVersion", {
get: function () {
return this.view.getUint16(46, true);
},
set: function (val) {
this.view.setUint16(46, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorSubsystemVersion", {
get: function () {
return this.view.getUint16(48, true);
},
set: function (val) {
this.view.setUint16(48, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorSubsystemVersion", {
get: function () {
return this.view.getUint16(50, true);
},
set: function (val) {
this.view.setUint16(50, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "win32VersionValue", {
get: function () {
return this.view.getUint32(52, true);
},
set: function (val) {
this.view.setUint32(52, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfImage", {
get: function () {
return this.view.getUint32(56, true);
},
set: function (val) {
this.view.setUint32(56, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeaders", {
get: function () {
return this.view.getUint32(60, true);
},
set: function (val) {
this.view.setUint32(60, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "checkSum", {
get: function () {
return this.view.getUint32(64, true);
},
set: function (val) {
this.view.setUint32(64, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "subsystem", {
get: function () {
return this.view.getUint16(68, true);
},
set: function (val) {
this.view.setUint16(68, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "dllCharacteristics", {
get: function () {
return this.view.getUint16(70, true);
},
set: function (val) {
this.view.setUint16(70, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackReserve", {
get: function () {
return getUint64LE(this.view, 72);
},
set: function (val) {
setUint64LE(this.view, 72, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackReserveBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 72);
},
set: function (val) {
setUint64LEBigInt(this.view, 72, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackCommit", {
get: function () {
return getUint64LE(this.view, 80);
},
set: function (val) {
setUint64LE(this.view, 80, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackCommitBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 80);
},
set: function (val) {
setUint64LEBigInt(this.view, 80, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapReserve", {
get: function () {
return getUint64LE(this.view, 88);
},
set: function (val) {
setUint64LE(this.view, 88, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapReserveBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 88);
},
set: function (val) {
setUint64LEBigInt(this.view, 88, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapCommit", {
get: function () {
return getUint64LE(this.view, 96);
},
set: function (val) {
setUint64LE(this.view, 96, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapCommitBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 96);
},
set: function (val) {
setUint64LEBigInt(this.view, 96, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "loaderFlags", {
get: function () {
return this.view.getUint32(104, true);
},
set: function (val) {
this.view.setUint32(104, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "numberOfRvaAndSizes", {
get: function () {
return this.view.getUint32(108, true);
},
set: function (val) {
this.view.setUint32(108, val, true);
},
enumerable: false,
configurable: true
});
ImageOptionalHeader64.size = 112;
ImageOptionalHeader64.DEFAULT_MAGIC = 0x20b;
return ImageOptionalHeader64;
}(FormatBase));
export default ImageOptionalHeader64;

View File

@@ -0,0 +1,21 @@
import ArrayFormatBase from './ArrayFormatBase.js';
export interface ImageSectionHeader {
name: string;
virtualSize: number;
virtualAddress: number;
sizeOfRawData: number;
pointerToRawData: number;
pointerToRelocations: number;
pointerToLineNumbers: number;
numberOfRelocations: number;
numberOfLineNumbers: number;
characteristics: number;
}
export default class ImageSectionHeaderArray extends ArrayFormatBase<ImageSectionHeader> {
readonly length: number;
static readonly itemSize = 40;
private constructor();
static from(bin: ArrayBuffer, length: number, offset?: number): ImageSectionHeaderArray;
get(index: number): Readonly<ImageSectionHeader>;
set(index: number, data: ImageSectionHeader): void;
}

View File

@@ -0,0 +1,59 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import ArrayFormatBase from './ArrayFormatBase.js';
import { getFixedString, setFixedString } from '../util/functions.js';
var ImageSectionHeaderArray = /** @class */ (function (_super) {
__extends(ImageSectionHeaderArray, _super);
function ImageSectionHeaderArray(view, length) {
var _this = _super.call(this, view) || this;
_this.length = length;
return _this;
}
ImageSectionHeaderArray.from = function (bin, length, offset) {
if (offset === void 0) { offset = 0; }
var size = length * 40;
return new ImageSectionHeaderArray(new DataView(bin, offset, size), length);
};
ImageSectionHeaderArray.prototype.get = function (index) {
return {
name: getFixedString(this.view, index * 40, 8),
virtualSize: this.view.getUint32(8 + index * 40, true),
virtualAddress: this.view.getUint32(12 + index * 40, true),
sizeOfRawData: this.view.getUint32(16 + index * 40, true),
pointerToRawData: this.view.getUint32(20 + index * 40, true),
pointerToRelocations: this.view.getUint32(24 + index * 40, true),
pointerToLineNumbers: this.view.getUint32(28 + index * 40, true),
numberOfRelocations: this.view.getUint16(32 + index * 40, true),
numberOfLineNumbers: this.view.getUint16(34 + index * 40, true),
characteristics: this.view.getUint32(36 + index * 40, true),
};
};
ImageSectionHeaderArray.prototype.set = function (index, data) {
setFixedString(this.view, index * 40, 8, data.name);
this.view.setUint32(8 + index * 40, data.virtualSize, true);
this.view.setUint32(12 + index * 40, data.virtualAddress, true);
this.view.setUint32(16 + index * 40, data.sizeOfRawData, true);
this.view.setUint32(20 + index * 40, data.pointerToRawData, true);
this.view.setUint32(24 + index * 40, data.pointerToRelocations, true);
this.view.setUint32(28 + index * 40, data.pointerToLineNumbers, true);
this.view.setUint16(32 + index * 40, data.numberOfRelocations, true);
this.view.setUint16(34 + index * 40, data.numberOfLineNumbers, true);
this.view.setUint32(36 + index * 40, data.characteristics, true);
};
ImageSectionHeaderArray.itemSize = 40;
return ImageSectionHeaderArray;
}(ArrayFormatBase));
export default ImageSectionHeaderArray;

View File

@@ -0,0 +1,15 @@
import ArrayFormatBase from './ArrayFormatBase.js';
import FormatBase from './FormatBase.js';
import ImageDataDirectoryArray, { ImageDataDirectory } from './ImageDataDirectoryArray.js';
import ImageDirectoryEntry from './ImageDirectoryEntry.js';
import ImageDosHeader from './ImageDosHeader.js';
import ImageFileHeader from './ImageFileHeader.js';
import ImageNtHeaders from './ImageNtHeaders.js';
import ImageOptionalHeader from './ImageOptionalHeader.js';
import ImageOptionalHeader64 from './ImageOptionalHeader64.js';
import ImageSectionHeaderArray, { ImageSectionHeader } from './ImageSectionHeaderArray.js';
export { ArrayFormatBase, FormatBase, ImageDataDirectory, ImageDataDirectoryArray, ImageDirectoryEntry, ImageDosHeader, ImageFileHeader, ImageNtHeaders, ImageOptionalHeader, ImageOptionalHeader64, ImageSectionHeader, ImageSectionHeaderArray, };
export declare function getImageDosHeader(bin: ArrayBuffer): ImageDosHeader;
export declare function getImageNtHeadersByDosHeader(bin: ArrayBuffer, dosHeader: ImageDosHeader): ImageNtHeaders;
export declare function getImageSectionHeadersByNtHeaders(bin: ArrayBuffer, dosHeader: ImageDosHeader, ntHeaders: ImageNtHeaders): ImageSectionHeaderArray;
export declare function findImageSectionBlockByDirectoryEntry(bin: ArrayBuffer, dosHeader: ImageDosHeader, ntHeaders: ImageNtHeaders, entryType: ImageDirectoryEntry): ArrayBuffer | null;

View File

@@ -0,0 +1,40 @@
import ArrayFormatBase from './ArrayFormatBase.js';
import FormatBase from './FormatBase.js';
import ImageDataDirectoryArray from './ImageDataDirectoryArray.js';
import ImageDirectoryEntry from './ImageDirectoryEntry.js';
import ImageDosHeader from './ImageDosHeader.js';
import ImageFileHeader from './ImageFileHeader.js';
import ImageNtHeaders from './ImageNtHeaders.js';
import ImageOptionalHeader from './ImageOptionalHeader.js';
import ImageOptionalHeader64 from './ImageOptionalHeader64.js';
import ImageSectionHeaderArray from './ImageSectionHeaderArray.js';
export { ArrayFormatBase, FormatBase, ImageDataDirectoryArray, ImageDirectoryEntry, ImageDosHeader, ImageFileHeader, ImageNtHeaders, ImageOptionalHeader, ImageOptionalHeader64, ImageSectionHeaderArray, };
export function getImageDosHeader(bin) {
return ImageDosHeader.from(bin);
}
export function getImageNtHeadersByDosHeader(bin, dosHeader) {
return ImageNtHeaders.from(bin, dosHeader.newHeaderAddress);
}
export function getImageSectionHeadersByNtHeaders(bin, dosHeader, ntHeaders) {
return ImageSectionHeaderArray.from(bin, ntHeaders.fileHeader.numberOfSections, dosHeader.newHeaderAddress + ntHeaders.byteLength);
}
export function findImageSectionBlockByDirectoryEntry(bin, dosHeader, ntHeaders, entryType) {
var arr = ImageSectionHeaderArray.from(bin, ntHeaders.fileHeader.numberOfSections, dosHeader.newHeaderAddress + ntHeaders.byteLength);
var len = arr.length;
var rva = ntHeaders.optionalHeaderDataDirectory.get(entryType).virtualAddress;
for (var i = 0; i < len; ++i) {
var sec = arr.get(i);
var vaEnd = sec.virtualAddress + sec.virtualSize;
if (rva >= sec.virtualAddress && rva < vaEnd) {
var ptr = sec.pointerToRawData;
if (!ptr) {
return null;
}
return bin.slice(ptr, ptr + sec.sizeOfRawData);
}
if (rva < sec.virtualAddress) {
return null;
}
}
return null;
}

View File

@@ -0,0 +1,7 @@
import NtExecutable, { NtExecutableFromOptions, NtExecutableSection } from './NtExecutable.js';
import NtExecutableResource from './NtExecutableResource.js';
import { calculateCheckSumForPE } from './util/functions.js';
import version from './version.js';
import * as Format from './format/index.js';
import * as Type from './type/index.js';
export { NtExecutable, NtExecutableFromOptions, NtExecutableResource, NtExecutableSection, calculateCheckSumForPE, version, Format, Type, };

View File

@@ -0,0 +1,7 @@
import NtExecutable from './NtExecutable.js';
import NtExecutableResource from './NtExecutableResource.js';
import { calculateCheckSumForPE } from './util/functions.js';
import version from './version.js';
import * as Format from './format/index.js';
import * as Type from './type/index.js';
export { NtExecutable, NtExecutableResource, calculateCheckSumForPE, version, Format, Type, };

View File

@@ -0,0 +1,31 @@
export interface ResourceEntryBaseType<TType extends string | number, TID extends string | number, TLang extends string | number> {
/**
* The resource type name or numeric value.
* For well-known type (such as `RT_ICON`), this value must be the predefined numeric value.
*/
type: TType;
/** The ID of resource data. */
id: TID;
/**
* The language value of resource data.
* According to specification, this value can be string, but
* typically this value would be LANGID (numeric) value.
*/
lang: TLang;
/**
* The code page value for strings within the resource data.
* Typically this value would be the Unicode code page '1200'.
*/
codepage: number;
/** The actual resource data. If the data cannot be read, this field will be an empty binary. */
bin: ArrayBuffer;
/** RVA data for resource data. This field is available only when actual data (`bin` field) cannot be read. */
rva?: number;
/** (used by output) */
offset?: number;
}
export declare type ResourceEntryT<TType extends string | number> = ResourceEntryBaseType<TType, string | number, string | number>;
export declare type ResourceEntryTT<TType extends string | number, TID extends string | number> = ResourceEntryBaseType<TType, TID, string | number>;
/** Raw resource entry data */
declare type ResourceEntry = ResourceEntryBaseType<string | number, string | number, string | number>;
export default ResourceEntry;

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,2 @@
import ResourceEntry, { ResourceEntryBaseType, ResourceEntryT, ResourceEntryTT } from './ResourceEntry.js';
export { ResourceEntry, ResourceEntryBaseType, ResourceEntryT, ResourceEntryTT, };

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,13 @@
/// <reference lib="dom" />
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 | ArrayBufferView, 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 getFixedString(view: DataView, offset: number, length: number): string;
export declare function setFixedString(view: DataView, offset: number, length: number, text: string): void;
export declare function binaryToString(bin: ArrayBuffer | ArrayBufferView): string;
export declare function stringToBinary(string: string): ArrayBuffer;

View File

@@ -0,0 +1,259 @@
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference lib='dom' />
import ImageDosHeader from '../format/ImageDosHeader.js';
export function cloneObject(object) {
var r = {};
Object.keys(object).forEach(function (key) {
r[key] = object[key];
});
return r;
}
/* eslint-enable @typescript-eslint/ban-types */
export 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);
}
}
export function calculateCheckSumForPE(bin, storeToBinary) {
var dosHeader = ImageDosHeader.from(bin);
var view = new DataView(bin);
var checkSumOffset = dosHeader.newHeaderAddress + 88;
var result = 0;
var limit = 0x100000000; // 2^32
var update = function (dword) {
result += dword;
if (result >= limit) {
result = (result % limit) + ((result / limit) | 0);
}
};
var len = view.byteLength;
var lenExtra = len % 4;
var lenAlign = len - lenExtra;
for (var i = 0; i < lenAlign; i += 4) {
if (i !== checkSumOffset) {
update(view.getUint32(i, true));
}
}
if (lenExtra !== 0) {
var extra = 0;
for (var i = 0; i < lenExtra; i++) {
extra |= view.getUint8(lenAlign + i) << ((3 - i) * 8);
}
update(extra);
}
result = (result & 0xffff) + (result >>> 16);
result += result >>> 16;
result = (result & 0xffff) + len;
if (storeToBinary) {
view.setUint32(checkSumOffset, result, true);
}
return result;
}
export function roundUp(val, align) {
return Math.floor((val + align - 1) / align) * align;
}
export function copyBuffer(dest, destOffset, src, srcOffset, length) {
var ua8Dest = 'buffer' in dest
? new Uint8Array(dest.buffer, dest.byteOffset + (destOffset || 0), length)
: new Uint8Array(dest, destOffset, length);
var ua8Src = 'buffer' in src
? new Uint8Array(src.buffer, src.byteOffset + (srcOffset || 0), length)
: new Uint8Array(src, srcOffset, length);
ua8Dest.set(ua8Src);
}
export function allocatePartialBinary(binBase, offset, length) {
var b = new ArrayBuffer(length);
copyBuffer(b, 0, binBase, offset, length);
return b;
}
export 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;
}
}
export function getFixedString(view, offset, length) {
var actualLen = 0;
for (var i = 0; i < length; ++i) {
if (view.getUint8(offset + i) === 0) {
break;
}
++actualLen;
}
if (typeof Buffer !== 'undefined') {
return Buffer.from(view.buffer, view.byteOffset + offset, actualLen).toString('utf8');
}
else if (typeof decodeURIComponent !== 'undefined') {
var s = '';
for (var i = 0; i < actualLen; ++i) {
var c = view.getUint8(offset + i);
if (c < 16) {
s += '%0' + c.toString(16);
}
else {
s += '%' + c.toString(16);
}
}
return decodeURIComponent(s);
}
else {
var s = '';
for (var i = 0; i < actualLen; ++i) {
var c = view.getUint8(offset + i);
s += String.fromCharCode(c);
}
return s;
}
}
export function setFixedString(view, offset, length, text) {
if (typeof Buffer !== 'undefined') {
var u = new Uint8Array(view.buffer, view.byteOffset + offset, length);
// fill by zero
u.set(new Uint8Array(length));
u.set(Buffer.from(text, 'utf8').subarray(0, length));
}
else if (typeof encodeURIComponent !== 'undefined') {
var s = encodeURIComponent(text);
for (var i = 0, j = 0; i < length; ++i) {
if (j >= s.length) {
view.setUint8(i + offset, 0);
}
else {
var c = s.charCodeAt(j);
if (c === 37) {
// '%'
var n = parseInt(s.substr(j + 1, 2), 16);
if (typeof n === 'number' && !isNaN(n)) {
view.setUint8(i + offset, n);
}
else {
view.setUint8(i + offset, 0);
}
j += 3;
}
else {
view.setUint8(i + offset, c);
}
}
}
}
else {
for (var i = 0, j = 0; i < length; ++i) {
if (j >= text.length) {
view.setUint8(i + offset, 0);
}
else {
var c = text.charCodeAt(j);
view.setUint8(i + offset, c & 0xff);
}
}
}
}
export function binaryToString(bin) {
if (typeof TextDecoder !== 'undefined') {
var dec = new TextDecoder();
return dec.decode(bin);
}
else if (typeof Buffer !== 'undefined') {
var b = void 0;
if ('buffer' in bin) {
b = Buffer.from(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
b = Buffer.from(bin);
}
return b.toString('utf8');
}
else {
var view = void 0;
if ('buffer' in bin) {
view = new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
view = new Uint8Array(bin);
}
if (typeof decodeURIComponent !== 'undefined') {
var s = '';
for (var i = 0; i < view.length; ++i) {
var c = view[i];
if (c < 16) {
s += '%0' + c.toString(16);
}
else {
s += '%' + c.toString(16);
}
}
return decodeURIComponent(s);
}
else {
var s = '';
for (var i = 0; i < view.length; ++i) {
var c = view[i];
s += String.fromCharCode(c);
}
return s;
}
}
}
export function stringToBinary(string) {
if (typeof TextEncoder !== 'undefined') {
var enc = new TextEncoder();
return cloneToArrayBuffer(enc.encode(string));
}
else if (typeof Buffer !== 'undefined') {
return cloneToArrayBuffer(Buffer.from(string, 'utf8'));
}
else if (typeof encodeURIComponent !== 'undefined') {
var data = encodeURIComponent(string);
var len = 0;
for (var i = 0; i < data.length; ++len) {
var c = data.charCodeAt(i);
if (c === 37) {
i += 3;
}
else {
++i;
}
}
var bin = new ArrayBuffer(len);
var view = new Uint8Array(bin);
for (var i = 0, j = 0; i < data.length; ++j) {
var c = data.charCodeAt(i);
if (c === 37) {
var n = parseInt(data.substring(i + 1, i + 3), 16);
view[j] = n;
i += 3;
}
else {
view[j] = c;
++i;
}
}
return bin;
}
else {
var bin = new ArrayBuffer(string.length);
new Uint8Array(bin).set([].map.call(string, function (c) {
return c.charCodeAt(0);
}));
return bin;
}
}

View File

@@ -0,0 +1,5 @@
export declare function getDosStubDataSize(): number;
export declare function fillDosStubData(bin: ArrayBuffer | ArrayBufferView): void;
export declare function estimateNewHeaderSize(is32Bit: boolean): number;
export declare function fillPeHeaderEmptyData(bin: ArrayBuffer | ArrayBufferView, offset: number, totalBinSize: number, is32Bit: boolean, isDLL: boolean): void;
export declare function makeEmptyNtExecutableBinary(is32Bit: boolean, isDLL: boolean): ArrayBuffer;

View File

@@ -0,0 +1,119 @@
// To make the binary (DOS_STUB_PROGRAM):
// $ cd tools/dos-stub
// $ nasm -f bin -o dos-stub.bin dos-stub.asm
// $ node -e "console.log([].map.call(fs.readFileSync('tools/dos-stub/dos-stub.bin'), (v)=>`0x${Buffer.from([v]).toString('hex')}`).join(','))"
//
// NOTE: the original dos-stub.asm program and the bit code in DOS_STUB_PROGRAM are under the 0-BSD license.
import ImageDataDirectoryArray from '../format/ImageDataDirectoryArray.js';
import ImageDosHeader from '../format/ImageDosHeader.js';
import ImageFileHeader from '../format/ImageFileHeader.js';
import ImageNtHeaders from '../format/ImageNtHeaders.js';
import ImageOptionalHeader from '../format/ImageOptionalHeader.js';
import ImageOptionalHeader64 from '../format/ImageOptionalHeader64.js';
import { copyBuffer, roundUp } from './functions.js';
// fill with '0x00' to make 8-bytes alignment
// prettier-ignore
var DOS_STUB_PROGRAM = new Uint8Array([
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x44, 0x4f,
0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f,
0x72, 0x74, 0x65, 0x64, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);
var DOS_STUB_SIZE = roundUp(ImageDosHeader.size + DOS_STUB_PROGRAM.length, 0x80);
var DEFAULT_FILE_ALIGNMENT = 512;
export function getDosStubDataSize() {
return DOS_STUB_SIZE;
}
export function fillDosStubData(bin) {
var dos = ImageDosHeader.from(bin);
dos.magic = ImageDosHeader.DEFAULT_MAGIC;
// last page size
dos.lastPageSize = DOS_STUB_SIZE % 512;
// total page count
dos.pages = Math.ceil(DOS_STUB_SIZE / 512);
// no relocations
dos.relocations = 0;
// header size as paragraph count (1 paragraph = 16 bytes)
dos.headerSizeInParagraph = Math.ceil(ImageDosHeader.size / 16);
dos.minAllocParagraphs = 0;
dos.maxAllocParagraphs = 0xffff;
dos.initialSS = 0;
dos.initialSP = 0x80;
// (no relocations, but set offset after the header)
dos.relocationTableAddress = ImageDosHeader.size;
dos.newHeaderAddress = DOS_STUB_SIZE;
copyBuffer(bin, ImageDosHeader.size, DOS_STUB_PROGRAM, 0, DOS_STUB_PROGRAM.length);
}
export function estimateNewHeaderSize(is32Bit) {
return (
// magic
4 +
ImageFileHeader.size +
(is32Bit ? ImageOptionalHeader.size : ImageOptionalHeader64.size) +
ImageDataDirectoryArray.size);
}
export function fillPeHeaderEmptyData(bin, offset, totalBinSize, is32Bit, isDLL) {
var _bin;
var _offset;
if ('buffer' in bin) {
_bin = bin.buffer;
_offset = bin.byteOffset + offset;
}
else {
_bin = bin;
_offset = offset;
}
new DataView(_bin, _offset).setUint32(0, ImageNtHeaders.DEFAULT_SIGNATURE, true);
var fh = ImageFileHeader.from(_bin, _offset + 4);
fh.machine = is32Bit ? 0x14c : 0x8664;
fh.numberOfSections = 0; // no sections
fh.timeDateStamp = 0;
fh.pointerToSymbolTable = 0;
fh.numberOfSymbols = 0;
fh.sizeOfOptionalHeader =
(is32Bit ? ImageOptionalHeader.size : ImageOptionalHeader64.size) +
ImageDataDirectoryArray.size;
fh.characteristics = isDLL ? 0x2102 : 0x102;
var oh = (is32Bit ? ImageOptionalHeader : ImageOptionalHeader64).from(_bin, _offset + 4 + ImageFileHeader.size);
oh.magic = is32Bit
? ImageOptionalHeader.DEFAULT_MAGIC
: ImageOptionalHeader64.DEFAULT_MAGIC;
// oh.majorLinkerVersion = 0;
// oh.minorLinkerVersion = 0;
oh.sizeOfCode = 0;
oh.sizeOfInitializedData = 0;
oh.sizeOfUninitializedData = 0;
oh.addressOfEntryPoint = 0;
oh.baseOfCode = 0x1000;
// oh.baseOfData = 0; // for 32bit only
oh.imageBase = is32Bit ? 0x1000000 : 0x180000000;
oh.sectionAlignment = 4096;
oh.fileAlignment = DEFAULT_FILE_ALIGNMENT;
oh.majorOperatingSystemVersion = 6;
oh.minorOperatingSystemVersion = 0;
// oh.majorImageVersion = 0;
// oh.minorImageVersion = 0;
oh.majorSubsystemVersion = 6;
oh.minorSubsystemVersion = 0;
// oh.win32VersionValue = 0;
oh.sizeOfHeaders = roundUp(totalBinSize, oh.fileAlignment);
// oh.checkSum = 0;
oh.subsystem = 2; // IMAGE_SUBSYSTEM_WINDOWS_GUI
oh.dllCharacteristics =
(is32Bit ? 0 : 0x20) + // IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
0x40 + // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
0x100; // IMAGE_DLLCHARACTERISTICS_NX_COMPAT
oh.sizeOfStackReserve = 0x100000;
oh.sizeOfStackCommit = 0x1000;
oh.sizeOfHeapReserve = 0x100000;
oh.sizeOfHeapCommit = 0x1000;
// oh.loaderFlags = 0;
oh.numberOfRvaAndSizes =
ImageDataDirectoryArray.size / ImageDataDirectoryArray.itemSize;
}
export function makeEmptyNtExecutableBinary(is32Bit, isDLL) {
var bufferSize = roundUp(DOS_STUB_SIZE + estimateNewHeaderSize(is32Bit), DEFAULT_FILE_ALIGNMENT);
var bin = new ArrayBuffer(bufferSize);
fillDosStubData(bin);
fillPeHeaderEmptyData(bin, DOS_STUB_SIZE, bufferSize, is32Bit, isDLL);
return bin;
}

View File

@@ -0,0 +1,2 @@
declare const _default: "0.4.1";
export default _default;

View File

@@ -0,0 +1 @@
export default '0.4.1';

View File

@@ -0,0 +1,14 @@
import FormatBase from './FormatBase.js';
/** abstract class that support array-like methods and 'for...of' operation */
declare abstract class ArrayFormatBase<T> extends FormatBase {
protected constructor(view: DataView);
abstract readonly length: number;
abstract get(index: number): Readonly<T>;
abstract set(index: number, data: T): void;
forEach(callback: (value: T, index: number, base: this) => void): void;
_iterator(): Iterator<Readonly<T>>;
}
interface ArrayFormatBase<T> {
[Symbol.iterator]: () => Iterator<Readonly<T>>;
}
export default ArrayFormatBase;

View File

@@ -0,0 +1,66 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase_js_1 = require("./FormatBase.js");
/** abstract class that support array-like methods and 'for...of' operation */
var ArrayFormatBase = /** @class */ (function (_super) {
__extends(ArrayFormatBase, _super);
function ArrayFormatBase(view) {
return _super.call(this, view) || this;
}
ArrayFormatBase.prototype.forEach = function (callback) {
var len = this.length;
var a = [];
a.length = len;
for (var i = 0; i < len; ++i) {
a[i] = this.get(i);
}
for (var i = 0; i < len; ++i) {
callback(a[i], i, this);
}
};
ArrayFormatBase.prototype._iterator = function () {
return new (/** @class */ (function () {
function class_1(base) {
this.base = base;
this.i = 0;
}
class_1.prototype.next = function () {
if (this.i === this.base.length) {
return {
value: undefined,
done: true,
};
}
else {
return {
value: this.base.get(this.i++),
done: false,
};
}
};
return class_1;
}()))(this);
};
return ArrayFormatBase;
}(FormatBase_js_1.default));
/* istanbul ignore else */
if (typeof Symbol !== 'undefined') {
ArrayFormatBase.prototype[Symbol.iterator] =
ArrayFormatBase.prototype._iterator;
}
exports.default = ArrayFormatBase;

View File

@@ -0,0 +1,6 @@
export default abstract class FormatBase {
protected readonly view: DataView;
protected constructor(view: DataView);
copyTo(bin: ArrayBuffer, offset: number): void;
get byteLength(): number;
}

View File

@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase = /** @class */ (function () {
function FormatBase(view) {
this.view = view;
}
FormatBase.prototype.copyTo = function (bin, offset) {
new Uint8Array(bin, offset, this.view.byteLength).set(new Uint8Array(this.view.buffer, this.view.byteOffset, this.view.byteLength));
};
Object.defineProperty(FormatBase.prototype, "byteLength", {
get: function () {
return this.view.byteLength;
},
enumerable: false,
configurable: true
});
return FormatBase;
}());
exports.default = FormatBase;

View File

@@ -0,0 +1,16 @@
import ArrayFormatBase from './ArrayFormatBase.js';
export interface ImageDataDirectory {
virtualAddress: number;
size: number;
}
export default class ImageDataDirectoryArray extends ArrayFormatBase<ImageDataDirectory> {
static readonly size = 128;
static readonly itemSize = 8;
readonly length = 16;
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;
get(index: number): Readonly<ImageDataDirectory>;
set(index: number, data: ImageDataDirectory): void;
findIndexByVirtualAddress(virtualAddress: number): number | null;
}

View File

@@ -0,0 +1,55 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ArrayFormatBase_js_1 = require("./ArrayFormatBase.js");
var ImageDataDirectoryArray = /** @class */ (function (_super) {
__extends(ImageDataDirectoryArray, _super);
function ImageDataDirectoryArray(view) {
var _this = _super.call(this, view) || this;
_this.length = 16;
return _this;
}
/** @note This does not clone binary data; the changes to the array will modify the specified buffer `bin` */
ImageDataDirectoryArray.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageDataDirectoryArray(new DataView(bin, offset, 128));
};
ImageDataDirectoryArray.prototype.get = function (index) {
return {
virtualAddress: this.view.getUint32(index * 8, true),
size: this.view.getUint32(4 + index * 8, true),
};
};
ImageDataDirectoryArray.prototype.set = function (index, data) {
this.view.setUint32(index * 8, data.virtualAddress, true);
this.view.setUint32(4 + index * 8, data.size, true);
};
ImageDataDirectoryArray.prototype.findIndexByVirtualAddress = function (virtualAddress) {
for (var i = 0; i < 16; ++i) {
var va = this.view.getUint32(i * 8, true);
var vs = this.view.getUint32(4 + i * 8, true);
if (virtualAddress >= va && virtualAddress < va + vs) {
return i;
}
}
return null;
};
ImageDataDirectoryArray.size = 128; // 16 * 8
ImageDataDirectoryArray.itemSize = 8;
return ImageDataDirectoryArray;
}(ArrayFormatBase_js_1.default));
exports.default = ImageDataDirectoryArray;

View File

@@ -0,0 +1,22 @@
declare enum ImageDirectoryEntry {
Export = 0,
Import = 1,
Resource = 2,
Exception = 3,
Certificate = 4,
Security = 4,
BaseRelocation = 5,
Debug = 6,
Architecture = 7,
GlobalPointer = 8,
Tls = 9,
TLS = 9,
LoadConfig = 10,
BoundImport = 11,
Iat = 12,
IAT = 12,
DelayImport = 13,
ComDescriptor = 14,
COMDescriptor = 14
}
export default ImageDirectoryEntry;

View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ImageDirectoryEntry;
(function (ImageDirectoryEntry) {
ImageDirectoryEntry[ImageDirectoryEntry["Export"] = 0] = "Export";
ImageDirectoryEntry[ImageDirectoryEntry["Import"] = 1] = "Import";
ImageDirectoryEntry[ImageDirectoryEntry["Resource"] = 2] = "Resource";
ImageDirectoryEntry[ImageDirectoryEntry["Exception"] = 3] = "Exception";
ImageDirectoryEntry[ImageDirectoryEntry["Certificate"] = 4] = "Certificate";
// alias
ImageDirectoryEntry[ImageDirectoryEntry["Security"] = 4] = "Security";
ImageDirectoryEntry[ImageDirectoryEntry["BaseRelocation"] = 5] = "BaseRelocation";
ImageDirectoryEntry[ImageDirectoryEntry["Debug"] = 6] = "Debug";
ImageDirectoryEntry[ImageDirectoryEntry["Architecture"] = 7] = "Architecture";
ImageDirectoryEntry[ImageDirectoryEntry["GlobalPointer"] = 8] = "GlobalPointer";
ImageDirectoryEntry[ImageDirectoryEntry["Tls"] = 9] = "Tls";
ImageDirectoryEntry[ImageDirectoryEntry["TLS"] = 9] = "TLS";
ImageDirectoryEntry[ImageDirectoryEntry["LoadConfig"] = 10] = "LoadConfig";
ImageDirectoryEntry[ImageDirectoryEntry["BoundImport"] = 11] = "BoundImport";
ImageDirectoryEntry[ImageDirectoryEntry["Iat"] = 12] = "Iat";
ImageDirectoryEntry[ImageDirectoryEntry["IAT"] = 12] = "IAT";
ImageDirectoryEntry[ImageDirectoryEntry["DelayImport"] = 13] = "DelayImport";
ImageDirectoryEntry[ImageDirectoryEntry["ComDescriptor"] = 14] = "ComDescriptor";
ImageDirectoryEntry[ImageDirectoryEntry["COMDescriptor"] = 14] = "COMDescriptor";
})(ImageDirectoryEntry || (ImageDirectoryEntry = {}));
exports.default = ImageDirectoryEntry;

View File

@@ -0,0 +1,42 @@
import FormatBase from './FormatBase.js';
export default class ImageDosHeader extends FormatBase {
static readonly size = 64;
static readonly DEFAULT_MAGIC = 23117;
private constructor();
static from(bin: ArrayBuffer | ArrayBufferView, offset?: number): ImageDosHeader;
isValid(): boolean;
get magic(): number;
set magic(val: number);
get lastPageSize(): number;
set lastPageSize(val: number);
get pages(): number;
set pages(val: number);
get relocations(): number;
set relocations(val: number);
get headerSizeInParagraph(): number;
set headerSizeInParagraph(val: number);
get minAllocParagraphs(): number;
set minAllocParagraphs(val: number);
get maxAllocParagraphs(): number;
set maxAllocParagraphs(val: number);
get initialSS(): number;
set initialSS(val: number);
get initialSP(): number;
set initialSP(val: number);
get checkSum(): number;
set checkSum(val: number);
get initialIP(): number;
set initialIP(val: number);
get initialCS(): number;
set initialCS(val: number);
get relocationTableAddress(): number;
set relocationTableAddress(val: number);
get overlayNum(): number;
set overlayNum(val: number);
get oemId(): number;
set oemId(val: number);
get oemInfo(): number;
set oemInfo(val: number);
get newHeaderAddress(): number;
set newHeaderAddress(val: number);
}

View File

@@ -0,0 +1,208 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase_js_1 = require("./FormatBase.js");
var functions_js_1 = require("../util/functions.js");
var ImageDosHeader = /** @class */ (function (_super) {
__extends(ImageDosHeader, _super);
function ImageDosHeader(view) {
return _super.call(this, view) || this;
}
ImageDosHeader.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageDosHeader(functions_js_1.createDataView(bin, offset, 64));
};
ImageDosHeader.prototype.isValid = function () {
return this.magic === ImageDosHeader.DEFAULT_MAGIC;
};
Object.defineProperty(ImageDosHeader.prototype, "magic", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "lastPageSize", {
get: function () {
return this.view.getUint16(2, true);
},
set: function (val) {
this.view.setUint16(2, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "pages", {
get: function () {
return this.view.getUint16(4, true);
},
set: function (val) {
this.view.setUint16(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "relocations", {
get: function () {
return this.view.getUint16(6, true);
},
set: function (val) {
this.view.setUint16(6, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "headerSizeInParagraph", {
get: function () {
return this.view.getUint16(8, true);
},
set: function (val) {
this.view.setUint16(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "minAllocParagraphs", {
get: function () {
return this.view.getUint16(10, true);
},
set: function (val) {
this.view.setUint16(10, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "maxAllocParagraphs", {
get: function () {
return this.view.getUint16(12, true);
},
set: function (val) {
this.view.setUint16(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialSS", {
get: function () {
return this.view.getUint16(14, true);
},
set: function (val) {
this.view.setUint16(14, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialSP", {
get: function () {
return this.view.getUint16(16, true);
},
set: function (val) {
this.view.setUint16(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "checkSum", {
get: function () {
return this.view.getUint16(18, true);
},
set: function (val) {
this.view.setUint16(18, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialIP", {
get: function () {
return this.view.getUint16(20, true);
},
set: function (val) {
this.view.setUint16(20, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "initialCS", {
get: function () {
return this.view.getUint16(22, true);
},
set: function (val) {
this.view.setUint16(22, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "relocationTableAddress", {
get: function () {
return this.view.getUint16(24, true);
},
set: function (val) {
this.view.setUint16(24, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "overlayNum", {
get: function () {
return this.view.getUint16(26, true);
},
set: function (val) {
this.view.setUint16(26, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "oemId", {
// WORD e_res[4] (28,30,32,34)
get: function () {
return this.view.getUint16(36, true);
},
set: function (val) {
this.view.setUint16(36, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "oemInfo", {
get: function () {
return this.view.getUint16(38, true);
},
set: function (val) {
this.view.setUint16(38, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageDosHeader.prototype, "newHeaderAddress", {
// WORD e_res2[10] (40,42,44,46,48,50,52,54,56,58)
get: function () {
return this.view.getUint32(60, true);
},
set: function (val) {
this.view.setUint32(60, val, true);
},
enumerable: false,
configurable: true
});
ImageDosHeader.size = 64;
ImageDosHeader.DEFAULT_MAGIC = 0x5a4d; // 'MZ'
return ImageDosHeader;
}(FormatBase_js_1.default));
exports.default = ImageDosHeader;

View File

@@ -0,0 +1,20 @@
import FormatBase from './FormatBase.js';
export default class ImageFileHeader extends FormatBase {
static readonly size = 20;
private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageFileHeader;
get machine(): number;
set machine(val: number);
get numberOfSections(): number;
set numberOfSections(val: number);
get timeDateStamp(): number;
set timeDateStamp(val: number);
get pointerToSymbolTable(): number;
set pointerToSymbolTable(val: number);
get numberOfSymbols(): number;
set numberOfSymbols(val: number);
get sizeOfOptionalHeader(): number;
set sizeOfOptionalHeader(val: number);
get characteristics(): number;
set characteristics(val: number);
}

View File

@@ -0,0 +1,101 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase_js_1 = require("./FormatBase.js");
var ImageFileHeader = /** @class */ (function (_super) {
__extends(ImageFileHeader, _super);
function ImageFileHeader(view) {
return _super.call(this, view) || this;
}
ImageFileHeader.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageFileHeader(new DataView(bin, offset, 20));
};
Object.defineProperty(ImageFileHeader.prototype, "machine", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "numberOfSections", {
get: function () {
return this.view.getUint16(2, true);
},
set: function (val) {
this.view.setUint16(2, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "timeDateStamp", {
get: function () {
return this.view.getUint32(4, true);
},
set: function (val) {
this.view.setUint32(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "pointerToSymbolTable", {
get: function () {
return this.view.getUint32(8, true);
},
set: function (val) {
this.view.setUint32(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "numberOfSymbols", {
get: function () {
return this.view.getUint32(12, true);
},
set: function (val) {
this.view.setUint32(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "sizeOfOptionalHeader", {
get: function () {
return this.view.getUint16(16, true);
},
set: function (val) {
this.view.setUint16(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageFileHeader.prototype, "characteristics", {
get: function () {
return this.view.getUint16(18, true);
},
set: function (val) {
this.view.setUint16(18, val, true);
},
enumerable: false,
configurable: true
});
ImageFileHeader.size = 20;
return ImageFileHeader;
}(FormatBase_js_1.default));
exports.default = ImageFileHeader;

View File

@@ -0,0 +1,19 @@
import FormatBase from './FormatBase.js';
import ImageFileHeader from './ImageFileHeader.js';
import ImageOptionalHeader from './ImageOptionalHeader.js';
import ImageOptionalHeader64 from './ImageOptionalHeader64.js';
import ImageDataDirectoryArray from './ImageDataDirectoryArray.js';
export default class ImageNtHeaders extends FormatBase {
static readonly DEFAULT_SIGNATURE = 17744;
private constructor();
static from(bin: ArrayBuffer | ArrayBufferView, offset?: number): ImageNtHeaders;
isValid(): boolean;
is32bit(): boolean;
get signature(): number;
set signature(val: number);
get fileHeader(): ImageFileHeader;
get optionalHeader(): ImageOptionalHeader | ImageOptionalHeader64;
get optionalHeaderDataDirectory(): ImageDataDirectoryArray;
getDataDirectoryOffset(): number;
getSectionHeaderOffset(): number;
}

View File

@@ -0,0 +1,103 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase_js_1 = require("./FormatBase.js");
var ImageFileHeader_js_1 = require("./ImageFileHeader.js");
var ImageOptionalHeader_js_1 = require("./ImageOptionalHeader.js");
var ImageOptionalHeader64_js_1 = require("./ImageOptionalHeader64.js");
var ImageDataDirectoryArray_js_1 = require("./ImageDataDirectoryArray.js");
var functions_js_1 = require("../util/functions.js");
var ImageNtHeaders = /** @class */ (function (_super) {
__extends(ImageNtHeaders, _super);
function ImageNtHeaders(view) {
return _super.call(this, view) || this;
}
ImageNtHeaders.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
var magic = functions_js_1.createDataView(bin, offset + ImageFileHeader_js_1.default.size, 6).getUint16(4, true);
var len = 4 + ImageFileHeader_js_1.default.size + ImageDataDirectoryArray_js_1.default.size;
if (magic === ImageOptionalHeader64_js_1.default.DEFAULT_MAGIC) {
len += ImageOptionalHeader64_js_1.default.size;
}
else {
len += ImageOptionalHeader_js_1.default.size;
}
return new ImageNtHeaders(functions_js_1.createDataView(bin, offset, len));
};
ImageNtHeaders.prototype.isValid = function () {
return this.signature === ImageNtHeaders.DEFAULT_SIGNATURE;
};
ImageNtHeaders.prototype.is32bit = function () {
return (this.view.getUint16(ImageFileHeader_js_1.default.size + 4, true) ===
ImageOptionalHeader_js_1.default.DEFAULT_MAGIC);
};
Object.defineProperty(ImageNtHeaders.prototype, "signature", {
get: function () {
return this.view.getUint32(0, true);
},
set: function (val) {
this.view.setUint32(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageNtHeaders.prototype, "fileHeader", {
get: function () {
return ImageFileHeader_js_1.default.from(this.view.buffer, this.view.byteOffset + 4);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageNtHeaders.prototype, "optionalHeader", {
get: function () {
var off = ImageFileHeader_js_1.default.size + 4;
var magic = this.view.getUint16(off, true);
if (magic === ImageOptionalHeader64_js_1.default.DEFAULT_MAGIC) {
return ImageOptionalHeader64_js_1.default.from(this.view.buffer, this.view.byteOffset + off);
}
else {
return ImageOptionalHeader_js_1.default.from(this.view.buffer, this.view.byteOffset + off);
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageNtHeaders.prototype, "optionalHeaderDataDirectory", {
get: function () {
return ImageDataDirectoryArray_js_1.default.from(this.view.buffer, this.view.byteOffset + this.getDataDirectoryOffset());
},
enumerable: false,
configurable: true
});
ImageNtHeaders.prototype.getDataDirectoryOffset = function () {
var off = ImageFileHeader_js_1.default.size + 4;
var magic = this.view.getUint16(off, true);
if (magic === ImageOptionalHeader64_js_1.default.DEFAULT_MAGIC) {
off += ImageOptionalHeader64_js_1.default.size;
}
else {
off += ImageOptionalHeader_js_1.default.size;
}
return off;
};
ImageNtHeaders.prototype.getSectionHeaderOffset = function () {
return this.getDataDirectoryOffset() + ImageDataDirectoryArray_js_1.default.size;
};
ImageNtHeaders.DEFAULT_SIGNATURE = 0x4550; // 'PE\x00\x00'
return ImageNtHeaders;
}(FormatBase_js_1.default));
exports.default = ImageNtHeaders;

View File

@@ -0,0 +1,67 @@
import FormatBase from './FormatBase.js';
export default class ImageOptionalHeader extends FormatBase {
static readonly size = 96;
static readonly DEFAULT_MAGIC = 267;
private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageOptionalHeader;
get magic(): number;
set magic(val: number);
get majorLinkerVersion(): number;
set majorLinkerVersion(val: number);
get minorLinkerVersion(): number;
set minorLinkerVersion(val: number);
get sizeOfCode(): number;
set sizeOfCode(val: number);
get sizeOfInitializedData(): number;
set sizeOfInitializedData(val: number);
get sizeOfUninitializedData(): number;
set sizeOfUninitializedData(val: number);
get addressOfEntryPoint(): number;
set addressOfEntryPoint(val: number);
get baseOfCode(): number;
set baseOfCode(val: number);
get baseOfData(): number;
set baseOfData(val: number);
get imageBase(): number;
set imageBase(val: number);
get sectionAlignment(): number;
set sectionAlignment(val: number);
get fileAlignment(): number;
set fileAlignment(val: number);
get majorOperatingSystemVersion(): number;
set majorOperatingSystemVersion(val: number);
get minorOperatingSystemVersion(): number;
set minorOperatingSystemVersion(val: number);
get majorImageVersion(): number;
set majorImageVersion(val: number);
get minorImageVersion(): number;
set minorImageVersion(val: number);
get majorSubsystemVersion(): number;
set majorSubsystemVersion(val: number);
get minorSubsystemVersion(): number;
set minorSubsystemVersion(val: number);
get win32VersionValue(): number;
set win32VersionValue(val: number);
get sizeOfImage(): number;
set sizeOfImage(val: number);
get sizeOfHeaders(): number;
set sizeOfHeaders(val: number);
get checkSum(): number;
set checkSum(val: number);
get subsystem(): number;
set subsystem(val: number);
get dllCharacteristics(): number;
set dllCharacteristics(val: number);
get sizeOfStackReserve(): number;
set sizeOfStackReserve(val: number);
get sizeOfStackCommit(): number;
set sizeOfStackCommit(val: number);
get sizeOfHeapReserve(): number;
set sizeOfHeapReserve(val: number);
get sizeOfHeapCommit(): number;
set sizeOfHeapCommit(val: number);
get loaderFlags(): number;
set loaderFlags(val: number);
get numberOfRvaAndSizes(): number;
set numberOfRvaAndSizes(val: number);
}

View File

@@ -0,0 +1,332 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase_js_1 = require("./FormatBase.js");
var ImageOptionalHeader = /** @class */ (function (_super) {
__extends(ImageOptionalHeader, _super);
function ImageOptionalHeader(view) {
return _super.call(this, view) || this;
}
ImageOptionalHeader.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageOptionalHeader(new DataView(bin, offset, 96));
};
Object.defineProperty(ImageOptionalHeader.prototype, "magic", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorLinkerVersion", {
get: function () {
return this.view.getUint8(2);
},
set: function (val) {
this.view.setUint8(2, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorLinkerVersion", {
get: function () {
return this.view.getUint8(3);
},
set: function (val) {
this.view.setUint8(3, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfCode", {
get: function () {
return this.view.getUint32(4, true);
},
set: function (val) {
this.view.setUint32(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfInitializedData", {
get: function () {
return this.view.getUint32(8, true);
},
set: function (val) {
this.view.setUint32(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfUninitializedData", {
get: function () {
return this.view.getUint32(12, true);
},
set: function (val) {
this.view.setUint32(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "addressOfEntryPoint", {
get: function () {
return this.view.getUint32(16, true);
},
set: function (val) {
this.view.setUint32(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "baseOfCode", {
get: function () {
return this.view.getUint32(20, true);
},
set: function (val) {
this.view.setUint32(20, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "baseOfData", {
get: function () {
return this.view.getUint32(24, true);
},
set: function (val) {
this.view.setUint32(24, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "imageBase", {
get: function () {
return this.view.getUint32(28, true);
},
set: function (val) {
this.view.setUint32(28, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sectionAlignment", {
get: function () {
return this.view.getUint32(32, true);
},
set: function (val) {
this.view.setUint32(32, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "fileAlignment", {
get: function () {
return this.view.getUint32(36, true);
},
set: function (val) {
this.view.setUint32(36, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(40, true);
},
set: function (val) {
this.view.setUint16(40, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(42, true);
},
set: function (val) {
this.view.setUint16(42, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorImageVersion", {
get: function () {
return this.view.getUint16(44, true);
},
set: function (val) {
this.view.setUint16(44, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorImageVersion", {
get: function () {
return this.view.getUint16(46, true);
},
set: function (val) {
this.view.setUint16(46, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "majorSubsystemVersion", {
get: function () {
return this.view.getUint16(48, true);
},
set: function (val) {
this.view.setUint16(48, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "minorSubsystemVersion", {
get: function () {
return this.view.getUint16(50, true);
},
set: function (val) {
this.view.setUint16(50, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "win32VersionValue", {
get: function () {
return this.view.getUint32(52, true);
},
set: function (val) {
this.view.setUint32(52, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfImage", {
get: function () {
return this.view.getUint32(56, true);
},
set: function (val) {
this.view.setUint32(56, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfHeaders", {
get: function () {
return this.view.getUint32(60, true);
},
set: function (val) {
this.view.setUint32(60, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "checkSum", {
get: function () {
return this.view.getUint32(64, true);
},
set: function (val) {
this.view.setUint32(64, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "subsystem", {
get: function () {
return this.view.getUint16(68, true);
},
set: function (val) {
this.view.setUint16(68, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "dllCharacteristics", {
get: function () {
return this.view.getUint16(70, true);
},
set: function (val) {
this.view.setUint16(70, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfStackReserve", {
get: function () {
return this.view.getUint32(72, true);
},
set: function (val) {
this.view.setUint32(72, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfStackCommit", {
get: function () {
return this.view.getUint32(76, true);
},
set: function (val) {
this.view.setUint32(76, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfHeapReserve", {
get: function () {
return this.view.getUint32(80, true);
},
set: function (val) {
this.view.setUint32(80, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "sizeOfHeapCommit", {
get: function () {
return this.view.getUint32(84, true);
},
set: function (val) {
this.view.setUint32(84, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "loaderFlags", {
get: function () {
return this.view.getUint32(88, true);
},
set: function (val) {
this.view.setUint32(88, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader.prototype, "numberOfRvaAndSizes", {
get: function () {
return this.view.getUint32(92, true);
},
set: function (val) {
this.view.setUint32(92, val, true);
},
enumerable: false,
configurable: true
});
ImageOptionalHeader.size = 96;
ImageOptionalHeader.DEFAULT_MAGIC = 0x10b;
return ImageOptionalHeader;
}(FormatBase_js_1.default));
exports.default = ImageOptionalHeader;

View File

@@ -0,0 +1,75 @@
import FormatBase from './FormatBase.js';
export default class ImageOptionalHeader64 extends FormatBase {
static readonly size = 112;
static readonly DEFAULT_MAGIC = 523;
private constructor();
static from(bin: ArrayBuffer, offset?: number): ImageOptionalHeader64;
get magic(): number;
set magic(val: number);
get majorLinkerVersion(): number;
set majorLinkerVersion(val: number);
get minorLinkerVersion(): number;
set minorLinkerVersion(val: number);
get sizeOfCode(): number;
set sizeOfCode(val: number);
get sizeOfInitializedData(): number;
set sizeOfInitializedData(val: number);
get sizeOfUninitializedData(): number;
set sizeOfUninitializedData(val: number);
get addressOfEntryPoint(): number;
set addressOfEntryPoint(val: number);
get baseOfCode(): number;
set baseOfCode(val: number);
get imageBase(): number;
set imageBase(val: number);
get imageBaseBigInt(): bigint;
set imageBaseBigInt(val: bigint);
get sectionAlignment(): number;
set sectionAlignment(val: number);
get fileAlignment(): number;
set fileAlignment(val: number);
get majorOperatingSystemVersion(): number;
set majorOperatingSystemVersion(val: number);
get minorOperatingSystemVersion(): number;
set minorOperatingSystemVersion(val: number);
get majorImageVersion(): number;
set majorImageVersion(val: number);
get minorImageVersion(): number;
set minorImageVersion(val: number);
get majorSubsystemVersion(): number;
set majorSubsystemVersion(val: number);
get minorSubsystemVersion(): number;
set minorSubsystemVersion(val: number);
get win32VersionValue(): number;
set win32VersionValue(val: number);
get sizeOfImage(): number;
set sizeOfImage(val: number);
get sizeOfHeaders(): number;
set sizeOfHeaders(val: number);
get checkSum(): number;
set checkSum(val: number);
get subsystem(): number;
set subsystem(val: number);
get dllCharacteristics(): number;
set dllCharacteristics(val: number);
get sizeOfStackReserve(): number;
set sizeOfStackReserve(val: number);
get sizeOfStackReserveBigInt(): bigint;
set sizeOfStackReserveBigInt(val: bigint);
get sizeOfStackCommit(): number;
set sizeOfStackCommit(val: number);
get sizeOfStackCommitBigInt(): bigint;
set sizeOfStackCommitBigInt(val: bigint);
get sizeOfHeapReserve(): number;
set sizeOfHeapReserve(val: number);
get sizeOfHeapReserveBigInt(): bigint;
set sizeOfHeapReserveBigInt(val: bigint);
get sizeOfHeapCommit(): number;
set sizeOfHeapCommit(val: number);
get sizeOfHeapCommitBigInt(): bigint;
set sizeOfHeapCommitBigInt(val: bigint);
get loaderFlags(): number;
set loaderFlags(val: number);
get numberOfRvaAndSizes(): number;
set numberOfRvaAndSizes(val: number);
}

View File

@@ -0,0 +1,396 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var FormatBase_js_1 = require("./FormatBase.js");
function getUint64LE(view, offset) {
return (view.getUint32(offset + 4, true) * 0x100000000 +
view.getUint32(offset, true));
}
function setUint64LE(view, offset, val) {
view.setUint32(offset, val & 0xffffffff, true);
view.setUint32(offset + 4, Math.floor(val / 0x100000000), true);
}
function getUint64LEBigInt(view, offset) {
/* istanbul ignore if */
if (typeof BigInt === 'undefined') {
throw new Error('BigInt not supported');
}
return (BigInt(0x100000000) * BigInt(view.getUint32(offset + 4, true)) +
BigInt(view.getUint32(offset, true)));
}
function setUint64LEBigInt(view, offset, val) {
/* istanbul ignore if */
if (typeof BigInt === 'undefined') {
throw new Error('BigInt not supported');
}
view.setUint32(offset, Number(val & BigInt(0xffffffff)), true);
view.setUint32(offset + 4, Math.floor(Number((val / BigInt(0x100000000)) & BigInt(0xffffffff))), true);
}
var ImageOptionalHeader64 = /** @class */ (function (_super) {
__extends(ImageOptionalHeader64, _super);
function ImageOptionalHeader64(view) {
return _super.call(this, view) || this;
}
ImageOptionalHeader64.from = function (bin, offset) {
if (offset === void 0) { offset = 0; }
return new ImageOptionalHeader64(new DataView(bin, offset, 112));
};
Object.defineProperty(ImageOptionalHeader64.prototype, "magic", {
get: function () {
return this.view.getUint16(0, true);
},
set: function (val) {
this.view.setUint16(0, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorLinkerVersion", {
get: function () {
return this.view.getUint8(2);
},
set: function (val) {
this.view.setUint8(2, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorLinkerVersion", {
get: function () {
return this.view.getUint8(3);
},
set: function (val) {
this.view.setUint8(3, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfCode", {
get: function () {
return this.view.getUint32(4, true);
},
set: function (val) {
this.view.setUint32(4, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfInitializedData", {
get: function () {
return this.view.getUint32(8, true);
},
set: function (val) {
this.view.setUint32(8, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfUninitializedData", {
get: function () {
return this.view.getUint32(12, true);
},
set: function (val) {
this.view.setUint32(12, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "addressOfEntryPoint", {
get: function () {
return this.view.getUint32(16, true);
},
set: function (val) {
this.view.setUint32(16, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "baseOfCode", {
get: function () {
return this.view.getUint32(20, true);
},
set: function (val) {
this.view.setUint32(20, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "imageBase", {
get: function () {
return getUint64LE(this.view, 24);
},
set: function (val) {
setUint64LE(this.view, 24, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "imageBaseBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 24);
},
set: function (val) {
setUint64LEBigInt(this.view, 24, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sectionAlignment", {
get: function () {
return this.view.getUint32(32, true);
},
set: function (val) {
this.view.setUint32(32, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "fileAlignment", {
get: function () {
return this.view.getUint32(36, true);
},
set: function (val) {
this.view.setUint32(36, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(40, true);
},
set: function (val) {
this.view.setUint16(40, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorOperatingSystemVersion", {
get: function () {
return this.view.getUint16(42, true);
},
set: function (val) {
this.view.setUint16(42, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorImageVersion", {
get: function () {
return this.view.getUint16(44, true);
},
set: function (val) {
this.view.setUint16(44, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorImageVersion", {
get: function () {
return this.view.getUint16(46, true);
},
set: function (val) {
this.view.setUint16(46, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "majorSubsystemVersion", {
get: function () {
return this.view.getUint16(48, true);
},
set: function (val) {
this.view.setUint16(48, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "minorSubsystemVersion", {
get: function () {
return this.view.getUint16(50, true);
},
set: function (val) {
this.view.setUint16(50, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "win32VersionValue", {
get: function () {
return this.view.getUint32(52, true);
},
set: function (val) {
this.view.setUint32(52, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfImage", {
get: function () {
return this.view.getUint32(56, true);
},
set: function (val) {
this.view.setUint32(56, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeaders", {
get: function () {
return this.view.getUint32(60, true);
},
set: function (val) {
this.view.setUint32(60, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "checkSum", {
get: function () {
return this.view.getUint32(64, true);
},
set: function (val) {
this.view.setUint32(64, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "subsystem", {
get: function () {
return this.view.getUint16(68, true);
},
set: function (val) {
this.view.setUint16(68, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "dllCharacteristics", {
get: function () {
return this.view.getUint16(70, true);
},
set: function (val) {
this.view.setUint16(70, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackReserve", {
get: function () {
return getUint64LE(this.view, 72);
},
set: function (val) {
setUint64LE(this.view, 72, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackReserveBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 72);
},
set: function (val) {
setUint64LEBigInt(this.view, 72, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackCommit", {
get: function () {
return getUint64LE(this.view, 80);
},
set: function (val) {
setUint64LE(this.view, 80, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfStackCommitBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 80);
},
set: function (val) {
setUint64LEBigInt(this.view, 80, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapReserve", {
get: function () {
return getUint64LE(this.view, 88);
},
set: function (val) {
setUint64LE(this.view, 88, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapReserveBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 88);
},
set: function (val) {
setUint64LEBigInt(this.view, 88, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapCommit", {
get: function () {
return getUint64LE(this.view, 96);
},
set: function (val) {
setUint64LE(this.view, 96, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "sizeOfHeapCommitBigInt", {
get: function () {
return getUint64LEBigInt(this.view, 96);
},
set: function (val) {
setUint64LEBigInt(this.view, 96, val);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "loaderFlags", {
get: function () {
return this.view.getUint32(104, true);
},
set: function (val) {
this.view.setUint32(104, val, true);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ImageOptionalHeader64.prototype, "numberOfRvaAndSizes", {
get: function () {
return this.view.getUint32(108, true);
},
set: function (val) {
this.view.setUint32(108, val, true);
},
enumerable: false,
configurable: true
});
ImageOptionalHeader64.size = 112;
ImageOptionalHeader64.DEFAULT_MAGIC = 0x20b;
return ImageOptionalHeader64;
}(FormatBase_js_1.default));
exports.default = ImageOptionalHeader64;

View File

@@ -0,0 +1,21 @@
import ArrayFormatBase from './ArrayFormatBase.js';
export interface ImageSectionHeader {
name: string;
virtualSize: number;
virtualAddress: number;
sizeOfRawData: number;
pointerToRawData: number;
pointerToRelocations: number;
pointerToLineNumbers: number;
numberOfRelocations: number;
numberOfLineNumbers: number;
characteristics: number;
}
export default class ImageSectionHeaderArray extends ArrayFormatBase<ImageSectionHeader> {
readonly length: number;
static readonly itemSize = 40;
private constructor();
static from(bin: ArrayBuffer, length: number, offset?: number): ImageSectionHeaderArray;
get(index: number): Readonly<ImageSectionHeader>;
set(index: number, data: ImageSectionHeader): void;
}

View File

@@ -0,0 +1,61 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ArrayFormatBase_js_1 = require("./ArrayFormatBase.js");
var functions_js_1 = require("../util/functions.js");
var ImageSectionHeaderArray = /** @class */ (function (_super) {
__extends(ImageSectionHeaderArray, _super);
function ImageSectionHeaderArray(view, length) {
var _this = _super.call(this, view) || this;
_this.length = length;
return _this;
}
ImageSectionHeaderArray.from = function (bin, length, offset) {
if (offset === void 0) { offset = 0; }
var size = length * 40;
return new ImageSectionHeaderArray(new DataView(bin, offset, size), length);
};
ImageSectionHeaderArray.prototype.get = function (index) {
return {
name: functions_js_1.getFixedString(this.view, index * 40, 8),
virtualSize: this.view.getUint32(8 + index * 40, true),
virtualAddress: this.view.getUint32(12 + index * 40, true),
sizeOfRawData: this.view.getUint32(16 + index * 40, true),
pointerToRawData: this.view.getUint32(20 + index * 40, true),
pointerToRelocations: this.view.getUint32(24 + index * 40, true),
pointerToLineNumbers: this.view.getUint32(28 + index * 40, true),
numberOfRelocations: this.view.getUint16(32 + index * 40, true),
numberOfLineNumbers: this.view.getUint16(34 + index * 40, true),
characteristics: this.view.getUint32(36 + index * 40, true),
};
};
ImageSectionHeaderArray.prototype.set = function (index, data) {
functions_js_1.setFixedString(this.view, index * 40, 8, data.name);
this.view.setUint32(8 + index * 40, data.virtualSize, true);
this.view.setUint32(12 + index * 40, data.virtualAddress, true);
this.view.setUint32(16 + index * 40, data.sizeOfRawData, true);
this.view.setUint32(20 + index * 40, data.pointerToRawData, true);
this.view.setUint32(24 + index * 40, data.pointerToRelocations, true);
this.view.setUint32(28 + index * 40, data.pointerToLineNumbers, true);
this.view.setUint16(32 + index * 40, data.numberOfRelocations, true);
this.view.setUint16(34 + index * 40, data.numberOfLineNumbers, true);
this.view.setUint32(36 + index * 40, data.characteristics, true);
};
ImageSectionHeaderArray.itemSize = 40;
return ImageSectionHeaderArray;
}(ArrayFormatBase_js_1.default));
exports.default = ImageSectionHeaderArray;

View File

@@ -0,0 +1,15 @@
import ArrayFormatBase from './ArrayFormatBase.js';
import FormatBase from './FormatBase.js';
import ImageDataDirectoryArray, { ImageDataDirectory } from './ImageDataDirectoryArray.js';
import ImageDirectoryEntry from './ImageDirectoryEntry.js';
import ImageDosHeader from './ImageDosHeader.js';
import ImageFileHeader from './ImageFileHeader.js';
import ImageNtHeaders from './ImageNtHeaders.js';
import ImageOptionalHeader from './ImageOptionalHeader.js';
import ImageOptionalHeader64 from './ImageOptionalHeader64.js';
import ImageSectionHeaderArray, { ImageSectionHeader } from './ImageSectionHeaderArray.js';
export { ArrayFormatBase, FormatBase, ImageDataDirectory, ImageDataDirectoryArray, ImageDirectoryEntry, ImageDosHeader, ImageFileHeader, ImageNtHeaders, ImageOptionalHeader, ImageOptionalHeader64, ImageSectionHeader, ImageSectionHeaderArray, };
export declare function getImageDosHeader(bin: ArrayBuffer): ImageDosHeader;
export declare function getImageNtHeadersByDosHeader(bin: ArrayBuffer, dosHeader: ImageDosHeader): ImageNtHeaders;
export declare function getImageSectionHeadersByNtHeaders(bin: ArrayBuffer, dosHeader: ImageDosHeader, ntHeaders: ImageNtHeaders): ImageSectionHeaderArray;
export declare function findImageSectionBlockByDirectoryEntry(bin: ArrayBuffer, dosHeader: ImageDosHeader, ntHeaders: ImageNtHeaders, entryType: ImageDirectoryEntry): ArrayBuffer | null;

View File

@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findImageSectionBlockByDirectoryEntry = exports.getImageSectionHeadersByNtHeaders = exports.getImageNtHeadersByDosHeader = exports.getImageDosHeader = exports.ImageSectionHeaderArray = exports.ImageOptionalHeader64 = exports.ImageOptionalHeader = exports.ImageNtHeaders = exports.ImageFileHeader = exports.ImageDosHeader = exports.ImageDirectoryEntry = exports.ImageDataDirectoryArray = exports.FormatBase = exports.ArrayFormatBase = void 0;
var ArrayFormatBase_js_1 = require("./ArrayFormatBase.js");
exports.ArrayFormatBase = ArrayFormatBase_js_1.default;
var FormatBase_js_1 = require("./FormatBase.js");
exports.FormatBase = FormatBase_js_1.default;
var ImageDataDirectoryArray_js_1 = require("./ImageDataDirectoryArray.js");
exports.ImageDataDirectoryArray = ImageDataDirectoryArray_js_1.default;
var ImageDirectoryEntry_js_1 = require("./ImageDirectoryEntry.js");
exports.ImageDirectoryEntry = ImageDirectoryEntry_js_1.default;
var ImageDosHeader_js_1 = require("./ImageDosHeader.js");
exports.ImageDosHeader = ImageDosHeader_js_1.default;
var ImageFileHeader_js_1 = require("./ImageFileHeader.js");
exports.ImageFileHeader = ImageFileHeader_js_1.default;
var ImageNtHeaders_js_1 = require("./ImageNtHeaders.js");
exports.ImageNtHeaders = ImageNtHeaders_js_1.default;
var ImageOptionalHeader_js_1 = require("./ImageOptionalHeader.js");
exports.ImageOptionalHeader = ImageOptionalHeader_js_1.default;
var ImageOptionalHeader64_js_1 = require("./ImageOptionalHeader64.js");
exports.ImageOptionalHeader64 = ImageOptionalHeader64_js_1.default;
var ImageSectionHeaderArray_js_1 = require("./ImageSectionHeaderArray.js");
exports.ImageSectionHeaderArray = ImageSectionHeaderArray_js_1.default;
function getImageDosHeader(bin) {
return ImageDosHeader_js_1.default.from(bin);
}
exports.getImageDosHeader = getImageDosHeader;
function getImageNtHeadersByDosHeader(bin, dosHeader) {
return ImageNtHeaders_js_1.default.from(bin, dosHeader.newHeaderAddress);
}
exports.getImageNtHeadersByDosHeader = getImageNtHeadersByDosHeader;
function getImageSectionHeadersByNtHeaders(bin, dosHeader, ntHeaders) {
return ImageSectionHeaderArray_js_1.default.from(bin, ntHeaders.fileHeader.numberOfSections, dosHeader.newHeaderAddress + ntHeaders.byteLength);
}
exports.getImageSectionHeadersByNtHeaders = getImageSectionHeadersByNtHeaders;
function findImageSectionBlockByDirectoryEntry(bin, dosHeader, ntHeaders, entryType) {
var arr = ImageSectionHeaderArray_js_1.default.from(bin, ntHeaders.fileHeader.numberOfSections, dosHeader.newHeaderAddress + ntHeaders.byteLength);
var len = arr.length;
var rva = ntHeaders.optionalHeaderDataDirectory.get(entryType).virtualAddress;
for (var i = 0; i < len; ++i) {
var sec = arr.get(i);
var vaEnd = sec.virtualAddress + sec.virtualSize;
if (rva >= sec.virtualAddress && rva < vaEnd) {
var ptr = sec.pointerToRawData;
if (!ptr) {
return null;
}
return bin.slice(ptr, ptr + sec.sizeOfRawData);
}
if (rva < sec.virtualAddress) {
return null;
}
}
return null;
}
exports.findImageSectionBlockByDirectoryEntry = findImageSectionBlockByDirectoryEntry;

View File

@@ -0,0 +1,7 @@
import NtExecutable, { NtExecutableFromOptions, NtExecutableSection } from './NtExecutable.js';
import NtExecutableResource from './NtExecutableResource.js';
import { calculateCheckSumForPE } from './util/functions.js';
import version from './version.js';
import * as Format from './format/index.js';
import * as Type from './type/index.js';
export { NtExecutable, NtExecutableFromOptions, NtExecutableResource, NtExecutableSection, calculateCheckSumForPE, version, Format, Type, };

15
desktop-operator/node_modules/pe-library/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Type = exports.Format = exports.version = exports.calculateCheckSumForPE = exports.NtExecutableResource = exports.NtExecutable = void 0;
var NtExecutable_js_1 = require("./NtExecutable.js");
exports.NtExecutable = NtExecutable_js_1.default;
var NtExecutableResource_js_1 = require("./NtExecutableResource.js");
exports.NtExecutableResource = NtExecutableResource_js_1.default;
var functions_js_1 = require("./util/functions.js");
Object.defineProperty(exports, "calculateCheckSumForPE", { enumerable: true, get: function () { return functions_js_1.calculateCheckSumForPE; } });
var version_js_1 = require("./version.js");
exports.version = version_js_1.default;
var Format = require("./format/index.js");
exports.Format = Format;
var Type = require("./type/index.js");
exports.Type = Type;

View File

@@ -0,0 +1,17 @@
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const {
NtExecutable,
NtExecutableResource,
calculateCheckSumForPE,
version,
Format,
} = require('./index.js');
export {
NtExecutable,
NtExecutableResource,
calculateCheckSumForPE,
version,
Format,
};

View File

@@ -0,0 +1,31 @@
export interface ResourceEntryBaseType<TType extends string | number, TID extends string | number, TLang extends string | number> {
/**
* The resource type name or numeric value.
* For well-known type (such as `RT_ICON`), this value must be the predefined numeric value.
*/
type: TType;
/** The ID of resource data. */
id: TID;
/**
* The language value of resource data.
* According to specification, this value can be string, but
* typically this value would be LANGID (numeric) value.
*/
lang: TLang;
/**
* The code page value for strings within the resource data.
* Typically this value would be the Unicode code page '1200'.
*/
codepage: number;
/** The actual resource data. If the data cannot be read, this field will be an empty binary. */
bin: ArrayBuffer;
/** RVA data for resource data. This field is available only when actual data (`bin` field) cannot be read. */
rva?: number;
/** (used by output) */
offset?: number;
}
export declare type ResourceEntryT<TType extends string | number> = ResourceEntryBaseType<TType, string | number, string | number>;
export declare type ResourceEntryTT<TType extends string | number, TID extends string | number> = ResourceEntryBaseType<TType, TID, string | number>;
/** Raw resource entry data */
declare type ResourceEntry = ResourceEntryBaseType<string | number, string | number, string | number>;
export default ResourceEntry;

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,2 @@
import ResourceEntry, { ResourceEntryBaseType, ResourceEntryT, ResourceEntryTT } from './ResourceEntry.js';
export { ResourceEntry, ResourceEntryBaseType, ResourceEntryT, ResourceEntryTT, };

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,13 @@
/// <reference lib="dom" />
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 | ArrayBufferView, 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 getFixedString(view: DataView, offset: number, length: number): string;
export declare function setFixedString(view: DataView, offset: number, length: number, text: string): void;
export declare function binaryToString(bin: ArrayBuffer | ArrayBufferView): string;
export declare function stringToBinary(string: string): ArrayBuffer;

View File

@@ -0,0 +1,273 @@
"use strict";
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference lib='dom' />
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringToBinary = exports.binaryToString = exports.setFixedString = exports.getFixedString = exports.cloneToArrayBuffer = exports.allocatePartialBinary = exports.copyBuffer = exports.roundUp = exports.calculateCheckSumForPE = exports.createDataView = exports.cloneObject = void 0;
var ImageDosHeader_js_1 = require("../format/ImageDosHeader.js");
function cloneObject(object) {
var r = {};
Object.keys(object).forEach(function (key) {
r[key] = object[key];
});
return r;
}
exports.cloneObject = cloneObject;
/* eslint-enable @typescript-eslint/ban-types */
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) {
var dosHeader = ImageDosHeader_js_1.default.from(bin);
var view = new DataView(bin);
var checkSumOffset = dosHeader.newHeaderAddress + 88;
var result = 0;
var limit = 0x100000000; // 2^32
var update = function (dword) {
result += dword;
if (result >= limit) {
result = (result % limit) + ((result / limit) | 0);
}
};
var len = view.byteLength;
var lenExtra = len % 4;
var lenAlign = len - lenExtra;
for (var i = 0; i < lenAlign; i += 4) {
if (i !== checkSumOffset) {
update(view.getUint32(i, true));
}
}
if (lenExtra !== 0) {
var extra = 0;
for (var i = 0; i < lenExtra; i++) {
extra |= view.getUint8(lenAlign + i) << ((3 - i) * 8);
}
update(extra);
}
result = (result & 0xffff) + (result >>> 16);
result += result >>> 16;
result = (result & 0xffff) + len;
if (storeToBinary) {
view.setUint32(checkSumOffset, result, true);
}
return result;
}
exports.calculateCheckSumForPE = calculateCheckSumForPE;
function roundUp(val, align) {
return Math.floor((val + align - 1) / align) * align;
}
exports.roundUp = roundUp;
function copyBuffer(dest, destOffset, src, srcOffset, length) {
var ua8Dest = 'buffer' in dest
? new Uint8Array(dest.buffer, dest.byteOffset + (destOffset || 0), length)
: new Uint8Array(dest, destOffset, length);
var ua8Src = 'buffer' in src
? new Uint8Array(src.buffer, src.byteOffset + (srcOffset || 0), length)
: new Uint8Array(src, srcOffset, length);
ua8Dest.set(ua8Src);
}
exports.copyBuffer = copyBuffer;
function allocatePartialBinary(binBase, offset, length) {
var b = new ArrayBuffer(length);
copyBuffer(b, 0, binBase, offset, length);
return b;
}
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 getFixedString(view, offset, length) {
var actualLen = 0;
for (var i = 0; i < length; ++i) {
if (view.getUint8(offset + i) === 0) {
break;
}
++actualLen;
}
if (typeof Buffer !== 'undefined') {
return Buffer.from(view.buffer, view.byteOffset + offset, actualLen).toString('utf8');
}
else if (typeof decodeURIComponent !== 'undefined') {
var s = '';
for (var i = 0; i < actualLen; ++i) {
var c = view.getUint8(offset + i);
if (c < 16) {
s += '%0' + c.toString(16);
}
else {
s += '%' + c.toString(16);
}
}
return decodeURIComponent(s);
}
else {
var s = '';
for (var i = 0; i < actualLen; ++i) {
var c = view.getUint8(offset + i);
s += String.fromCharCode(c);
}
return s;
}
}
exports.getFixedString = getFixedString;
function setFixedString(view, offset, length, text) {
if (typeof Buffer !== 'undefined') {
var u = new Uint8Array(view.buffer, view.byteOffset + offset, length);
// fill by zero
u.set(new Uint8Array(length));
u.set(Buffer.from(text, 'utf8').subarray(0, length));
}
else if (typeof encodeURIComponent !== 'undefined') {
var s = encodeURIComponent(text);
for (var i = 0, j = 0; i < length; ++i) {
if (j >= s.length) {
view.setUint8(i + offset, 0);
}
else {
var c = s.charCodeAt(j);
if (c === 37) {
// '%'
var n = parseInt(s.substr(j + 1, 2), 16);
if (typeof n === 'number' && !isNaN(n)) {
view.setUint8(i + offset, n);
}
else {
view.setUint8(i + offset, 0);
}
j += 3;
}
else {
view.setUint8(i + offset, c);
}
}
}
}
else {
for (var i = 0, j = 0; i < length; ++i) {
if (j >= text.length) {
view.setUint8(i + offset, 0);
}
else {
var c = text.charCodeAt(j);
view.setUint8(i + offset, c & 0xff);
}
}
}
}
exports.setFixedString = setFixedString;
function binaryToString(bin) {
if (typeof TextDecoder !== 'undefined') {
var dec = new TextDecoder();
return dec.decode(bin);
}
else if (typeof Buffer !== 'undefined') {
var b = void 0;
if ('buffer' in bin) {
b = Buffer.from(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
b = Buffer.from(bin);
}
return b.toString('utf8');
}
else {
var view = void 0;
if ('buffer' in bin) {
view = new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
view = new Uint8Array(bin);
}
if (typeof decodeURIComponent !== 'undefined') {
var s = '';
for (var i = 0; i < view.length; ++i) {
var c = view[i];
if (c < 16) {
s += '%0' + c.toString(16);
}
else {
s += '%' + c.toString(16);
}
}
return decodeURIComponent(s);
}
else {
var s = '';
for (var i = 0; i < view.length; ++i) {
var c = view[i];
s += String.fromCharCode(c);
}
return s;
}
}
}
exports.binaryToString = binaryToString;
function stringToBinary(string) {
if (typeof TextEncoder !== 'undefined') {
var enc = new TextEncoder();
return cloneToArrayBuffer(enc.encode(string));
}
else if (typeof Buffer !== 'undefined') {
return cloneToArrayBuffer(Buffer.from(string, 'utf8'));
}
else if (typeof encodeURIComponent !== 'undefined') {
var data = encodeURIComponent(string);
var len = 0;
for (var i = 0; i < data.length; ++len) {
var c = data.charCodeAt(i);
if (c === 37) {
i += 3;
}
else {
++i;
}
}
var bin = new ArrayBuffer(len);
var view = new Uint8Array(bin);
for (var i = 0, j = 0; i < data.length; ++j) {
var c = data.charCodeAt(i);
if (c === 37) {
var n = parseInt(data.substring(i + 1, i + 3), 16);
view[j] = n;
i += 3;
}
else {
view[j] = c;
++i;
}
}
return bin;
}
else {
var bin = new ArrayBuffer(string.length);
new Uint8Array(bin).set([].map.call(string, function (c) {
return c.charCodeAt(0);
}));
return bin;
}
}
exports.stringToBinary = stringToBinary;

View File

@@ -0,0 +1,5 @@
export declare function getDosStubDataSize(): number;
export declare function fillDosStubData(bin: ArrayBuffer | ArrayBufferView): void;
export declare function estimateNewHeaderSize(is32Bit: boolean): number;
export declare function fillPeHeaderEmptyData(bin: ArrayBuffer | ArrayBufferView, offset: number, totalBinSize: number, is32Bit: boolean, isDLL: boolean): void;
export declare function makeEmptyNtExecutableBinary(is32Bit: boolean, isDLL: boolean): ArrayBuffer;

View File

@@ -0,0 +1,127 @@
"use strict";
// To make the binary (DOS_STUB_PROGRAM):
// $ cd tools/dos-stub
// $ nasm -f bin -o dos-stub.bin dos-stub.asm
// $ node -e "console.log([].map.call(fs.readFileSync('tools/dos-stub/dos-stub.bin'), (v)=>`0x${Buffer.from([v]).toString('hex')}`).join(','))"
//
// NOTE: the original dos-stub.asm program and the bit code in DOS_STUB_PROGRAM are under the 0-BSD license.
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeEmptyNtExecutableBinary = exports.fillPeHeaderEmptyData = exports.estimateNewHeaderSize = exports.fillDosStubData = exports.getDosStubDataSize = void 0;
var ImageDataDirectoryArray_js_1 = require("../format/ImageDataDirectoryArray.js");
var ImageDosHeader_js_1 = require("../format/ImageDosHeader.js");
var ImageFileHeader_js_1 = require("../format/ImageFileHeader.js");
var ImageNtHeaders_js_1 = require("../format/ImageNtHeaders.js");
var ImageOptionalHeader_js_1 = require("../format/ImageOptionalHeader.js");
var ImageOptionalHeader64_js_1 = require("../format/ImageOptionalHeader64.js");
var functions_js_1 = require("./functions.js");
// fill with '0x00' to make 8-bytes alignment
// prettier-ignore
var DOS_STUB_PROGRAM = new Uint8Array([
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x44, 0x4f,
0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f,
0x72, 0x74, 0x65, 0x64, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);
var DOS_STUB_SIZE = functions_js_1.roundUp(ImageDosHeader_js_1.default.size + DOS_STUB_PROGRAM.length, 0x80);
var DEFAULT_FILE_ALIGNMENT = 512;
function getDosStubDataSize() {
return DOS_STUB_SIZE;
}
exports.getDosStubDataSize = getDosStubDataSize;
function fillDosStubData(bin) {
var dos = ImageDosHeader_js_1.default.from(bin);
dos.magic = ImageDosHeader_js_1.default.DEFAULT_MAGIC;
// last page size
dos.lastPageSize = DOS_STUB_SIZE % 512;
// total page count
dos.pages = Math.ceil(DOS_STUB_SIZE / 512);
// no relocations
dos.relocations = 0;
// header size as paragraph count (1 paragraph = 16 bytes)
dos.headerSizeInParagraph = Math.ceil(ImageDosHeader_js_1.default.size / 16);
dos.minAllocParagraphs = 0;
dos.maxAllocParagraphs = 0xffff;
dos.initialSS = 0;
dos.initialSP = 0x80;
// (no relocations, but set offset after the header)
dos.relocationTableAddress = ImageDosHeader_js_1.default.size;
dos.newHeaderAddress = DOS_STUB_SIZE;
functions_js_1.copyBuffer(bin, ImageDosHeader_js_1.default.size, DOS_STUB_PROGRAM, 0, DOS_STUB_PROGRAM.length);
}
exports.fillDosStubData = fillDosStubData;
function estimateNewHeaderSize(is32Bit) {
return (
// magic
4 +
ImageFileHeader_js_1.default.size +
(is32Bit ? ImageOptionalHeader_js_1.default.size : ImageOptionalHeader64_js_1.default.size) +
ImageDataDirectoryArray_js_1.default.size);
}
exports.estimateNewHeaderSize = estimateNewHeaderSize;
function fillPeHeaderEmptyData(bin, offset, totalBinSize, is32Bit, isDLL) {
var _bin;
var _offset;
if ('buffer' in bin) {
_bin = bin.buffer;
_offset = bin.byteOffset + offset;
}
else {
_bin = bin;
_offset = offset;
}
new DataView(_bin, _offset).setUint32(0, ImageNtHeaders_js_1.default.DEFAULT_SIGNATURE, true);
var fh = ImageFileHeader_js_1.default.from(_bin, _offset + 4);
fh.machine = is32Bit ? 0x14c : 0x8664;
fh.numberOfSections = 0; // no sections
fh.timeDateStamp = 0;
fh.pointerToSymbolTable = 0;
fh.numberOfSymbols = 0;
fh.sizeOfOptionalHeader =
(is32Bit ? ImageOptionalHeader_js_1.default.size : ImageOptionalHeader64_js_1.default.size) +
ImageDataDirectoryArray_js_1.default.size;
fh.characteristics = isDLL ? 0x2102 : 0x102;
var oh = (is32Bit ? ImageOptionalHeader_js_1.default : ImageOptionalHeader64_js_1.default).from(_bin, _offset + 4 + ImageFileHeader_js_1.default.size);
oh.magic = is32Bit
? ImageOptionalHeader_js_1.default.DEFAULT_MAGIC
: ImageOptionalHeader64_js_1.default.DEFAULT_MAGIC;
// oh.majorLinkerVersion = 0;
// oh.minorLinkerVersion = 0;
oh.sizeOfCode = 0;
oh.sizeOfInitializedData = 0;
oh.sizeOfUninitializedData = 0;
oh.addressOfEntryPoint = 0;
oh.baseOfCode = 0x1000;
// oh.baseOfData = 0; // for 32bit only
oh.imageBase = is32Bit ? 0x1000000 : 0x180000000;
oh.sectionAlignment = 4096;
oh.fileAlignment = DEFAULT_FILE_ALIGNMENT;
oh.majorOperatingSystemVersion = 6;
oh.minorOperatingSystemVersion = 0;
// oh.majorImageVersion = 0;
// oh.minorImageVersion = 0;
oh.majorSubsystemVersion = 6;
oh.minorSubsystemVersion = 0;
// oh.win32VersionValue = 0;
oh.sizeOfHeaders = functions_js_1.roundUp(totalBinSize, oh.fileAlignment);
// oh.checkSum = 0;
oh.subsystem = 2; // IMAGE_SUBSYSTEM_WINDOWS_GUI
oh.dllCharacteristics =
(is32Bit ? 0 : 0x20) + // IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
0x40 + // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
0x100; // IMAGE_DLLCHARACTERISTICS_NX_COMPAT
oh.sizeOfStackReserve = 0x100000;
oh.sizeOfStackCommit = 0x1000;
oh.sizeOfHeapReserve = 0x100000;
oh.sizeOfHeapCommit = 0x1000;
// oh.loaderFlags = 0;
oh.numberOfRvaAndSizes =
ImageDataDirectoryArray_js_1.default.size / ImageDataDirectoryArray_js_1.default.itemSize;
}
exports.fillPeHeaderEmptyData = fillPeHeaderEmptyData;
function makeEmptyNtExecutableBinary(is32Bit, isDLL) {
var bufferSize = functions_js_1.roundUp(DOS_STUB_SIZE + estimateNewHeaderSize(is32Bit), DEFAULT_FILE_ALIGNMENT);
var bin = new ArrayBuffer(bufferSize);
fillDosStubData(bin);
fillPeHeaderEmptyData(bin, DOS_STUB_SIZE, bufferSize, is32Bit, isDLL);
return bin;
}
exports.makeEmptyNtExecutableBinary = makeEmptyNtExecutableBinary;

View File

@@ -0,0 +1,2 @@
declare const _default: "0.4.1";
export default _default;

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = '0.4.1';