mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-04 15:14:49 +00:00
AVM2 Deobfuscator stub (similar to ActionDeobfuscator)
This commit is contained in:
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.deobfuscation.*;
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.action.ActionLocalData;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.ReturnActionItem;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionEnd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionGetVariable;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionLess;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionMultiply;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionNot;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionSubtract;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ConstantIndex;
|
||||
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionAdd2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitAnd;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitLShift;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitOr;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitXor;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionCallFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionLess2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionModulo;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionReturn;
|
||||
import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.ecma.Undefined;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 Deobfuscator - FIXME!!! Not ready yet!
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Deobfuscator extends AVM2DeobfuscatorSimple {
|
||||
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions, SWF swf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deobfuscate(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
removeZeroJumps(body.getCode(), body);
|
||||
}
|
||||
|
||||
private boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
|
||||
AVM2Code code = body.getCode();
|
||||
if (code.code.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
System.err.println("=============================================");
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
System.err.println("Execute from " + i);
|
||||
executeActions(classIndex, isStatic, body, scriptIndex, abc, code, i, code.code.size() - 1, result);
|
||||
|
||||
if (result.idx != -1) {
|
||||
int newIstructionCount = 1; // jump
|
||||
if (!result.stack.isEmpty()) {
|
||||
newIstructionCount++;
|
||||
}
|
||||
newIstructionCount += 2 * result.variables.size();
|
||||
|
||||
if (newIstructionCount * 2 < result.instructionsProcessed) {
|
||||
AVM2Instruction target = code.code.get(result.idx);
|
||||
AVM2Instruction prevAction = code.code.get(i);
|
||||
|
||||
for (int variableName : result.variables.keySet()) {
|
||||
Object value = result.variables.get(variableName);
|
||||
/*ActionPush push = new ActionPush(variableName);
|
||||
push.values.add(value);*/
|
||||
AVM2Instruction push = makePush(value, cpool);
|
||||
|
||||
code.insertInstruction(i++, push);
|
||||
push.offset = prevAction.offset;
|
||||
|
||||
code.insertInstruction(i++, push);
|
||||
prevAction = push;
|
||||
|
||||
/*if (result.defines.contains(variableName)) {
|
||||
//ActionDefineLocal defineLocal = new ActionDefineLocal();
|
||||
AVM2Instruction defineLocal = new AVM2Instruction(prevAction.offset, new SetLocalIns(), new int[]{});
|
||||
defineLocal.setAddress(prevAction.getAddress());
|
||||
code.addAction(i++, defineLocal);
|
||||
prevAction = defineLocal;
|
||||
} else {
|
||||
ActionSetVariable setVariable = new ActionSetVariable();
|
||||
setVariable.setAddress(prevAction.getAddress());
|
||||
code.addAction(i++, setVariable);
|
||||
prevAction = setVariable;
|
||||
}*/
|
||||
AVM2Instruction setVariable = new AVM2Instruction(prevAction.offset, new SetLocalIns(), new int[]{});
|
||||
code.insertInstruction(i++, setVariable);
|
||||
prevAction = setVariable;
|
||||
}
|
||||
|
||||
if (!result.stack.isEmpty()) {
|
||||
//ActionPush push = new ActionPush(0);
|
||||
//push.values.clear();
|
||||
long ofs = prevAction.offset;
|
||||
for (GraphTargetItem graphTargetItem : result.stack) {
|
||||
//DirectValueActionItem dv = (DirectValueActionItem) graphTargetItem;
|
||||
//push.values.add(dv.value);
|
||||
AVM2Instruction push = makePush(cpool, graphTargetItem);
|
||||
push.offset = ofs;
|
||||
code.insertInstruction(i++, push);
|
||||
ofs += push.getBytes().length;
|
||||
prevAction = push;
|
||||
}
|
||||
}
|
||||
|
||||
//ctionJump jump = new ActionJump(0);
|
||||
AVM2Instruction jump = new AVM2Instruction(prevAction.offset, new JumpIns(), new int[]{0});
|
||||
//jump.setAddress(prevAction.getAddress());
|
||||
jump.operands[0] = (int) (target.offset - jump.offset - jump.getBytes().length);
|
||||
code.insertInstruction(i++, jump);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) {
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
localData.isStatic = isStatic;
|
||||
localData.classIndex = classIndex;
|
||||
localData.localRegs = new HashMap<>();
|
||||
localData.scopeStack = new ScopeStack();
|
||||
localData.constants = cpool;
|
||||
localData.methodInfo = abc.method_info;
|
||||
localData.methodBody = body;
|
||||
localData.abc = abc;
|
||||
localData.localRegNames = new HashMap<>();
|
||||
localData.fullyQualifiedNames = new ArrayList<>();
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
localData.finallyJumps = new HashMap<>();
|
||||
localData.ignoredSwitches = new HashMap<>();
|
||||
localData.ignoredSwitches2 = new ArrayList<>();
|
||||
localData.scriptIndex = scriptIndex;
|
||||
localData.localRegAssignmentIps = new HashMap<>();
|
||||
localData.ip = 0;
|
||||
localData.refs = new HashMap<>();
|
||||
localData.code = body.getCode();
|
||||
return localData;
|
||||
}
|
||||
|
||||
private void executeActions(int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
|
||||
localData.localRegs.put(0, new NullAVM2Item(null));//this
|
||||
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
|
||||
int instructionsProcessed = 0;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (idx > endIdx) {
|
||||
break;
|
||||
}
|
||||
|
||||
AVM2Instruction action = code.code.get(idx);
|
||||
instructionsProcessed++;
|
||||
|
||||
if (instructionsProcessed > executionLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*if (action instanceof ActionDefineLocal) {
|
||||
GraphTargetItem top = stack.pop();
|
||||
String variableName = stack.peek().getResult().toString();
|
||||
result.defines.add(variableName);
|
||||
stack.push(top);
|
||||
}*/
|
||||
if (action.definition instanceof GetLocalTypeIns) {
|
||||
int regId = ((GetLocalTypeIns) action.definition).getRegisterId(action);//stack.peek().getResult().toString();
|
||||
if (!localData.localRegs.containsKey(regId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*if (action instanceof ActionCallFunction) {
|
||||
String functionName = stack.pop().getResult().toString();
|
||||
long numArgs = EcmaScript.toUint32(stack.pop().getResult());
|
||||
if (numArgs == 0) {
|
||||
if (fakeFunctions != null && fakeFunctions.containsKey(functionName)) {
|
||||
stack.push(new DirectValueActionItem(fakeFunctions.get(functionName)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
}*/
|
||||
System.err.println("Translating " + action);
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
Class allowedDefs[] = new Class[]{
|
||||
PushByteIns.class,
|
||||
PushShortIns.class,
|
||||
PushIntIns.class,
|
||||
PushDoubleIns.class,
|
||||
PushStringIns.class,
|
||||
PushNullIns.class,
|
||||
PushUndefinedIns.class,
|
||||
PushFalseIns.class,
|
||||
PushTrueIns.class,
|
||||
DupIns.class,
|
||||
SwapIns.class,
|
||||
AddIns.class,
|
||||
AddIIns.class,
|
||||
SubtractIns.class,
|
||||
SubtractIIns.class,
|
||||
ModuloIns.class,
|
||||
MultiplyIns.class,
|
||||
BitAndIns.class,
|
||||
BitXorIns.class,
|
||||
BitOrIns.class,
|
||||
LShiftIns.class,
|
||||
RShiftIns.class,
|
||||
URShiftIns.class,
|
||||
EqualsIns.class,
|
||||
NotIns.class,
|
||||
IfTypeIns.class,
|
||||
JumpIns.class,
|
||||
IncrementIns.class,
|
||||
IncrementIIns.class,
|
||||
DecrementIns.class,
|
||||
DecrementIIns.class,
|
||||
SetLocalTypeIns.class,
|
||||
GetLocalTypeIns.class,
|
||||
GreaterEqualsIns.class,
|
||||
GreaterThanIns.class,
|
||||
LessThanIns.class,
|
||||
LessEqualsIns.class,
|
||||
StrictEqualsIns.class,
|
||||
IfTypeIns.class,
|
||||
ReturnVoidIns.class,
|
||||
ReturnValueIns.class,
|
||||
NewFunctionIns.class,
|
||||
PopIns.class,
|
||||
PushScopeIns.class
|
||||
};
|
||||
|
||||
InstructionDefinition def = action.definition;
|
||||
|
||||
boolean ok = false;
|
||||
for (Class<?> s : allowedDefs) {
|
||||
if (s.isAssignableFrom(def.getClass())) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
System.err.println("Broken");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*for (String variable : localData.variables.keySet()) {
|
||||
System.out.println(Helper.byteArrToString(variable.getBytes()));
|
||||
}*/
|
||||
idx++;
|
||||
|
||||
if (action.definition instanceof JumpIns) {
|
||||
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (action.definition instanceof IfTypeIns) {
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("If target not found: " + address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (/*localData.variables.size() == 1 && */stack.allItemsFixed()) {
|
||||
result.idx = idx == code.code.size() ? idx - 1 : idx;
|
||||
result.instructionsProcessed = instructionsProcessed;
|
||||
result.variables.clear();
|
||||
for (int variableName : localData.localRegs.keySet()) {
|
||||
Object value = localData.localRegs.get(variableName).getResult();
|
||||
result.variables.put(variableName, value);
|
||||
}
|
||||
result.stack.clear();
|
||||
result.stack.addAll(stack);
|
||||
}
|
||||
|
||||
if (action.definition instanceof ReturnValueIns) {
|
||||
if (output.size() > 0) {
|
||||
ReturnValueAVM2Item ret = (ReturnValueAVM2Item) output.get(output.size() - 1);
|
||||
result.resultValue = ret.value.getResult();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (action.definition instanceof ReturnVoidIns) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
|
||||
//ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/*private Map<String, Object> getFakeFunctionResults(ActionList actions) {
|
||||
|
||||
Map<String, Object> results = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action action = actions.get(i);
|
||||
if (action instanceof ActionDefineFunction) {
|
||||
ActionDefineFunction def = (ActionDefineFunction) action;
|
||||
if (def.paramNames.isEmpty()) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
List<Action> lastActions = actions.getContainerLastActions(action);
|
||||
int lastActionIdx = actions.indexOf(lastActions.get(0));
|
||||
executeActions(actions, i + 1, lastActionIdx, null, result, null);
|
||||
if (result.resultValue != null) {
|
||||
results.put(def.functionName, result.resultValue);
|
||||
for (int j = i; j <= lastActionIdx; j++) {
|
||||
actions.removeAction(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] proxyFileCatched(byte[] data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swfParsed(SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abcParsed(ABC abc, SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodBodyParsed(MethodBody body, SWF swf) {
|
||||
}*/
|
||||
class ExecutionResult {
|
||||
|
||||
public int idx = -1;
|
||||
|
||||
public int instructionsProcessed = -1;
|
||||
|
||||
//public ActionConstantPool constantPool;
|
||||
public Map<Integer, Object> variables = new HashMap<>();
|
||||
|
||||
//public Set<String> defines = new HashSet<>();
|
||||
public TranslateStack stack = new TranslateStack("?");
|
||||
|
||||
public ScopeStack scopeStack = new ScopeStack();
|
||||
|
||||
public Object resultValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.flash.ecma.Undefined;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.model.FalseItem;
|
||||
import com.jpexs.decompiler.graph.model.TrueItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions, SWF swf) {
|
||||
|
||||
}
|
||||
|
||||
protected AVM2Instruction makePush(Object ovalue, AVM2ConstantPool cpool) {
|
||||
if (ovalue instanceof Long) {
|
||||
long value = (Long) ovalue;
|
||||
if (value >= -128 && value <= 127) {
|
||||
return new AVM2Instruction(0, new PushByteIns(), new int[]{(int) (long) value});
|
||||
} else if (value >= -32768 && value <= 32767) {
|
||||
return new AVM2Instruction(0, new PushShortIns(), new int[]{((int) (long) value) & 0xffff});
|
||||
} else {
|
||||
return new AVM2Instruction(0, new PushIntIns(), new int[]{cpool.getIntId(value, true)});
|
||||
}
|
||||
}
|
||||
if (ovalue instanceof Double) {
|
||||
return new AVM2Instruction(0, new PushDoubleIns(), new int[]{cpool.getDoubleId((Double) ovalue, true)});
|
||||
}
|
||||
if (ovalue instanceof String) {
|
||||
return new AVM2Instruction(0, new PushStringIns(), new int[]{cpool.getStringId((String) ovalue, true)});
|
||||
}
|
||||
if (ovalue instanceof Boolean) {
|
||||
if ((Boolean) ovalue) {
|
||||
return new AVM2Instruction(0, new PushTrueIns(), new int[]{});
|
||||
}
|
||||
return new AVM2Instruction(0, new PushFalseIns(), new int[]{});
|
||||
}
|
||||
if (ovalue instanceof Null) {
|
||||
return new AVM2Instruction(0, new PushNullIns(), new int[]{});
|
||||
}
|
||||
if (ovalue instanceof Undefined) {
|
||||
return new AVM2Instruction(0, new PushUndefinedIns(), new int[]{});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected AVM2Instruction makePush(AVM2ConstantPool cpool, GraphTargetItem graphTargetItem) {
|
||||
AVM2Instruction ins = null;
|
||||
if (graphTargetItem instanceof IntegerValueAVM2Item) {
|
||||
IntegerValueAVM2Item iv = (IntegerValueAVM2Item) graphTargetItem;
|
||||
return makePush(iv.value, cpool);
|
||||
} else if (graphTargetItem instanceof FloatValueAVM2Item) {
|
||||
FloatValueAVM2Item fv = (FloatValueAVM2Item) graphTargetItem;
|
||||
return makePush(fv.value, cpool);
|
||||
} else if (graphTargetItem instanceof StringAVM2Item) {
|
||||
StringAVM2Item fv = (StringAVM2Item) graphTargetItem;
|
||||
return makePush(fv.value, cpool);
|
||||
} else if (graphTargetItem instanceof TrueItem) {
|
||||
return makePush(Boolean.TRUE, cpool);
|
||||
} else if (graphTargetItem instanceof FalseItem) {
|
||||
return makePush(Boolean.FALSE, cpool);
|
||||
} else if (graphTargetItem instanceof NullAVM2Item) {
|
||||
return makePush(new Null(), cpool);
|
||||
} else if (graphTargetItem instanceof UndefinedAVM2Item) {
|
||||
return makePush(new Undefined(), cpool);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
if (code.code.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
System.err.println("=====================================================");
|
||||
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
System.err.println("Execute from " + i);
|
||||
executeActions(code, i, code.code.size() - 1, result);
|
||||
|
||||
if (result.idx != -1) {
|
||||
int newIstructionCount = 1; // jump
|
||||
if (!result.stack.isEmpty()) {
|
||||
newIstructionCount += result.stack.size();
|
||||
}
|
||||
|
||||
if (newIstructionCount < result.instructionsProcessed) {
|
||||
AVM2Instruction target = code.code.get(result.idx);
|
||||
AVM2Instruction prevAction = code.code.get(i);
|
||||
|
||||
if (result.stack.isEmpty() && prevAction.definition instanceof JumpIns) {
|
||||
prevAction.operands[0] = ((int) (target.getOffset() - prevAction.getOffset() - prevAction.getBytes().length));
|
||||
} else {
|
||||
if (!result.stack.isEmpty()) {
|
||||
for (GraphTargetItem graphTargetItem : result.stack) {
|
||||
AVM2Instruction ins = makePush(cpool, graphTargetItem);
|
||||
if (ins != null) {
|
||||
code.insertInstruction(i++, ins);
|
||||
}
|
||||
prevAction = ins;
|
||||
//DirectValueActionItem dv = (DirectValueActionItem) graphTargetItem;
|
||||
//push.values.add(dv.value);
|
||||
}
|
||||
//push.setAddress(prevAction.getAddress());
|
||||
|
||||
}
|
||||
|
||||
AVM2Instruction jump = new AVM2Instruction(0, new JumpIns(), new int[]{0});
|
||||
jump.offset = prevAction.offset;
|
||||
jump.operands[0] = ((int) (target.offset - jump.offset - jump.getBytes().length));
|
||||
code.insertInstruction(i++, jump);
|
||||
}
|
||||
|
||||
AVM2Instruction nextAction = code.code.size() > i ? code.code.get(i) : null;
|
||||
|
||||
removeUnreachableActions(code, cpool, trait, minfo, body);
|
||||
removeZeroJumps(code, body);
|
||||
|
||||
if (nextAction != null) {
|
||||
int nextIdx = code.code.indexOf(nextAction);
|
||||
if (nextIdx < i) {
|
||||
i = nextIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void removeUnreachableActions(AVM2Code code, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
code.removeDeadCode(cpool, trait, minfo, body);
|
||||
}
|
||||
|
||||
protected boolean removeZeroJumps(AVM2Code actions, MethodBody body) {
|
||||
boolean result = false;
|
||||
for (int i = 0; i < actions.code.size(); i++) {
|
||||
AVM2Instruction action = actions.code.get(i);
|
||||
if (action.definition instanceof JumpIns && action.operands[0] == 0) {
|
||||
actions.removeInstruction(i, body);
|
||||
i--;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void executeActions(AVM2Code code, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
|
||||
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
|
||||
int instructionsProcessed = 0;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (idx > endIdx) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (instructionsProcessed > executionLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
AVM2Instruction action = code.code.get(idx);
|
||||
|
||||
/*System.out.print(action.getASMSource(actions, new ArrayList<Long>(), ScriptExportMode.PCODE));
|
||||
for (int j = 0; j < stack.size(); j++) {
|
||||
System.out.print(" '" + stack.get(j).getResult() + "'");
|
||||
}
|
||||
System.out.println();*/
|
||||
InstructionDefinition def = action.definition;
|
||||
|
||||
Class allowedDefs[] = new Class[]{
|
||||
PushByteIns.class,
|
||||
PushShortIns.class,
|
||||
PushIntIns.class,
|
||||
PushDoubleIns.class,
|
||||
PushStringIns.class,
|
||||
PushNullIns.class,
|
||||
PushUndefinedIns.class,
|
||||
PushFalseIns.class,
|
||||
PushTrueIns.class,
|
||||
DupIns.class,
|
||||
SwapIns.class,
|
||||
AddIns.class,
|
||||
AddIIns.class,
|
||||
SubtractIns.class,
|
||||
SubtractIIns.class,
|
||||
ModuloIns.class,
|
||||
MultiplyIns.class,
|
||||
BitAndIns.class,
|
||||
BitXorIns.class,
|
||||
BitOrIns.class,
|
||||
LShiftIns.class,
|
||||
RShiftIns.class,
|
||||
URShiftIns.class,
|
||||
EqualsIns.class,
|
||||
NotIns.class,
|
||||
IfTypeIns.class,
|
||||
JumpIns.class
|
||||
};
|
||||
|
||||
boolean ok = false;
|
||||
for (Class<?> s : allowedDefs) {
|
||||
if (s.isAssignableFrom(def.getClass())) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
|
||||
idx++;
|
||||
|
||||
if (def instanceof JumpIns) {
|
||||
//ActionJump jump = (ActionJump) action;
|
||||
long address = action.getOffset() + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (def instanceof IfTypeIns) {
|
||||
//ActionIf aif = (ActionIf) action;
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("If target not found: " + address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instructionsProcessed++;
|
||||
|
||||
if (stack.allItemsFixed()) {
|
||||
result.idx = idx == code.code.size() ? idx - 1 : idx;
|
||||
result.instructionsProcessed = instructionsProcessed;
|
||||
result.stack.clear();
|
||||
result.stack.addAll(stack);
|
||||
}
|
||||
}
|
||||
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] proxyFileCatched(byte[] data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swfParsed(SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abcParsed(ABC abc, SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodBodyParsed(MethodBody body, SWF swf) {
|
||||
|
||||
}
|
||||
|
||||
public void deobfuscate(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
removeZeroJumps(body.getCode(), body);
|
||||
}
|
||||
|
||||
class ExecutionResult {
|
||||
|
||||
public int idx = -1;
|
||||
|
||||
public int instructionsProcessed = -1;
|
||||
|
||||
public TranslateStack stack = new TranslateStack("?");
|
||||
|
||||
public Object resultValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FixItemCounterTranslateStack extends TranslateStack {
|
||||
|
||||
private int fixItemCount = Integer.MAX_VALUE;
|
||||
|
||||
public FixItemCounterTranslateStack(String path) {
|
||||
super(null); //null path => do not add PushItems
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTargetItem pop() {
|
||||
GraphTargetItem result = super.pop();
|
||||
int itemCount = size();
|
||||
if (itemCount < fixItemCount) {
|
||||
fixItemCount = itemCount;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized GraphTargetItem remove(int index) {
|
||||
if (index < fixItemCount) {
|
||||
fixItemCount = index;
|
||||
}
|
||||
return super.remove(index);
|
||||
}
|
||||
|
||||
public boolean allItemsFixed() {
|
||||
return size() <= fixItemCount;
|
||||
}
|
||||
|
||||
public int getFixItemCount() {
|
||||
return fixItemCount;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.NotCompileTimeItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
@@ -116,7 +117,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S
|
||||
}
|
||||
|
||||
//if(val.startsWith("catchscope ")) return;
|
||||
//if(val.startsWith("newactivation()")) return;
|
||||
//if(val.startsWith("newactivation()")) return;
|
||||
output.add(new SetLocalAVM2Item(ins, regId, value));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Deobfuscator;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
@@ -279,13 +280,9 @@ public final class MethodBody implements Cloneable {
|
||||
deobfuscated.markMappedOffsets();
|
||||
//deobfuscated.inlineJumpExit();
|
||||
if (Configuration.autoDeobfuscate.get()) {
|
||||
try {
|
||||
deobfuscated.removeTraps(constants, trait, method_info.get(this.method_info), b, abc, scriptIndex, classIndex, isStatic, path);
|
||||
} catch (StackOverflowError ex) {
|
||||
logger.log(Level.SEVERE, "Error during remove traps in " + path, ex);
|
||||
}
|
||||
AVM2Deobfuscator deo = new AVM2Deobfuscator();
|
||||
deo.deobfuscate(classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
|
||||
}
|
||||
//deobfuscated.restoreControlFlow(constants, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -22,5 +22,9 @@ import java.util.Stack;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ScopeStack extends Stack<GraphTargetItem> {
|
||||
public class ScopeStack extends TranslateStack {
|
||||
|
||||
public ScopeStack() {
|
||||
super("scope");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,17 @@ public class TranslateStack extends Stack<GraphTargetItem> {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized GraphTargetItem get(int index) {
|
||||
if (path != null) {
|
||||
if (index >= this.size() || index < 0) {
|
||||
Logger.getLogger(TranslateStack.class.getName()).log(Level.FINE, "{0}: Attemp to Get item outside of bounds of stack", path);
|
||||
return pop;
|
||||
}
|
||||
}
|
||||
return super.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized GraphTargetItem peek() {
|
||||
if (path != null) {
|
||||
|
||||
Reference in New Issue
Block a user