如何反混淆Webpack4拆分打包的JS代码?需优化指定函数可读性
First off, great call using Chrome DevTools breakpoints to map out the function's behavior—that's such a smart first step! Let's walk through deobfuscating this specific function l(e) and turning it into clean, reusable code you can drop into your project.
Step 1: Break Down the Original Logic
First, let's parse what the obfuscated code is actually doing (leaning on your breakpoint insights and common Webpack runtime patterns):
function l(e) { t.d(8, function(e) { for (var n = e.length, r = t.b(n), f = a(), c = 0; c < n; c++) { var i = e.charCodeAt(c); if (i > 127) break; f[r + c] = i } if (c !== n) { 0 !== c && (e = e.slice(c)), r = t.c(r, n, n = c + 3 * e.length); var d = a().subarray(r + c, r + n); c += o(e, d).written } return u = c, r }(e), u); var n, r, f = (null !== i && i.buffer === t.e.buffer || (i = new Int32Array(t.e.buffer)), i), c = (n = f[2], r = f[3], d.decode(a().subarray(n, n + r))).slice(); return t.a(f[2], 1 * f[3]), c }
This is an optimized string decoder (almost certainly for UTF-8) that:
- First processes ASCII characters (charCode ≤127) directly into a shared buffer to save overhead
- Handles non-ASCII characters with a separate encoding step
- Uses Webpack's internal shared buffer to avoid frequent memory allocations
- Decodes the final buffer and cleans up the used memory space
Step 2: Replace Webpack Runtime Helpers with Semantic Code
Webpack's obfuscated variables (t.d, t.b, a(), etc.) are internal runtime utilities. Based on typical behavior and your breakpoint observations, we can swap them out for readable, standard JS equivalents:
t.b(n): Gets the current offset in the shared buffer for ASCII contenta(): Creates aUint8Arrayview of the shared buffert.c(r, n, newLength): Adjusts the buffer offset to accommodate non-ASCII characterso(e, d): Encodes non-ASCII stringeinto theUint8Arrayd(returns bytes written)d.decode: ATextDecoderinstance for UTF-8 decodingt.a: Resets the shared buffer offset to free up space
Step 3: Refactored, Production-Ready Code
Here's the cleaned-up version with semantic variable names and comments. I've kept the core efficiency logic but stripped out Webpack-specific cruft:
// Shared buffer (mimics Webpack's runtime buffer for memory efficiency) const SHARED_BUFFER = new ArrayBuffer(1024 * 16); // Adjust size based on your needs const UINT8_VIEW = new Uint8Array(SHARED_BUFFER); let bufferOffset = 0; // Helper: Get current buffer offset and reserve space for ASCII chars function getAsciiBufferOffset(strLength) { const currentOffset = bufferOffset; bufferOffset += strLength; return currentOffset; } // Helper: Adjust buffer offset to fit non-ASCII content function adjustOffsetForExtendedChars(currentOffset, newTotalLength) { bufferOffset = currentOffset + newTotalLength; return currentOffset; } // Helper: Encode non-ASCII string to Uint8Array function encodeExtendedString(str, targetArray) { const encoder = new TextEncoder(); return { written: encoder.encodeInto(str, targetArray).written }; } // Helper: Reset buffer offset and clear used space (optional but good practice) function releaseBuffer(startOffset, length) { UINT8_VIEW.fill(0, startOffset, startOffset + length); bufferOffset = startOffset; } // The refactored core function (matches your original function's behavior) function decodeOptimizedString(inputStr) { let asciiCharCount = 0; const inputLength = inputStr.length; // Step 1: Process ASCII characters first const asciiStartOffset = getAsciiBufferOffset(inputLength); for (; asciiCharCount < inputLength; asciiCharCount++) { const charCode = inputStr.charCodeAt(asciiCharCount); if (charCode > 127) break; // Stop at first non-ASCII character UINT8_VIEW[asciiStartOffset + asciiCharCount] = charCode; } // Step 2: Handle non-ASCII characters if present if (asciiCharCount !== inputLength) { const remainingStr = inputStr.slice(asciiCharCount); // Reserve 3 bytes per non-ASCII char (safe estimate for UTF-8) const extendedTotalLength = asciiCharCount + 3 * remainingStr.length; adjustOffsetForExtendedChars(asciiStartOffset, extendedTotalLength); const extendedBuffer = UINT8_VIEW.subarray( asciiStartOffset + asciiCharCount, asciiStartOffset + extendedTotalLength ); const encodeResult = encodeExtendedString(remainingStr, extendedBuffer); asciiCharCount += encodeResult.written; } // Step 3: Decode the full buffer to a string const decoder = new TextDecoder('utf-8'); const decodedStr = decoder.decode( UINT8_VIEW.subarray(asciiStartOffset, asciiStartOffset + asciiCharCount) ).slice(); // Step 4: Clean up the shared buffer releaseBuffer(asciiStartOffset, asciiCharCount); return decodedStr; }
Quick Tips for Your Project
- If your original function used a different encoding (not UTF-8), update the
TextEncoder/TextDecoderparameters (e.g.,'iso-8859-1'). - The shared buffer is optional—if you don't need the memory optimization, you can create a new
Uint8Arrayfor each call instead. - I've kept the buffer cleanup step, but you can omit it if memory usage isn't a concern for your use case.
内容的提问来源于stack exchange,提问作者Mahdi

