Refactor PE scan buffer decoding and checks

Replace custom hex decoding and helper with direct PE.readBytes, removing hexLUT and getDecodedBuffer to reduce overhead. Simplify scanBuffer signature and internals (rename comment, local caching, remove unused offsetBase), tighten verifyPeSignature comments and remove redundant explanatory comments. Use PE.readBytes for resources, overlay and sections, and keep existing algorithm detection logic intact; this is a cleanup/optimization to improve readability and performance without changing core behavior.
This commit is contained in:
DosX 2026-06-22 16:15:17 +03:00
commit c4c388de73

View file

@ -7867,7 +7867,7 @@ function scanForMaliciousCode_NET_and_Native() {
var k0_off = new Uint8Arr(21),
k1_off = new Uint8Arr(21),
k3_off = new Uint8Arr(21),
lfa0_off = new Uint8Arr(21), // Pre-calculated offsets for e_lfanew
lfa0_off = new Uint8Arr(21),
lfa1_off = new Uint8Arr(21),
lfa2_off = new Uint8Arr(21),
lfa3_off = new Uint8Arr(21);
@ -7877,35 +7877,22 @@ function scanForMaliciousCode_NET_and_Native() {
k1_off[len] = 40 + ((1 + len - (40 % len)) % len);
k3_off[len] = 40 + ((3 + len - (40 % len)) % len);
// 0x3C is 60. Offset from e_res2 is 60 - 40 = 20
lfa0_off[len] = 40 + (20 % len);
lfa1_off[len] = 40 + (21 % len);
lfa2_off[len] = 40 + (22 % len);
lfa3_off[len] = 40 + (23 % len);
}
// LUT (Lookup Table) for ULTRA-FAST Hex to Byte decoding
var hexLUT = new Uint8Arr(256);
for (var i = 0; i < 256; i++) hexLUT[i] = 0;
for (var i = 48; i <= 57; i++) hexLUT[i] = i - 48; // 0-9
for (var i = 65; i <= 70; i++) hexLUT[i] = i - 55; // A-F
for (var i = 97; i <= 102; i++) hexLUT[i] = i - 87; // a-f
// Strict PE header verification function.
// mode 0: Bitwise algorithms (XOR, XNOR)
// mode 1: Arithmetic algorithms (ADD, SUB)
// mode 2: Arithmetic Reverse algorithms (SUB-REV)
// Strict PE header verification function
function verifyPeSignature(dataBuffer, peStartOffset, maxValidLfaNew, keyLength, mode) {
var z, c, b2, b1, b0;
// Fast fail: Check if upper 16-bits already exceed max search bounds
z = dataBuffer[peStartOffset + lfa2_off[keyLength]];
c = dataBuffer[peStartOffset + 0x3E];
b2 = mode === 0 ? (c ^ z) : (mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF));
if ((b2 << 16) >= maxValidLfaNew) return false;
// Decode remaining e_lfanew bytes (byte 3 is implicitly 0x00 at this stage)
z = dataBuffer[peStartOffset + lfa1_off[keyLength]];
c = dataBuffer[peStartOffset + 0x3D];
b1 = mode === 0 ? (c ^ z) : (mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF));
@ -7916,15 +7903,12 @@ function scanForMaliciousCode_NET_and_Native() {
var lfaNewOffset = (b0 | (b1 << 8) | (b2 << 16)) >>> 0;
// Sanity check for the e_lfanew pointer
if (lfaNewOffset > 0x40 && lfaNewOffset < maxValidLfaNew) {
var peHeaderOffset = lfaNewOffset,
baseZ = peStartOffset + 40,
pe = peStartOffset + peHeaderOffset,
// Calculate base remainder ONCE to avoid repeated expensive modulo operations
r = (lfaNewOffset - 40) % keyLength;
// 1. Verify PE Signature (PE\0\0)
z = dataBuffer[baseZ + ((r + 0) % keyLength)]; c = dataBuffer[pe + 0];
if ((mode === 0 ? (c ^ z) : mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF)) !== 0x50) return false;
@ -7937,7 +7921,6 @@ function scanForMaliciousCode_NET_and_Native() {
z = dataBuffer[baseZ + ((r + 3) % keyLength)]; c = dataBuffer[pe + 3];
if ((mode === 0 ? (c ^ z) : mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF)) !== 0x00) return false;
// 2. Verify Optional Header Magic (PE32=0x10B, PE64=0x20B)
var m1, m2;
z = dataBuffer[baseZ + ((r + 0x18) % keyLength)]; c = dataBuffer[pe + 0x18];
m1 = mode === 0 ? (c ^ z) : mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF);
@ -7948,7 +7931,6 @@ function scanForMaliciousCode_NET_and_Native() {
var magic = m1 | (m2 << 8);
if (magic !== 0x010B && magic !== 0x020B) return false;
// 3. Verify NumberOfSections (IMAGE_FILE_HEADER)
var ns1, ns2;
z = dataBuffer[baseZ + ((r + 0x06) % keyLength)]; c = dataBuffer[pe + 0x06];
ns1 = mode === 0 ? (c ^ z) : mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF);
@ -7959,7 +7941,6 @@ function scanForMaliciousCode_NET_and_Native() {
var numSections = ns1 | (ns2 << 8);
if (numSections === 0 || numSections > 48) return false;
// 4. Verify Characteristics (IMAGE_FILE_HEADER)
var ch1, ch2;
z = dataBuffer[baseZ + ((r + 0x16) % keyLength)]; c = dataBuffer[pe + 0x16];
ch1 = mode === 0 ? (c ^ z) : mode === 1 ? ((c - z) & 0xFF) : ((z - c) & 0xFF);
@ -7975,12 +7956,12 @@ function scanForMaliciousCode_NET_and_Native() {
return false;
}
// Scan function to avoid code duplication
function scanBuffer(dataBuffer, bufferSize, offsetBase) {
// Core scanner
function scanBuffer(dataBuffer, bufferSize) {
var maxSearchIndex = bufferSize - 0x100,
j = 0, L = 1, b0, b1, e0_bit, e1_bit, d3, d3F, c0,
e0_math, e1_math, e0_rev, e1_rev, maxLfa,
_k0 = k0_off, _k1 = k1_off, _k3 = k3_off, _lfa3 = lfa3_off; // Local variable cache
_k0 = k0_off, _k1 = k1_off, _k3 = k3_off, _lfa3 = lfa3_off;
for (; j < maxSearchIndex; j++) {
b0 = dataBuffer[j];
@ -7988,44 +7969,41 @@ function scanForMaliciousCode_NET_and_Native() {
e0_bit = b0 ^ 0x4D;
e1_bit = b1 ^ 0x5A;
// Skip if both e0_bit and e1_bit are zero, as it indicates no encryption
if (e0_bit === 0x00 && e1_bit === 0x00) continue;
d3 = dataBuffer[j + 3];
d3F = dataBuffer[j + 0x3F]; // Read MSB of e_lfanew ONCE per iteration
d3F = dataBuffer[j + 0x3F];
maxLfa = bufferSize - j - 0x20;
for (L = 1; L <= 20; L++) {
if (d3 !== dataBuffer[j + _k3[L]]) continue;
// Universal Lock: If MSB of e_lfanew is 0x00 (which it always is),
// its ciphertext MUST equal its exact key byte in ALL supported algorithms.
if (d3F !== dataBuffer[j + _lfa3[L]]) continue;
c0 = dataBuffer[j + _k0[L]];
if (c0 === e0_bit && dataBuffer[j + _k1[L]] === e1_bit) {
if (verifyPeSignature(dataBuffer, j, maxLfa, L, 0)) {
detectedAlgo = "XOR-XNOR"; return true;
detectedAlgo = "XOR-XNOR";
return true;
}
} else {
// LAZY EVALUATION: Execute this only if the previous checks failed
e0_math = (b0 - 0x4D) & 0xFF;
if (c0 === e0_math) {
e1_math = (b1 - 0x5A) & 0xFF;
if (dataBuffer[j + _k1[L]] === e1_math) {
if (verifyPeSignature(dataBuffer, j, maxLfa, L, 1)) {
detectedAlgo = "ADD-SUB"; return true;
detectedAlgo = "ADD-SUB";
return true;
}
}
} else {
// LAZY EVALUATION: Execute this only if the previous checks failed
e0_rev = (b0 + 0x4D) & 0xFF;
if (c0 === e0_rev) {
e1_rev = (b1 + 0x5A) & 0xFF;
if (dataBuffer[j + _k1[L]] === e1_rev) {
if (verifyPeSignature(dataBuffer, j, maxLfa, L, 2)) {
detectedAlgo = "SUB-REV"; return true;
detectedAlgo = "SUB-REV";
return true;
}
}
}
@ -8037,31 +8015,16 @@ function scanForMaliciousCode_NET_and_Native() {
return false;
}
// Helper function to decode hex signature into a byte array
function getDecodedBuffer(offset, size) {
var hexSignature = PE.getSignature(offset, size),
buffer = new Uint8Arr(size),
k = 0, p = 0,
lut = hexLUT; // Cache global LUT locally
for (; k < size; k++, p += 2) {
buffer[k] = (lut[hexSignature.charCodeAt(p)] << 4) | lut[hexSignature.charCodeAt(p + 1)];
}
return buffer;
}
// 1. Scan Resources
for (var i = 0; i < PE_Cached.numberOfUnmanagedResources && !isEncPePresent; i++) {
var resourceOffset = PE.getResourceOffsetByNumber(i),
resourceSize = PE.getResourceSizeByNumber(i);
// Target actual payloads (> 4 KB) and skip bitmaps
if (resourceOffset > 0 && resourceSize > 0x1000 && !PE.compare("28 00 00 00 ?? ?? 00 00 ?? ?? 00 00 01 00 ?? 00 00 00 00 00", resourceOffset)) {
var maxScanSize = Math.min(resourceSize, 0x1000),
dataBuffer = getDecodedBuffer(resourceOffset, maxScanSize);
dataBuffer = PE.readBytes(resourceOffset, maxScanSize);
if (scanBuffer(dataBuffer, maxScanSize, resourceOffset)) { isEncPePresent = true; break; }
if (scanBuffer(dataBuffer, maxScanSize)) { isEncPePresent = true; break; }
}
}
@ -8072,9 +8035,9 @@ function scanForMaliciousCode_NET_and_Native() {
if (overlayOffset > 0 && overlaySize > 0x1000 && !PE.isSigned()) {
var maxScanSize = Math.min(overlaySize, 0x14000),
dataBuffer = getDecodedBuffer(overlayOffset, maxScanSize);
dataBuffer = PE.readBytes(overlayOffset, maxScanSize);
if (scanBuffer(dataBuffer, maxScanSize, overlayOffset)) isEncPePresent = true;
if (scanBuffer(dataBuffer, maxScanSize)) isEncPePresent = true;
}
}
@ -8085,7 +8048,6 @@ function scanForMaliciousCode_NET_and_Native() {
sectionSize = PE.getSectionFileSize(i),
sectionName = PE.getSectionName(i);
// Optimizations: Skip known sections that are unlikely to contain encrypted payloads
if (PE_Cached.numberOfSections > 1) {
if (sectionOffset > 0 && sectionSize < 0x2500) {
continue;
@ -8101,12 +8063,11 @@ function scanForMaliciousCode_NET_and_Native() {
}
var maxScanSize = (PE_Cached.isDotNet && i === 0) ?
Math.min(sectionSize, 0x64000) : // Scan larger areas for .text section in .NET assemblies, smaller for others
Math.min(sectionSize, sectionName.match(/^\.[rex]?data$/i) ? 0x12000 : 0x6000), // Scan larger areas for .data, .rdata, .edata sections, smaller for others
Math.min(sectionSize, 0x64000) :
Math.min(sectionSize, sectionName.match(/^\.[rex]?data$/i) ? 0x12000 : 0x6000),
dataBuffer = PE.readBytes(sectionOffset, maxScanSize);
dataBuffer = getDecodedBuffer(sectionOffset, maxScanSize);
if (scanBuffer(dataBuffer, maxScanSize, sectionOffset)) { isEncPePresent = true; break; }
if (scanBuffer(dataBuffer, maxScanSize)) { isEncPePresent = true; break; }
}
}