diff --git a/src/context.ts b/src/context.ts index 22a3407..f174790 100644 --- a/src/context.ts +++ b/src/context.ts @@ -69,7 +69,7 @@ interface ControlFlowLiteral { identifier: string value: string | number } -interface ControlFlowStorage { +export interface ControlFlowStorage { identifier: string aliases: string[] functions: ControlFlowFunction[] @@ -96,9 +96,7 @@ export default class Context { stringDecoders: DecoderFunction[] = [] stringDecoderReferences: DecoderReference[] = [] - controlFlowStorageNodes: { - [x: BlockId]: ControlFlowStorage - } = {} + controlFlowStorageNodes = new Map() removeGarbage: boolean = true transformers: InstanceType[] @@ -112,7 +110,7 @@ export default class Context { ast: Program, transformers: [string, Partial][], isModule: boolean, - source?: string, + source?: string ) { this.ast = ast this.transformers = this.buildTransformerList(transformers) diff --git a/src/transformers/controlflow.ts b/src/transformers/controlflow.ts index a3763a2..357aa53 100644 --- a/src/transformers/controlflow.ts +++ b/src/transformers/controlflow.ts @@ -10,11 +10,12 @@ import { Identifier, ObjectExpression, Statement, + BlockStatement, } from '../util/types' import { Transformer, TransformerOptions } from './transformer' import { walk } from '../util/walk' import * as Guard from '../util/guard' -import Context from '../context' +import Context, { ControlFlowStorage } from '../context' import { immutate, literalOrIdentifierToString, @@ -38,24 +39,33 @@ export default class ControlFlow extends Transformer { if (!fx.body.body[0].argument) throw new TypeError('Function in CFSN was invalid (void return)') - let params = fx.params as Identifier[], - paramMap: { [ident: string]: Node } = {} + const params = fx.params as Identifier[], + paramMap = new Map() let i = 0 for (const p of params) { - paramMap[p.name] = cx.arguments[i] + paramMap.set(p.name, cx.arguments[i]) ++i } let immRtn = immutate(fx.body.body[0].argument) walk(immRtn, { Identifier(id) { - if (!paramMap[id.name]) return - sp(id, paramMap[id.name]) + const node = paramMap.get(id.name) + if (!node) return + sp(id, node) }, }) return immRtn as Node } + private getStorageNode( + context: Context, + node: BlockStatement + ): ControlFlowStorage | undefined { + const bid = getBlockId(node) + return context.controlFlowStorageNodes.get(bid) + } + // fixes empty object inits where there are setters in the same block populateEmptyObjects(context: Context) { walk(context.ast, { @@ -125,7 +135,8 @@ export default class ControlFlow extends Transformer { // /shrug let bid = getBlockId(node) - if (context.controlFlowStorageNodes[bid]) return + let cfsn = context.controlFlowStorageNodes.get(bid) + if (cfsn) return if (node.body.length === 0) return walk(node, { @@ -145,13 +156,14 @@ export default class ControlFlow extends Transformer { ) ) continue - context.controlFlowStorageNodes[bid] = { + + cfsn = { identifier: decl.id.name, aliases: [decl.id.name], functions: [], literals: [], } - const cfsn = context.controlFlowStorageNodes[bid] + context.controlFlowStorageNodes.set(bid, cfsn) for (const prop of decl.init.properties as PropertyLiteral[]) { let kn: Identifier | Literal = prop.key let key = ( @@ -228,12 +240,10 @@ export default class ControlFlow extends Transformer { findStorageNodeAliases = (context: Context, ast: Node) => { walk(ast, { - BlockStatement(node) { - let bid = getBlockId(node) - - if (!context.controlFlowStorageNodes[bid]) return + BlockStatement: (node) => { if (node.body.length === 0) return - const cfsn = context.controlFlowStorageNodes[bid] + const cfsn = this.getStorageNode(context, node) + if (!cfsn) return walk(node, { VariableDeclaration(vd) { @@ -268,11 +278,9 @@ export default class ControlFlow extends Transformer { replacer = (context: Context, ast: Node) => { const { translateCallExp } = this walk(ast, { - BlockStatement(node) { - const bid = getBlockId(node) - if (!context.controlFlowStorageNodes[bid]) return - const cfsn = context.controlFlowStorageNodes[bid] - + BlockStatement: (node) => { + const cfsn = this.getStorageNode(context, node) + if (!cfsn) return walk(node, { MemberExpression(mx) { if (!Guard.isIdentifier(mx.object)) return diff --git a/src/transformers/jsconfuser/controlflow.ts b/src/transformers/jsconfuser/controlflow.ts index c1d1bcb..82fb1e5 100644 --- a/src/transformers/jsconfuser/controlflow.ts +++ b/src/transformers/jsconfuser/controlflow.ts @@ -48,9 +48,7 @@ function inverseOperator(operator: BinaryOperator) { throw new Error("Invalid operator to inverse '" + operator + "'") } } -interface VarStack { - [x: string]: number -} +type VarStack = Map function generateCode(ast: Node): string { return escodegen.generate(ast as any, { sourceMapWithCode: true, @@ -69,31 +67,37 @@ function evaluateAssignmentExpr( operator: AssignmentOperator, value: number ) { + if (operator === '=') return stack.set(vk, value) + + const stackVal = stack.get(vk) + if (typeof stackVal !== 'number') + throw new Error( + 'Unexpected non-numeric value in jsconfuser controlflow stack' + ) + switch (operator) { - case '=': - return (stack[vk] = value) case '+=': - return (stack[vk] += value) + return stack.set(vk, stackVal + value) case '-=': - return (stack[vk] -= value) + return stack.set(vk, stackVal - value) case '*=': - return (stack[vk] *= value) + return stack.set(vk, stackVal * value) case '/=': - return (stack[vk] /= value) + return stack.set(vk, stackVal / value) case '%=': - return (stack[vk] %= value) + return stack.set(vk, stackVal % value) case '<<=': - return (stack[vk] <<= value) + return stack.set(vk, stackVal << value) case '>>=': - return (stack[vk] >>= value) + return stack.set(vk, stackVal >> value) case '>>>=': - return (stack[vk] >>>= value) + return stack.set(vk, stackVal >>> value) case '&=': - return (stack[vk] &= value) + return stack.set(vk, stackVal & value) case '^=': - return (stack[vk] ^= value) + return stack.set(vk, stackVal ^ value) case '|=': - return (stack[vk] |= value) + return stack.set(vk, stackVal | value) default: throw new Error( 'Invalid assignment expression operator "' + operator + '"' @@ -101,9 +105,8 @@ function evaluateAssignmentExpr( } } function updateIdentifiers(stack: VarStack, obj: any) { - for (const vk in stack) { - let value = stack[vk], - node = createLiteral(value) + for (const [vk, value] of stack) { + const node = createLiteral(value) walk(obj, { Identifier(id) { @@ -149,7 +152,7 @@ function evaluateSequenceAssignments( continue } if (!Guard.isIdentifier(expr.left)) continue - if (!(expr.left.name in stack)) continue + if (!stack.has(expr.left.name)) continue const vk = expr.left.name, operator = expr.operator @@ -179,7 +182,7 @@ function evaluateSequenceAssignments( let effect = literalOrUnaryExpressionToNumber(ie) evaluateAssignmentExpr(stack, vk, operator, effect) - log(`stack[${vk}] = ${stack[vk]}`) + log(`stack[${vk}] = ${stack.get(vk)}`) log('='.repeat(32)) ;(expr as any).type = 'EmptyStatement' } @@ -208,24 +211,24 @@ export default class JSCControlFlow extends Transformer { ) continue - const stack: VarStack = {} + const stack: VarStack = new Map() let bx = w.test, additive = false while (Guard.isBinaryExpression(bx)) { additive = bx.operator === '+' if (Guard.isIdentifier(bx.left)) { - stack[bx.left.name] = bx.left.start + stack.set(bx.left.name, bx.left.start) } if (Guard.isIdentifier(bx.right)) { - stack[bx.right.name] = bx.right.start + stack.set(bx.right.name, bx.right.start) } bx = bx.left as BinaryExpression } if (!additive) continue - for (const vk in stack) { + for (const [vk, value] of stack) { let vref = scope.references.find( - (i) => i.identifier.range![0] === stack[vk] + (i) => i.identifier.range![0] === value ) if (!vref) continue if ( @@ -246,7 +249,7 @@ export default class JSCControlFlow extends Transformer { i.range![0] !== def.node.range![0] && i.range![1] !== def.node.range![1] ) - stack[vk] = literalOrUnaryExpressionToNumber(def.node.init) + stack.set(vk, literalOrUnaryExpressionToNumber(def.node.init)) } const endState = literalOrUnaryExpressionToNumber(w.test.right) context.log(stack, endState)