Files

39 lines
1.9 KiB
JavaScript

// Bounded decoding for common wire encodings. This is not arbitrary deobfuscation.
export function inspectionTextVariants(text,maxBytes){
const values=[],seen=new Set();let size=0,candidates=0;
const budget=Math.min(maxBytes*4,16*1024*1024);
function add(value,depth){
if(typeof value!=='string'||seen.has(value))return;
if(depth>3)throw Error('Inspection normalization limit');
const bytes=Buffer.byteLength(value);
if(values.length>=64||bytes>maxBytes||size+bytes>budget)throw Error('Inspection normalization limit');
if(value.includes('\0'))return;
seen.add(value);size+=bytes;values.push({value,depth});
}
add(text,0);
for(let i=0;i<values.length;i++){
const {value,depth}=values[i];
try{add(decodeURIComponent(value.replace(/\+/g,' ')),depth+1);}catch(error){if(error.message==='Inspection normalization limit')throw error;}
try{const parsed=JSON.parse(value);const queue=[parsed];let nodes=0;
while(queue.length){if(++nodes>4096)throw Error('Inspection normalization limit');const node=queue.pop();
if(typeof node==='string')add(node,depth+1);
else if(node&&typeof node==='object'){
const children=Object.values(node);
if(nodes+queue.length+children.length>4096)throw Error('Inspection normalization limit');
for(const child of children)queue.push(child);
}
}
}catch(error){if(error.message==='Inspection normalization limit')throw error;}
for(const match of value.matchAll(/[A-Za-z0-9+/_-]{12,}={0,2}/g)){
const encoded=match[0].replace(/-/g,'+').replace(/_/g,'/'),raw=Buffer.from(encoded,'base64');
if(raw.toString('base64').replace(/=+$/,'')!==encoded.replace(/=+$/,''))continue;
try{const decoded=new TextDecoder('utf-8',{fatal:true}).decode(raw);
if(decoded.includes('\0'))continue;
if(++candidates>256)throw Error('Inspection normalization limit');
add(decoded,depth+1);
}catch(error){if(error.message==='Inspection normalization limit')throw error;}
}
}
return values.map(row=>row.value);
}