mirror of
https://github.com/Karmaz95/Snake_Apple.git
synced 2026-03-30 14:00:16 +02:00
Code related to Bypassing Electron Integrity article
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
// https://medium.com/@karol-mazurek/cracking-macos-apps-39575dd672e0
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var crypto = require("crypto");
|
||||
var asar = require("asar");
|
||||
var fs = require("fs");
|
||||
// Function to generate the integrity hash
|
||||
var generateAsarIntegrity = function (asarPath) {
|
||||
var headerString = asar.getRawHeader(asarPath).headerString;
|
||||
var hash = crypto
|
||||
.createHash('sha256')
|
||||
.update(headerString)
|
||||
.digest('hex');
|
||||
return {
|
||||
algorithm: 'SHA256',
|
||||
hash: hash
|
||||
};
|
||||
};
|
||||
// Main script execution
|
||||
var main = function () {
|
||||
if (process.argv.length !== 3) {
|
||||
console.error('Usage: node calculate_hash.ts <path_to_asar_file>');
|
||||
process.exit(1);
|
||||
}
|
||||
var asarPath = process.argv[2];
|
||||
// Check if the file exists
|
||||
if (!fs.existsSync(asarPath)) {
|
||||
console.error("File not found: ".concat(asarPath));
|
||||
process.exit(1);
|
||||
}
|
||||
var result = generateAsarIntegrity(asarPath);
|
||||
console.log("Algorithm: ".concat(result.algorithm));
|
||||
console.log("Hash: ".concat(result.hash));
|
||||
};
|
||||
// Run the script
|
||||
main()
|
||||
@@ -0,0 +1,30 @@
|
||||
import sys
|
||||
import struct
|
||||
import hashlib
|
||||
|
||||
def getASARHeaderSize(file_path):
|
||||
with open(file_path, 'rb') as f:
|
||||
asar_header = f.read(16)
|
||||
asar_header_size_bytes = asar_header[12:16]
|
||||
header_size = struct.unpack('<I', asar_header_size_bytes)[0]
|
||||
return(header_size)
|
||||
|
||||
def readASARHeader(file_path, header_size):
|
||||
with open(file_path, 'rb') as f:
|
||||
f.seek(16)
|
||||
asar_header = f.read(header_size)
|
||||
return(asar_header)
|
||||
|
||||
def calcASARHeaderHash(asar_header):
|
||||
return(hashlib.sha256(asar_header).hexdigest())
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python3 ElectronAsarIntegrityCalculator.py PATH_TO_ASAR_FILE")
|
||||
sys.exit(1)
|
||||
|
||||
file_path = sys.argv[1]
|
||||
asar_header_size = getASARHeaderSize(file_path)
|
||||
asar_header_bytes = readASARHeader(file_path, asar_header_size)
|
||||
asar_header_hash = calcASARHeaderHash(asar_header_bytes)
|
||||
print(asar_header_hash)
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script installs the necessary tools, sets up the project, creates the TypeScript file, compiles it, and runs the script with the specified ASAR file path.
|
||||
# https://medium.com/@karol-mazurek/cracking-macos-apps-39575dd672e0
|
||||
|
||||
# Define the TypeScript file and ASAR path
|
||||
TS_FILE="calculate_hash.ts"
|
||||
ASAR_PATH="$1"
|
||||
|
||||
# Step 1: Install Node.js and npm (if not installed)
|
||||
echo "Ensure Node.js and npm are installed..."
|
||||
|
||||
# Step 2: Install TypeScript and ts-node globally
|
||||
echo "Installing TypeScript and ts-node globally..."
|
||||
npm install -g typescript ts-node
|
||||
|
||||
# Step 3: Initialize npm project (if not already done)
|
||||
if [ ! -f "package.json" ]; then
|
||||
echo "Initializing npm project..."
|
||||
npm init -y
|
||||
fi
|
||||
|
||||
# Step 4: Install dependencies
|
||||
echo "Installing asar and @types/node..."
|
||||
npm install asar
|
||||
npm install --save-dev @types/node
|
||||
|
||||
# Step 5: Create TypeScript file
|
||||
cat <<EOL > $TS_FILE
|
||||
import * as crypto from 'crypto';
|
||||
import * as asar from 'asar';
|
||||
import * as fs from 'fs';
|
||||
|
||||
// Function to generate the integrity hash
|
||||
const generateAsarIntegrity = (asarPath: string) => {
|
||||
const headerString = asar.getRawHeader(asarPath).headerString;
|
||||
const hash = crypto
|
||||
.createHash('sha256')
|
||||
.update(headerString)
|
||||
.digest('hex');
|
||||
|
||||
return {
|
||||
algorithm: 'SHA256' as const,
|
||||
hash
|
||||
};
|
||||
};
|
||||
|
||||
// Main script execution
|
||||
const main = () => {
|
||||
if (process.argv.length !== 3) {
|
||||
console.error('Usage: node calculate_hash.ts <path_to_asar_file>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const asarPath = process.argv[2];
|
||||
|
||||
// Check if the file exists
|
||||
if (!fs.existsSync(asarPath)) {
|
||||
console.error(\`File not found: \${asarPath}\`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const result = generateAsarIntegrity(asarPath);
|
||||
|
||||
console.log(\`Algorithm: \${result.algorithm}\`);
|
||||
console.log(\`Hash: \${result.hash}\`);
|
||||
};
|
||||
|
||||
// Run the script
|
||||
main();
|
||||
EOL
|
||||
|
||||
# Step 6: Compile TypeScript to JavaScript
|
||||
echo "Compiling TypeScript to JavaScript..."
|
||||
tsc $TS_FILE
|
||||
|
||||
# Step 7: Run the JavaScript file
|
||||
echo "Running the script with ASAR path: $ASAR_PATH"
|
||||
node calculate_hash.js "$ASAR_PATH"
|
||||
|
||||
echo "Done."
|
||||
116
App Bundle Extension/custom/electron_patcher.py
Normal file
116
App Bundle Extension/custom/electron_patcher.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import sys
|
||||
import struct
|
||||
import hashlib
|
||||
import argparse
|
||||
import os
|
||||
|
||||
class ASARCalculator:
|
||||
def __init__(self, file_path):
|
||||
self.file_path = file_path
|
||||
self.asar_header_size = self.getASARHeaderSize()
|
||||
self.asar_header_bytes = self.readASARHeader()
|
||||
self.asar_header_hash = self.calcASARHeaderHash()
|
||||
|
||||
def getASARHeaderSize(self):
|
||||
with open(self.file_path, 'rb') as f:
|
||||
asar_header = f.read(16)
|
||||
asar_header_size_bytes = asar_header[12:16]
|
||||
header_size = struct.unpack('<I', asar_header_size_bytes)[0]
|
||||
return header_size
|
||||
|
||||
def readASARHeader(self):
|
||||
with open(self.file_path, 'rb') as f:
|
||||
f.seek(16)
|
||||
asar_header = f.read(self.asar_header_size)
|
||||
return asar_header
|
||||
|
||||
def calcASARHeaderHash(self):
|
||||
return hashlib.sha256(self.asar_header_bytes).hexdigest()
|
||||
|
||||
class ASARPatcher:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def extractASAR(self, app_path, output_path):
|
||||
'''Extracts {input_path} asar file to {output_path} directory.'''
|
||||
input_path = os.path.join(app_path, "Contents/Resources/app.asar")
|
||||
status_code = os.system(f"npx asar extract {input_path} {output_path}")
|
||||
|
||||
if status_code == 0:
|
||||
print(f"Extracted {input_path} to {output_path} directory.")
|
||||
|
||||
else:
|
||||
print(f"Failed to extract {input_path} to {output_path} directory. Error code: {status_code}")
|
||||
|
||||
def dumpEntitlements(self, app_path):
|
||||
output_path='/tmp/extracted_entitlements.xml'
|
||||
status_code = os.system(f"codesign -d --entitlements :- {app_path} > {output_path}")
|
||||
|
||||
if status_code == 0:
|
||||
print(f"Dumped entitlements from {app_path} to {output_path}")
|
||||
|
||||
else:
|
||||
print(f"Failed to dump entitlements from {app_path} to {output_path}. Error code: {status_code}")
|
||||
|
||||
def checkIfElectronAsarIntegrityIsUsed(self, app_path):
|
||||
status_code = os.system(f"plutil -p {app_path}/Contents/Info.plist | grep -q ElectronAsarIntegrity")
|
||||
if status_code == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def packASAR(self, input_path, app_path):
|
||||
'''Packs {input_path} directory to {output_path} asar file.
|
||||
Check if ElectronAsarIntegrity is used in Info.plist, and if so, calculate hash and replace it.
|
||||
Codesign the
|
||||
'''
|
||||
output_path = os.path.join(app_path, "Contents/Resources/app.asar")
|
||||
info_plist_path = os.path.join(app_path, "Contents/Info.plist")
|
||||
|
||||
status_code = os.system(f"npx asar pack {input_path} {output_path}")
|
||||
if status_code == 0:
|
||||
print(f"Packed {input_path} into {output_path}")
|
||||
|
||||
if self.checkIfElectronAsarIntegrityIsUsed(app_path):
|
||||
print("ElectronAsarIntegrity is used in Info.plist. Calculating hash and replacing it.")
|
||||
asar_calculator = ASARCalculator(output_path)
|
||||
new_hash = asar_calculator.calcASARHeaderHash()
|
||||
print(f"New hash: {new_hash}")
|
||||
print("Replacing ElectronAsarIntegrity in Info.plist")
|
||||
os.system(f"/usr/libexec/PlistBuddy -c 'Set :ElectronAsarIntegrity:Resources/app.asar:hash {new_hash}' {info_plist_path}")
|
||||
|
||||
print("Resigning app")
|
||||
self.dumpEntitlements(app_path)
|
||||
|
||||
os.system(f"codesign --force --entitlements /tmp/extracted_entitlements.xml --sign - {app_path}")
|
||||
os.remove('/tmp/extracted_entitlements.xml')
|
||||
|
||||
print("Done!")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="ASAR File Operations")
|
||||
subparsers = parser.add_subparsers(dest='command')
|
||||
|
||||
# Subparser for the extract command
|
||||
extract_parser = subparsers.add_parser('extract', help='Extract an ASAR file')
|
||||
extract_parser.add_argument('input_path', type=str, help='Path to the ASAR file to extract')
|
||||
extract_parser.add_argument('output_path', type=str, help='Directory to extract the ASAR file into')
|
||||
|
||||
# Subparser for the pack command
|
||||
pack_parser = subparsers.add_parser('pack', help='Pack files into an ASAR file')
|
||||
pack_parser.add_argument('input_directory', type=str, help='Directory to pack into an ASAR file')
|
||||
pack_parser.add_argument('output_path', type=str, help='Path to the output ASAR file')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
patcher = ASARPatcher()
|
||||
|
||||
if args.command == 'extract':
|
||||
patcher.extractASAR(args.input_path, args.output_path)
|
||||
elif args.command == 'pack':
|
||||
patcher.packASAR(args.input_directory, args.output_path)
|
||||
else:
|
||||
print("Invalid command. Use 'extract' or 'pack'.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user