A small typescript binary patching utility for windows, works both as a standalone application or library adaptable to specific usage scenarios.
This tool/library is intended for patch developers and enthusiasts to streamline patch tool distribution.
Install using npm
$ npm install patcherjs
Simple running example
import { Patcher } from 'patcherjs';
Patcher.runPatcher({});
Patcherjs has 3 main functions on its own:
- Patching binaries
- Executing arbitrary commands
- Execute any basic command
- Executing kill, system service or task scheduler commands
- Drop files in a directory
Download from releases or clone the repository
patcherjs-predist
- Just extract and edit
patcherjs-dist
- Open as an archive with 7-zip extract files files and drop inside again
$ git clone https://github.com/whois-team/patcherjs
$ npm install
There are a collection of scripts that are used help manage the build process
package.json
scripts:
"scriptsComments": {
"#GENERAL SCRIPTS#": "#SECTION#",
"start": "Runs the patcher (executable.js)",
"#BUILD SCRIPTS#": "#SECTION#",
"ts-build-clean": "Typescript clean build to 'dist' folder",
"ts-build": "Typescript build to 'dist' folder",
"esbuild": "ESBuild the standalone executable into a JS file (executable.js) on the 'sea' folder",
"sea-build": "Executes the SEA (single executable application) building script (builder.js) according to nodes sea generation guidelines (needs ts-build to be ran first)",
"sea-pack": "Packs all files in 'patch_files_unpacked' and drops them into 'patch_files' to be used by the patcher",
"sea-copy": "Copies 'config.json', 'patch_files' folder contents and 7zip binaries from node_modules to 'predist' folder (needs npm install to be ran first)",
"sea-predist": "Compresses built SEA file and its additional files into a 7zip archive using predist script (predist.js) (needs ts-build to be ran first)",
"sea-dist": "Merges SFX 7zip module and 7zip archive into a single file (no prompts) (needs 'sea-build' to be ran first)",
"sea-dist-prompt": "Merges SFX 7zip module, SFX 7zip module script and 7zip archive into a single file (with prompt) [alternative to no prompt]",
"sea-build-full": "Run full SEA build process including SFX ready for distribution (runs 'ts-build-clean', 'esbuild', 'sea-build', 'sea-copy', 'sea-predist' and 'sea-dist')",
"sea-build-full-clean": "Same as 'sea-build-full' but executes 'sea-cleanup-full' first, serves as a full clean build",
"sea-cleanup-full": "Build Typescript files and fully clean up build space",
"sea-cleanup": "fully clean up build space",
"sea-copy-config": "Copies 'config.json' to 'predist' folder",
"sea-copy-patch_files": "Copies 'patch_files' folder contents to 'predist' folder",
"sea-copy-7z": "Copies 7-zip binaries from 'node_modules' to 'predist folder' (needs npm install to be ran first)",
"generate-docs": "Generates documentation using typedoc to 'docs' folder"
},
The project comes with an example .patch
file and a .dll
file to be packed, these files should be removed and you should add your own files.
Theres two ways of using patcherjs as an applications, as multi file application which contains a nodejs SEA or a single SFX file.
- Run the following build script to do a full build
$ npm run sea-build-full-clean
- Grab your file from
sea/dist
folder if you want a single executable otherwise grab all files fromsea/predist
if you prefer a multi file approach.
Project folder
| Project folder
\
| dist - Compiled Typescript files
| docs - Generate typedoc documentation
| misc_bin - Miscellaneous binaries, containing signtool that can be installed to %PATH% to be used in the build process
| node_modules - Typical node modules folder
| patch_files - Contains '.patch' files to be used by the script and packed '.pack' files to be dropped by the script
| patch_files_unpacked - Contains all the unpacked files to be packed by patcherjs and dropped into 'patch_files' folder
| sea - Contains all the files pertaining to SEA (single executable application) build process
\
| sea/dist - Final build step folder which will contain the SEA SFX packed executable ready for distribution
\
| patcherjs-min.exe - Built single file executable ready for distribution (unpacks itself and runs patcherjs.exe)
| sea/predist - A Intermediate build step folder containing all the working parts of the patcher that can work but is not contained into a SFX file
\
| patch_files - Folder copied from root containing all patch files and filedrops
| win - Folder containing 7-zip binaries
| config.json - Application configuration copied from root
| patcherjs.exe - Nodejs SEA containing all the functions necessary to patchers execution (runs executable.ts)
| sea/sea-sfx.sfx - 7zip SFX module without prompt
| sea/sea-sfx-config.txt - 7zip SFX module script (only necessary for prompt)
| sea/sea-sfx-gui.sfx - 7zip SFX module with prompt
| source - Folder containing all source files for the project
\
| source/buildscripts - Contains all scripts related to the build scripts described in package.json
| source/lib - All the source code for the patcher inner workings and its different parts
\
| auxiliary - Folder containing all the auxiliary file, debug, uac and useful functions and operations
| build - Folder containing all the build, packaging and cleanup functions and routines
| commands - Folder containing all the command related functions and routines
| configuration - Folder containing all the configuration functions and routines, and also constants
| filedrops - Folder containing all the filedrops, encryption and packing functions and routines
| patches - Folder containing all the buffer, parser and patches functions and routines
| composites.ts - File containing the general 'runPatcher' function and related
| source/standalone - Folder containing 'executable.ts' that is used as the patcherjs standalone application
| config.json - File containing all the configurations used by patcherjs
Patcherjs functions with a configuration json file using the following structure, generally the provided default config.json
are the recommended values but you can set them as preferred and/or needed.
config.json
{
"options": { // OPTIONS
"general": { // OPTIONS > GENERAL, General options
"exitOnNonAdmin": true, // Exit when current running user doesn't have administrative privileges, on `false` will continue
"debug": true, // Enable debug messages (recommended)
"logging": false, // Enable logging debug messages to file (untested)
"runningOrder": [ // An array that defines in which order will the patcher run its commands, commands can be repeated though
"commands", // Run commands
"filedrops", // Run filedrops
"patches" // Run binary patches
],
"commandsOrder": [ // Within commands you can decide which type of command runs first
"tasks", // Task scheduler commands
"services", // System service commands
"kill", // Kill commands
"general" // General arbitrary commands
],
"onlyPackingMode": false // Use when you want to pack files using the SEA without access to source
},
"patches": { // OPTIONS > PATCHES, Patches related options
"runPatches": true, // Set to false if you want to skip patches for some reason
"forcePatch": false, // Set to true if you don't want to check for the current value, bulldozer mode basically
"fileSizeCheck": true, // Check for file size before running patch
"fileSizeThreshold": 0, // File size check threshold
"skipWritePatch": false, // Skip writing patch (mostly for debug purposes, like simulate a patch but not actually patch)
"failOnUnexpectedPreviousValue": false, // Fail patches if an unexpected previous/current value is found
"warnOnUnexpectedPreviousValue": true, // Warn/throw a debug message that an unexpected previous/current value was found
"nullPatch": false, // Just patch the offsets to null (basically 0, mostly useful just for debug)
"unpatchMode": false, // Reverse previous/current with new value to basically reverse patch a file
"verifyPatch": true, // Verify patch (not implemented)
"backupFiles": true, // Create copy with '.bak' extension in the destination directory for every patched file
"skipWritingBinary": false // Skip writing the patched buffer to file
},
"commands": { // OPTIONS > COMMANDS, Commands related options
"runCommands": true // Set to false to skip running any commands
},
"filedrops": { // OPTIONS > FILEDROPS, Filedrops related options
"runFiledrops": true, // Set to false to skip filedrops
"isFiledropPacked": true, // Is file compressed in a password protected 7zip archive or not compressed at all (affects packing process)
"isFiledropCrypted": true, // Is file encrypted (affects packing process)
"backupFiles": true // Backup destination files with '.bak' before replacing them
}
},
"patches": [ // A patches array, every object is related to a single '.patch' file
{
"name": "file.dll patch", // Patch display name, not important
"patchFilename": "file.dll.patch", // .patch filename
"fileNamePath": "C:\\Program Files (x86)\\Someapp\\file.dll", // File path to patch, use double slash always to escape characters
"enabled": true // Is this specific patch enabled, set false to skip
}
],
"commands": { // Contains all the arrays of the different command types
"tasks": [ // An array of task scheduler related commands
{
"name": "TestTaskApp-1", // Task scheduler name
"command": "delete", // Either 'delete' or 'stop' those are the two available options
"enabled": true // Set false to skip
}
],
"kill": [ // An array of processes to kill
{
"name": "testapp.exe", // Name of the process to kill
"enabled": true // Set false to skip
}
],
"services": [ // An array of system service commands to run
{
"name": "TestService", // Name of the service
"command": "delete", // Either 'stop', 'disable' or 'delete' the service
"enabled": true // Set false to skip
}
],
"general": [ // An array of general commands to run
{
"name": "echo test", // Display name
"command": "echo \"test\"", // Command to run, escape your special characters like backslash and quotes
"enabled": true // Set false to skip
}
]
},
"filedrops": [ // An array of file drops to run
{
"name": "helloworld.dll", // Display name
"fileDropName": "helloworld.dll.pack", // Packed filename inside 'patch_files' directory
"packedFileName": "helloworld.dll", // Original filename inside 'patch_files_unpacked' folder
"fileNamePath": "C:\\Program Files (x86)\\Someapp\\helloworld.dll", // Destination filename, always escape your backslashes
"decryptKey": "ad4bc8a11481000e4d8daf28412f867a", // Encryption/decryption password
"enabled": true // Set to false to skip
}
]
}
A .patch file should follow the following format: (uses 32 bit offsets)
0002EB40: 03 00
0006AA00: 04 10
OFFSET: PREVIOUS_VALUE NEW_VALUE
You can create patch files by exporting patches from x64dbg or vbindiff applications.
- NodeJS
- Typescript
Distributed under MIT License. Seelicense.md
for more information.