76 lines
4.2 KiB
TypeScript
76 lines
4.2 KiB
TypeScript
import { deflateRawSync } from 'node:zlib';
|
|
|
|
function crc32(bytes: Uint8Array): number {
|
|
let value = 0xffffffff;
|
|
for (const byte of bytes) {
|
|
value ^= byte;
|
|
for (let bit = 0; bit < 8; bit += 1) value = (value >>> 1) ^ (0xedb88320 & -(value & 1));
|
|
}
|
|
return (value ^ 0xffffffff) >>> 0;
|
|
}
|
|
|
|
export function syntheticBaselineArchive(entries: Array<{ path: string; content: Uint8Array }>): Uint8Array {
|
|
const localParts: Buffer[] = [];
|
|
const centralParts: Buffer[] = [];
|
|
let localOffset = 0;
|
|
entries.forEach(entry => {
|
|
const name = Buffer.from(entry.path);
|
|
const compressed = deflateRawSync(entry.content);
|
|
const checksum = crc32(entry.content);
|
|
const local = Buffer.alloc(30 + name.length);
|
|
local.writeUInt32LE(0x04034b50, 0); local.writeUInt16LE(20, 4); local.writeUInt16LE(0x0800, 6); local.writeUInt16LE(8, 8);
|
|
local.writeUInt32LE(checksum, 14); local.writeUInt32LE(compressed.length, 18); local.writeUInt32LE(entry.content.length, 22);
|
|
local.writeUInt16LE(name.length, 26); name.copy(local, 30);
|
|
localParts.push(local, compressed);
|
|
const central = Buffer.alloc(46 + name.length);
|
|
central.writeUInt32LE(0x02014b50, 0); central.writeUInt16LE(20, 4); central.writeUInt16LE(20, 6);
|
|
central.writeUInt16LE(0x0800, 8); central.writeUInt16LE(8, 10); central.writeUInt32LE(checksum, 16);
|
|
central.writeUInt32LE(compressed.length, 20); central.writeUInt32LE(entry.content.length, 24); central.writeUInt16LE(name.length, 28);
|
|
central.writeUInt32LE(localOffset, 42); name.copy(central, 46); centralParts.push(central);
|
|
localOffset += local.length + compressed.length;
|
|
});
|
|
const directory = Buffer.concat(centralParts);
|
|
const end = Buffer.alloc(22);
|
|
end.writeUInt32LE(0x06054b50, 0); end.writeUInt16LE(entries.length, 8); end.writeUInt16LE(entries.length, 10);
|
|
end.writeUInt32LE(directory.length, 12); end.writeUInt32LE(localOffset, 16);
|
|
return Buffer.concat([...localParts, directory, end]);
|
|
}
|
|
|
|
function registryPolicy(typeCode = 4): Uint8Array {
|
|
const unicode = (text: string) => Buffer.from(text, 'utf16le');
|
|
const header = Buffer.alloc(8); header.write('PReg'); header.writeUInt32LE(1, 4);
|
|
const type = Buffer.alloc(4); type.writeUInt32LE(typeCode);
|
|
const size = Buffer.alloc(4); size.writeUInt32LE(4);
|
|
const data = Buffer.alloc(4); data.writeUInt32LE(1);
|
|
return Buffer.concat([
|
|
header, unicode('['), unicode('Software\\Policies\\Synthetic'), Buffer.alloc(2), unicode(';'),
|
|
unicode('Mode'), Buffer.alloc(2), unicode(';'), type, unicode(';'), size, unicode(';'), data, unicode(']')
|
|
]);
|
|
}
|
|
|
|
const xmlNamespace = 'http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions';
|
|
const root = 'Synthetic Baseline/GPOs/{11111111-1111-4111-8111-111111111111}';
|
|
|
|
export function syntheticMicrosoftBaselineZip(typeCode = 4, securityTemplate?: string): Uint8Array {
|
|
return syntheticBaselineArchive([
|
|
{
|
|
path: `${root}/Backup.xml`,
|
|
content: Buffer.from('<?xml version="1.0"?><BackupInst><ID>{22222222-2222-4222-8222-222222222222}</ID><GPOGuid>{33333333-3333-4333-8333-333333333333}</GPOGuid><GPODomain>baseline.invalid</GPODomain><BackupTime>2026-08-04T10:00:00Z</BackupTime></BackupInst>')
|
|
},
|
|
{ path: `${root}/DomainSysvol/GPO/Machine/Registry.pol`, content: registryPolicy(typeCode) },
|
|
...(securityTemplate === undefined ? [] : [{
|
|
path: `${root}/DomainSysvol/GPO/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf`,
|
|
content: Buffer.from(securityTemplate)
|
|
}]),
|
|
{
|
|
path: 'Synthetic Baseline/Templates/Synthetic.admx',
|
|
content: Buffer.from(`<policyDefinitions xmlns="${xmlNamespace}"><policyNamespaces><target prefix="synthetic" namespace="Synthetic.Policies" /></policyNamespaces><policies><policy name="Mode" class="Machine" displayName="$(string.Mode)" key="Software\\Policies\\Synthetic" valueName="Mode" /></policies></policyDefinitions>`)
|
|
},
|
|
{
|
|
path: 'Synthetic Baseline/Templates/en-US/Synthetic.adml',
|
|
content: Buffer.from(`<policyDefinitionResources xmlns="${xmlNamespace}"><resources><stringTable><string id="Mode">Synthetic mode</string></stringTable></resources></policyDefinitionResources>`)
|
|
},
|
|
{ path: 'Synthetic Baseline/Documentation/Baseline.xlsx', content: new Uint8Array([0x50, 0x4b, 0x03, 0x04, 1, 2, 3, 4]) }
|
|
]);
|
|
}
|