mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-09 10:53:51 +00:00
Fixed: #2486 AS3 switches detection in some cases
This commit is contained in:
@@ -38,6 +38,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Highlighter nullpointer
|
||||
- AS3 search slot name Index out of bounds
|
||||
- AS text search - not being able to cancel search over multiple swf files
|
||||
- [#2486] AS3 switches detection in some cases
|
||||
|
||||
### Changed
|
||||
- Icon of "Deobfuscation options" menu from pile of pills to medkit
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2025 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.deobfuscation;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This will fix some if(false) in Flex code in switch default statement.
|
||||
* It is not a real deobufscation, just fix for specific case.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2DeobfuscatorPushFalseIfFalse extends SWFDecompilerAdapter {
|
||||
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
Map<Integer, List<Integer>> refs = body.getCode().visitCode(body);
|
||||
AVM2Code code = body.getCode();
|
||||
for (int ip = 1; ip < code.code.size(); ip++) {
|
||||
AVM2Instruction ins = code.code.get(ip);
|
||||
AVM2Instruction insPrev = code.code.get(ip - 1);
|
||||
if (!(ins.definition instanceof IfFalseIns)) {
|
||||
continue;
|
||||
}
|
||||
if (!(insPrev.definition instanceof PushFalseIns)) {
|
||||
continue;
|
||||
}
|
||||
if (refs.containsKey(ip) && refs.get(ip).size() > 1) {
|
||||
continue;
|
||||
}
|
||||
insPrev.definition = new NopIns();
|
||||
ins.definition = new JumpIns();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,9 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewCatchIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictEqIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictNeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIIns;
|
||||
@@ -44,6 +46,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.other.decimalsupport.Dec
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.decimalsupport.IncLocalPIns;
|
||||
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.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns;
|
||||
@@ -84,6 +87,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.clauses.TryAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.EqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.NeqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictEqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictNeqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
@@ -110,13 +114,17 @@ import com.jpexs.decompiler.graph.model.BinaryOpItem;
|
||||
import com.jpexs.decompiler.graph.model.BreakItem;
|
||||
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
|
||||
import com.jpexs.decompiler.graph.model.ContinueItem;
|
||||
import com.jpexs.decompiler.graph.model.DefaultItem;
|
||||
import com.jpexs.decompiler.graph.model.ExitItem;
|
||||
import com.jpexs.decompiler.graph.model.FalseItem;
|
||||
import com.jpexs.decompiler.graph.model.GotoItem;
|
||||
import com.jpexs.decompiler.graph.model.IfItem;
|
||||
import com.jpexs.decompiler.graph.model.IntegerValueItem;
|
||||
import com.jpexs.decompiler.graph.model.IntegerValueTypeItem;
|
||||
import com.jpexs.decompiler.graph.model.LoopItem;
|
||||
import com.jpexs.decompiler.graph.model.NotItem;
|
||||
import com.jpexs.decompiler.graph.model.OrItem;
|
||||
import com.jpexs.decompiler.graph.model.PopItem;
|
||||
import com.jpexs.decompiler.graph.model.PushItem;
|
||||
import com.jpexs.decompiler.graph.model.SwitchItem;
|
||||
import com.jpexs.decompiler.graph.model.TernarOpItem;
|
||||
@@ -129,6 +137,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -1735,11 +1744,8 @@ public class AVM2Graph extends Graph {
|
||||
Loop currentLoop, int staticOperation, String path) throws InterruptedException {
|
||||
List<GraphTargetItem> ret = null;
|
||||
|
||||
/*if (ret != null) {
|
||||
return ret;
|
||||
}*/
|
||||
//Detect switch
|
||||
if ((part.nextParts.size() == 2) && (!stack.isEmpty()) && (stack.peek() instanceof StrictEqAVM2Item)) {
|
||||
if ((part.nextParts.size() == 2) && (!stack.isEmpty()) && ((stack.peek() instanceof StrictEqAVM2Item) || (stack.peek() instanceof StrictNeqAVM2Item))) {
|
||||
GraphSourceItem switchStartItem = code.get(part.start);
|
||||
|
||||
GraphTargetItem switchedObject = null;
|
||||
@@ -1750,29 +1756,82 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
List<GraphTargetItem> caseValuesMapLeft = new ArrayList<>();
|
||||
List<GraphTargetItem> caseValuesMapRight = new ArrayList<>();
|
||||
List<List<GraphTargetItem>> outs = new ArrayList<>();
|
||||
|
||||
StrictEqAVM2Item set = (StrictEqAVM2Item) stack.pop();
|
||||
StrictEqAVM2Item firstSet = set;
|
||||
outs.add(new ArrayList<>());
|
||||
|
||||
BinaryOpItem set = (BinaryOpItem) stack.pop();
|
||||
BinaryOpItem firstSet = set;
|
||||
caseValuesMapLeft.add(set.leftSide);
|
||||
caseValuesMapRight.add(set.rightSide);
|
||||
|
||||
int branchNum;
|
||||
|
||||
GraphPart origPart = part;
|
||||
List<GraphPart> caseBodyParts = new ArrayList<>();
|
||||
caseBodyParts.add(part.nextParts.get(0));
|
||||
|
||||
if (((AVM2Instruction) code.get(part.end)).definition instanceof IfStrictNeIns) {
|
||||
branchNum = 0;
|
||||
caseBodyParts.add(part.nextParts.get(1));
|
||||
} else {
|
||||
branchNum = 1;
|
||||
caseBodyParts.add(part.nextParts.get(0));
|
||||
}
|
||||
GraphTargetItem top = null;
|
||||
int cnt = 1;
|
||||
int branchCount = 2;
|
||||
try {
|
||||
while (part.nextParts.size() > 1
|
||||
&& part.nextParts.get(1).getHeight() > 1
|
||||
&& ((AVM2Instruction) code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end)).definition instanceof IfStrictEqIns
|
||||
&& ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqAVM2Item)) {
|
||||
cnt++;
|
||||
part = part.nextParts.get(1);
|
||||
caseBodyParts.add(part.nextParts.get(0));
|
||||
while (true) {
|
||||
List<GraphTargetItem> out = new ArrayList<>();
|
||||
//Special: In Flex (not air) there are these blocks sometimes:
|
||||
// if(false) {
|
||||
// §§push(5);
|
||||
// break;
|
||||
//}
|
||||
//AVM2DeobfuscatorPushFalseIfFalse changes it to
|
||||
// nop
|
||||
// jump
|
||||
// (to first case to work)
|
||||
if (part.nextParts.size() == branchCount
|
||||
&& part.nextParts.get(branchNum).getHeight() == 2
|
||||
&& ((AVM2Instruction) code.get(part.nextParts.get(branchNum).start >= code.size() ? code.size() - 1 : part.nextParts.get(branchNum).start)).definition instanceof NopIns
|
||||
&& ((AVM2Instruction) code.get(part.nextParts.get(branchNum).end >= code.size() ? code.size() - 1 : part.nextParts.get(branchNum).end)).definition instanceof JumpIns) {
|
||||
part = part.nextParts.get(branchNum);
|
||||
branchNum = 0;
|
||||
branchCount = 1;
|
||||
} else if (part.nextParts.size() == branchCount
|
||||
&& part.nextParts.get(branchNum).getHeight() > 1
|
||||
&& ((AVM2Instruction) code.get(part.nextParts.get(branchNum).end >= code.size() ? code.size() - 1 : part.nextParts.get(branchNum).end)).definition instanceof IfStrictEqIns
|
||||
&& ((top = translatePartGetStack(localData, part.nextParts.get(branchNum), stack, staticOperation, out)) instanceof StrictEqAVM2Item)) {
|
||||
cnt++;
|
||||
part = part.nextParts.get(branchNum);
|
||||
caseBodyParts.add(part.nextParts.get(0));
|
||||
branchNum = 1;
|
||||
|
||||
set = (StrictEqAVM2Item) top;
|
||||
caseValuesMapLeft.add(set.leftSide);
|
||||
caseValuesMapRight.add(set.rightSide);
|
||||
outs.add(out);
|
||||
out = new ArrayList<>();
|
||||
set = (StrictEqAVM2Item) top;
|
||||
caseValuesMapLeft.add(set.leftSide);
|
||||
caseValuesMapRight.add(set.rightSide);
|
||||
branchCount = 2;
|
||||
} else if (part.nextParts.size() == branchCount
|
||||
&& part.nextParts.get(branchNum).getHeight() > 1
|
||||
&& ((AVM2Instruction) code.get(part.nextParts.get(branchNum).end >= code.size() ? code.size() - 1 : part.nextParts.get(branchNum).end)).definition instanceof IfStrictNeIns
|
||||
&& ((top = translatePartGetStack(localData, part.nextParts.get(branchNum), stack, staticOperation, out)) instanceof StrictNeqAVM2Item)) {
|
||||
cnt++;
|
||||
part = part.nextParts.get(branchNum);
|
||||
caseBodyParts.add(part.nextParts.get(1));
|
||||
branchNum = 0;
|
||||
|
||||
outs.add(out);
|
||||
out = new ArrayList<>();
|
||||
set = (StrictNeqAVM2Item) top;
|
||||
caseValuesMapLeft.add(set.leftSide);
|
||||
caseValuesMapRight.add(set.rightSide);
|
||||
branchCount = 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (GraphPartChangeException gpc) {
|
||||
//ignore
|
||||
@@ -1818,10 +1877,17 @@ public class AVM2Graph extends Graph {
|
||||
otherSide = caseValuesMapRight;
|
||||
}
|
||||
|
||||
for (int i = 0; i < caseValuesMap.size(); i++) {
|
||||
if (!outs.get(i).isEmpty()) {
|
||||
outs.get(i).add(caseValuesMap.get(i));
|
||||
caseValuesMap.set(i, new CommaExpressionItem(dialect, null, null, outs.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
if ((leftReg < 0 && rightReg < 0) || (cnt == 1)) {
|
||||
stack.push(firstSet);
|
||||
} else {
|
||||
part = part.nextParts.get(1);
|
||||
part = part.nextParts.get(branchNum);
|
||||
GraphPart defaultPart = part;
|
||||
if (code.size() > defaultPart.start && ((AVM2Instruction) code.get(defaultPart.start)).definition instanceof JumpIns
|
||||
&& defaultPart.refs.size() == 1
|
||||
@@ -2443,9 +2509,11 @@ public class AVM2Graph extends Graph {
|
||||
if (item instanceof IntegerValueAVM2Item) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
if ((item instanceof PushItem) && (item.value instanceof IntegerValueAVM2Item)) {
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2454,6 +2522,159 @@ public class AVM2Graph extends Graph {
|
||||
if (debugDoNotProcess) {
|
||||
return;
|
||||
}
|
||||
|
||||
loopi:
|
||||
for (int i = 1 /*not first*/; i < list.size(); i++) {
|
||||
GraphTargetItem item = list.get(i);
|
||||
|
||||
GraphTargetItem prevItem = list.get(i - 1);
|
||||
if ((item instanceof SwitchItem) && (prevItem instanceof SwitchItem)) {
|
||||
SwitchItem thisSwitch = (SwitchItem) item;
|
||||
SwitchItem prevSwitch = (SwitchItem) prevItem;
|
||||
if (thisSwitch.switchedObject instanceof PopItem) {
|
||||
List<Integer> caseValues = new ArrayList<>();
|
||||
Map<Integer, GraphTargetItem> expressionsMap = new LinkedHashMap<>();
|
||||
List<GraphTargetItem> defaultCommands = null;
|
||||
for (int k = 0; k < thisSwitch.caseValues.size(); k++) {
|
||||
if (thisSwitch.caseValues.get(k) instanceof DefaultItem) {
|
||||
continue;
|
||||
}
|
||||
if (!(thisSwitch.caseValues.get(k) instanceof IntegerValueTypeItem)) {
|
||||
continue loopi;
|
||||
}
|
||||
}
|
||||
|
||||
int defaultInt = -1;
|
||||
|
||||
for (int j = 0; j < prevSwitch.caseCommands.size(); j++) {
|
||||
|
||||
int valueIndex = prevSwitch.valuesMapping.indexOf(j);
|
||||
|
||||
if (valueIndex == -1) {
|
||||
continue loopi;
|
||||
}
|
||||
|
||||
GraphTargetItem currentExpression = prevSwitch.caseValues.get(valueIndex);
|
||||
|
||||
if (prevSwitch.caseCommands.get(j).size() > 2) {
|
||||
continue loopi;
|
||||
}
|
||||
int delta = 0;
|
||||
if (currentExpression instanceof DefaultItem && prevSwitch.caseCommands.size() >= 2) {
|
||||
//Special case - in flex (not air), the default clause has weird
|
||||
// if (false) {
|
||||
// §§push(5);
|
||||
// }
|
||||
// §§push(5);
|
||||
if (prevSwitch.caseCommands.get(j).get(0) instanceof IfItem) {
|
||||
IfItem ifi = (IfItem) prevSwitch.caseCommands.get(j).get(0);
|
||||
if (ifi.expression instanceof FalseItem) {
|
||||
delta++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j == prevSwitch.caseCommands.size() - 1 && prevSwitch.caseCommands.get(j).size() == delta + 1) {
|
||||
//empty
|
||||
} else if (prevSwitch.caseCommands.get(j).size() != 2 + delta) {
|
||||
continue loopi;
|
||||
} else {
|
||||
if (!(prevSwitch.caseCommands.get(j).get(delta + 1) instanceof BreakItem)) {
|
||||
continue loopi;
|
||||
}
|
||||
BreakItem br = (BreakItem) prevSwitch.caseCommands.get(j).get(delta + 1);
|
||||
if (br.loopId != prevSwitch.loop.id) {
|
||||
continue loopi;
|
||||
}
|
||||
}
|
||||
if (!(prevSwitch.caseCommands.get(j).get(delta) instanceof PushItem)) {
|
||||
continue loopi;
|
||||
}
|
||||
PushItem pi = (PushItem) prevSwitch.caseCommands.get(j).get(delta);
|
||||
if (!(pi.value instanceof IntegerValueTypeItem)) {
|
||||
continue loopi;
|
||||
}
|
||||
Integer pushedInt = ((IntegerValueTypeItem) pi.value).intValue();
|
||||
expressionsMap.put(pushedInt, currentExpression);
|
||||
if (currentExpression instanceof DefaultItem) {
|
||||
defaultInt = pushedInt;
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> thisExpressions = new ArrayList<>();
|
||||
int defaultIndex = -1;
|
||||
for (int k = 0; k < thisSwitch.caseValues.size(); k++) {
|
||||
if (thisSwitch.caseValues.get(k) instanceof DefaultItem) {
|
||||
defaultIndex = k;
|
||||
continue;
|
||||
}
|
||||
if (!(thisSwitch.caseValues.get(k) instanceof IntegerValueTypeItem)) {
|
||||
continue loopi;
|
||||
}
|
||||
int cv = ((IntegerValueTypeItem) thisSwitch.caseValues.get(k)).intValue();
|
||||
if (!expressionsMap.containsKey(cv)) {
|
||||
continue loopi;
|
||||
}
|
||||
thisExpressions.add(cv);
|
||||
}
|
||||
|
||||
List<Integer> noCaseExpressions = new ArrayList<>();
|
||||
|
||||
for (int key : expressionsMap.keySet()) {
|
||||
if (!thisExpressions.contains(key)) {
|
||||
if (defaultIndex == -1 && defaultInt != key) {
|
||||
continue loopi;
|
||||
}
|
||||
noCaseExpressions.add(key);
|
||||
}
|
||||
}
|
||||
noCaseExpressions.sort(new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1 - o2;
|
||||
}
|
||||
});
|
||||
|
||||
for (int k = 0; k < thisSwitch.caseValues.size(); k++) {
|
||||
if (thisSwitch.caseValues.get(k) instanceof DefaultItem) {
|
||||
int m = thisSwitch.valuesMapping.get(k);
|
||||
thisSwitch.caseValues.remove(k);
|
||||
thisSwitch.valuesMapping.remove(k);
|
||||
|
||||
for (int e : noCaseExpressions) {
|
||||
thisSwitch.caseValues.add(k, expressionsMap.get(e));
|
||||
thisSwitch.valuesMapping.add(k, m);
|
||||
k++;
|
||||
}
|
||||
k--;
|
||||
|
||||
boolean foundElsewhere = false;
|
||||
for (int h = 0; h < thisSwitch.valuesMapping.size(); h++) {
|
||||
if (thisSwitch.valuesMapping.get(h) == m) {
|
||||
foundElsewhere = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundElsewhere) {
|
||||
thisSwitch.caseCommands.remove(m);
|
||||
for (int h = 0; h < thisSwitch.valuesMapping.size(); h++) {
|
||||
if (thisSwitch.valuesMapping.get(h) > m) {
|
||||
thisSwitch.valuesMapping.set(h, thisSwitch.valuesMapping.get(h) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int cv = ((IntegerValueTypeItem) thisSwitch.caseValues.get(k)).intValue();
|
||||
thisSwitch.caseValues.set(k, expressionsMap.get(cv));
|
||||
}
|
||||
|
||||
thisSwitch.switchedObject = prevSwitch.switchedObject;
|
||||
list.remove(i - 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level == 0) {
|
||||
if (!list.isEmpty()) {
|
||||
if (list.get(list.size() - 1) instanceof ReturnVoidAVM2Item) {
|
||||
@@ -2890,7 +3111,7 @@ public class AVM2Graph extends Graph {
|
||||
});
|
||||
i = newI.getVal();
|
||||
}
|
||||
*/
|
||||
*/
|
||||
//Handle for loops at the end:
|
||||
super.finalProcess(parent, list, level, localData, path);
|
||||
}
|
||||
@@ -2931,7 +3152,7 @@ public class AVM2Graph extends Graph {
|
||||
AVM2LocalData avm2LocalData = (AVM2LocalData) localData;
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(output.size() - 1);
|
||||
int setLocalIp = InstructionDefinition.getItemIp(avm2LocalData, setLocal);
|
||||
;
|
||||
|
||||
Set<Integer> allUsages = new HashSet<>(avm2LocalData.getSetLocalUsages(setLocalIp));
|
||||
boolean isOtherSideReg = false;
|
||||
for (GraphTargetItem otherSide : otherSides) {
|
||||
@@ -3263,5 +3484,5 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
|
||||
return ternar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCodeException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorPushFalseIfFalse;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
|
||||
@@ -642,6 +643,11 @@ public final class MethodBody implements Cloneable {
|
||||
code.fixJumps(path, body);
|
||||
return body;
|
||||
}
|
||||
} else {
|
||||
//This needs to be done otherwise some switch testcases fail. (Flex)
|
||||
try (Statistics s = new Statistics("AVM2DeobfuscatorPushFalseIfFalse")) {
|
||||
new AVM2DeobfuscatorPushFalseIfFalse().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, method_info, body);
|
||||
}
|
||||
}
|
||||
|
||||
lastConvertedBody = body;
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.graph.model.BinaryOpItem;
|
||||
import com.jpexs.decompiler.graph.model.BranchStackResistant;
|
||||
import com.jpexs.decompiler.graph.model.BreakItem;
|
||||
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
|
||||
import com.jpexs.decompiler.graph.model.CommentItem;
|
||||
import com.jpexs.decompiler.graph.model.ContinueItem;
|
||||
import com.jpexs.decompiler.graph.model.DefaultItem;
|
||||
import com.jpexs.decompiler.graph.model.DoWhileItem;
|
||||
@@ -1383,7 +1384,7 @@ public class Graph {
|
||||
* @param list List of GraphTargetItems
|
||||
* @param lastLoopId Last loop id
|
||||
*/
|
||||
protected final void processSwitches(List<GraphTargetItem> list, long lastLoopId) {
|
||||
protected void processSwitches(List<GraphTargetItem> list, long lastLoopId) {
|
||||
loopi:
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
GraphTargetItem item = list.get(i);
|
||||
@@ -2311,6 +2312,25 @@ public class Graph {
|
||||
translatePart(localData, part, stack, staticOperation, null);
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates part and get its stack with output
|
||||
*
|
||||
* @param localData Local data
|
||||
* @param part Part
|
||||
* @param stack Translate stack
|
||||
* @param staticOperation Unused
|
||||
* @return Top of the stack
|
||||
* @throws InterruptedException On interrupt
|
||||
* @throws GraphPartChangeException On graph part change
|
||||
*/
|
||||
//@SuppressWarnings("unchecked")
|
||||
protected final GraphTargetItem translatePartGetStack(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, List<GraphTargetItem> output) throws InterruptedException, GraphPartChangeException {
|
||||
stack = (TranslateStack) stack.clone();
|
||||
output.clear();
|
||||
output.addAll(translatePart(localData, part, stack, staticOperation, null));
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates part.
|
||||
@@ -3194,6 +3214,7 @@ public class Graph {
|
||||
if (debugPrintGraph) {
|
||||
System.err.println("Adding break");
|
||||
}
|
||||
makeAllCommands(ret, stack);
|
||||
ret.add(new BreakItem(dialect, null, localData.lineStartInstruction, el.id));
|
||||
return ret;
|
||||
}
|
||||
@@ -3204,6 +3225,7 @@ public class Graph {
|
||||
if (debugPrintGraph) {
|
||||
System.err.println("Adding precontinue");
|
||||
}
|
||||
makeAllCommands(ret, stack);
|
||||
ret.add(new ContinueItem(dialect, null, localData.lineStartInstruction, el.id));
|
||||
return ret;
|
||||
}
|
||||
@@ -3214,6 +3236,7 @@ public class Graph {
|
||||
if (debugPrintGraph) {
|
||||
System.err.println("Adding continue");
|
||||
}
|
||||
makeAllCommands(ret, stack);
|
||||
ret.add(new ContinueItem(dialect, null, localData.lineStartInstruction, el.id));
|
||||
return ret;
|
||||
}
|
||||
@@ -3267,8 +3290,10 @@ public class Graph {
|
||||
}
|
||||
}
|
||||
|
||||
if (code.size() <= part.start) {
|
||||
ret.add(new ScriptEndItem(dialect));
|
||||
if (code.size() <= part.start) {
|
||||
if (!(!ret.isEmpty() && ret.get(ret.size() - 1) instanceof ExitItem)) {
|
||||
ret.add(new ScriptEndItem(dialect));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3428,7 +3453,9 @@ public class Graph {
|
||||
}
|
||||
} while (exHappened);
|
||||
if ((part.end >= code.size() - 1) && getNextParts(localData, part).isEmpty()) {
|
||||
output.add(new ScriptEndItem(dialect));
|
||||
if (!(!output.isEmpty() && output.get(output.size() - 1) instanceof ExitItem)) {
|
||||
output.add(new ScriptEndItem(dialect));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4651,7 +4678,8 @@ public class Graph {
|
||||
stopPart2x.add(breakPart);
|
||||
stopPartKind2x.add(StopPartKind.OTHER);
|
||||
}
|
||||
currentCaseCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, stopPartKind2x, loops, throwStates, staticOperation, path);
|
||||
TranslateStack subStack = (TranslateStack) stack.clone();
|
||||
currentCaseCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, subStack, allParts, null, caseBodies.get(i), stopPart2x, stopPartKind2x, loops, throwStates, staticOperation, path);
|
||||
if (willHaveBreak) {
|
||||
if (!currentCaseCommands.isEmpty()) {
|
||||
GraphTargetItem last = currentCaseCommands.get(currentCaseCommands.size() - 1);
|
||||
@@ -4660,8 +4688,7 @@ public class Graph {
|
||||
}
|
||||
}
|
||||
}
|
||||
caseCommands.add(currentCaseCommands);
|
||||
makeAllCommands(currentCaseCommands, stack);
|
||||
caseCommands.add(currentCaseCommands);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorGroupParts;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorJumps;
|
||||
@@ -169,10 +168,10 @@ public class ActionScript3DeobfuscatorTest extends ActionScriptTestBase {
|
||||
code.removeTraps(null, 0, b, abc, 0, -1, true, pCode);
|
||||
code.removeLabelsAndDebugLine(b);
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false);
|
||||
String actual = b.toSource(10, new ArrayList<>(), swf.getAbcIndex(), 0, new HashSet<>());
|
||||
String actual = b.toSource(10, new ArrayList<>(), swf.getAbcIndex(), 0, new HashSet<>());
|
||||
actual = actual.replace("\r\n", "\n");
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
private String recompilePCode(String str, SWFDecompilerAdapter deobfuscator) throws IOException, AVM2ParseException, InterruptedException {
|
||||
str = "code\r\n"
|
||||
@@ -543,37 +542,383 @@ public class ActionScript3DeobfuscatorTest extends ActionScriptTestBase {
|
||||
@Test
|
||||
public void testWhileTrue() throws Exception {
|
||||
decompilePCode(
|
||||
" getlex QName(PackageNamespace(\"\"),\"Math\")\n" +
|
||||
" getlex QName(PackageNamespace(\"\"),\"Math\")\n" +
|
||||
" debugline 8\n" +
|
||||
" callproperty QName(PackageNamespace(\"\"),\"random\"), 0\n" +
|
||||
" pushbyte 6\n" +
|
||||
" multiply\n" +
|
||||
" callproperty QName(PackageNamespace(\"\"),\"floor\"), 1\n" +
|
||||
" convert_i\n" +
|
||||
" setlocal1\n" +
|
||||
" getlocal1\n" +
|
||||
" debugline 10\n" +
|
||||
" pushbyte 4\n" +
|
||||
" ifngt ofs0034\n" +
|
||||
" jump ofs0030\n" +
|
||||
" ofs002d:\n" +
|
||||
" label\n" +
|
||||
" debugline 11\n" +
|
||||
" ofs0030:\n" +
|
||||
" jump ofs002d\n" +
|
||||
" ofs0034:\n" +
|
||||
" ", " param1 = Math.floor(Math.random() * 6);\n" +
|
||||
" if(param1 <= 4)\n" +
|
||||
" {\n" +
|
||||
" return;\n" +
|
||||
" }\n" +
|
||||
" while(true)\n" +
|
||||
" {\n" +
|
||||
" }\n");
|
||||
|
||||
" getlex QName(PackageNamespace(\"\"),\"Math\")\n"
|
||||
+ " getlex QName(PackageNamespace(\"\"),\"Math\")\n"
|
||||
+ " debugline 8\n"
|
||||
+ " callproperty QName(PackageNamespace(\"\"),\"random\"), 0\n"
|
||||
+ " pushbyte 6\n"
|
||||
+ " multiply\n"
|
||||
+ " callproperty QName(PackageNamespace(\"\"),\"floor\"), 1\n"
|
||||
+ " convert_i\n"
|
||||
+ " setlocal1\n"
|
||||
+ " getlocal1\n"
|
||||
+ " debugline 10\n"
|
||||
+ " pushbyte 4\n"
|
||||
+ " ifngt ofs0034\n"
|
||||
+ " jump ofs0030\n"
|
||||
+ " ofs002d:\n"
|
||||
+ " label\n"
|
||||
+ " debugline 11\n"
|
||||
+ " ofs0030:\n"
|
||||
+ " jump ofs002d\n"
|
||||
+ " ofs0034:\n"
|
||||
+ " ", " param1 = Math.floor(Math.random() * 6);\n"
|
||||
+ " if(param1 <= 4)\n"
|
||||
+ " {\n"
|
||||
+ " return;\n"
|
||||
+ " }\n"
|
||||
+ " while(true)\n"
|
||||
+ " {\n"
|
||||
+ " }\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testObfuscatedSwitch() throws Exception {
|
||||
decompilePCode("getlocal0\n"
|
||||
+ " pushbyte 0\n"
|
||||
+ " initproperty QName(PackageNamespace(\"\"),\"testA\")\n"
|
||||
+ " jump ofs0012\n"
|
||||
+ " call 7\n"
|
||||
+ " throw\n"
|
||||
+ " callmethod 1413, 7\n"
|
||||
+ " ofs0012:\n"
|
||||
+ " jump ofs001a\n"
|
||||
+ " ifge ofs001a\n"
|
||||
+ " ofs001a:\n"
|
||||
+ " jump ofs0024\n"
|
||||
+ " equals\n"
|
||||
+ " pushwith\n"
|
||||
+ " newfunction 30\n"
|
||||
+ " pop\n"
|
||||
+ " setlocal2\n"
|
||||
+ " ofs0024:\n"
|
||||
+ " jump ofs0132\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal3\n"
|
||||
+ " ofs002a:\n"
|
||||
+ " label\n"
|
||||
+ " pushtrue\n"
|
||||
+ " iftrue ofs0036\n"
|
||||
+ " returnvoid\n"
|
||||
+ " popscope\n"
|
||||
+ " callsuper QName(PackageNamespace(\"aaa\"),\"xxx\"), 10\n"
|
||||
+ " pushwith\n"
|
||||
+ " ofs0036:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal0\n"
|
||||
+ " ofs0040:\n"
|
||||
+ " label\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " getlocal0\n"
|
||||
+ " pushtrue\n"
|
||||
+ " iftrue ofs0052\n"
|
||||
+ " returnvoid\n"
|
||||
+ " popscope\n"
|
||||
+ " pushwith\n"
|
||||
+ " newfunction 48\n"
|
||||
+ " pop\n"
|
||||
+ " divide\n"
|
||||
+ " ofs0052:\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " ifgt ofs0061\n"
|
||||
+ " ofs0061:\n"
|
||||
+ " label\n"
|
||||
+ " jump ofs006a\n"
|
||||
+ " ifstricteq ofs006a\n"
|
||||
+ " ofs006a:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs0078\n"
|
||||
+ " popscope\n"
|
||||
+ " pushwith\n"
|
||||
+ " newfunction 4\n"
|
||||
+ " throw\n"
|
||||
+ " checkfilter\n"
|
||||
+ " ofs0078:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal0\n"
|
||||
+ " getlocal3\n"
|
||||
+ " ofs0083:\n"
|
||||
+ " label\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " pushfalse\n"
|
||||
+ " iffalse ofs0094\n"
|
||||
+ " returnvoid\n"
|
||||
+ " popscope\n"
|
||||
+ " equals\n"
|
||||
+ " setlocal1\n"
|
||||
+ " newactivation\n"
|
||||
+ " increment\n"
|
||||
+ " decrement\n"
|
||||
+ " ofs0094:\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal2\n"
|
||||
+ " ofs009a:\n"
|
||||
+ " label\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " getlocal0\n"
|
||||
+ " jump ofs00a9\n"
|
||||
+ " modulo\n"
|
||||
+ " callsupervoid QName(PackageInternalNs(\"xxxx\"),\"tmp\"), 5\n"
|
||||
+ " pushwith\n"
|
||||
+ " ofs00a9:\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs00b4\n"
|
||||
+ " ifge ofs00b4\n"
|
||||
+ " ofs00b4:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs00c1\n"
|
||||
+ " popscope\n"
|
||||
+ " callproplex QName(PackageNamespace(\"\"),\"xxx\"), 18\n"
|
||||
+ " setlocal2\n"
|
||||
+ " ofs00c1:\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " ifstrictne ofs00c9\n"
|
||||
+ " ofs00c9:\n"
|
||||
+ " label\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs00d8\n"
|
||||
+ " nextname\n"
|
||||
+ " dxns \"position\"\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal2\n"
|
||||
+ " returnvalue\n"
|
||||
+ " ofs00d8:\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal3\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ofs00df:\n"
|
||||
+ " label\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " getlocal0\n"
|
||||
+ " jump ofs00ef\n"
|
||||
+ " popscope\n"
|
||||
+ " pushwith\n"
|
||||
+ " newfunction 24\n"
|
||||
+ " pop\n"
|
||||
+ " setlocal3\n"
|
||||
+ " ofs00ef:\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs00fa\n"
|
||||
+ " ifne ofs00fa\n"
|
||||
+ " ofs00fa:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " jump ofs0107\n"
|
||||
+ " popscope\n"
|
||||
+ " callproplex TypeName(QName(PackageNamespace(\"__AS3__.vec\"),\"Vector\")<QName(PackageNamespace(\"xxx\"),\"aaa\")>), 15\n"
|
||||
+ " throw\n"
|
||||
+ " ofs0107:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " pushtrue\n"
|
||||
+ " iftrue ofs0117\n"
|
||||
+ " returnvoid\n"
|
||||
+ " checkfilter\n"
|
||||
+ " pushwith\n"
|
||||
+ " newfunction 51\n"
|
||||
+ " throw\n"
|
||||
+ " instanceof\n"
|
||||
+ " ofs0117:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " callpropvoid QName(PackageNamespace(\"\"),\"test\"), 0\n"
|
||||
+ " pushfalse\n"
|
||||
+ " iffalse ofs0127\n"
|
||||
+ " returnvoid\n"
|
||||
+ " popscope\n"
|
||||
+ " setlocal1\n"
|
||||
+ " istypelate\n"
|
||||
+ " setlocal1\n"
|
||||
+ " setlocal2\n"
|
||||
+ " divide\n"
|
||||
+ " ofs0127:\n"
|
||||
+ " jump ofs01ff\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal2\n"
|
||||
+ " getlocal1\n"
|
||||
+ " jump ofs0132\n"
|
||||
+ " ofs0132:\n"
|
||||
+ " getlex QName(PackageNamespace(\"\"),\"Abc\")\n"
|
||||
+ " getproperty QName(PackageNamespace(\"\"),\"value\")\n"
|
||||
+ " setlocal1\n"
|
||||
+ " jump ofs013f\n"
|
||||
+ " ifle ofs013f\n"
|
||||
+ " ofs013f:\n"
|
||||
+ " pushbyte 1\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ifstricteq ofs014a\n"
|
||||
+ " jump ofs015e\n"
|
||||
+ " ofs014a:\n"
|
||||
+ " pushbyte 0\n"
|
||||
+ " jump ofs0156\n"
|
||||
+ " pushscope\n"
|
||||
+ " setlocal0\n"
|
||||
+ " istypelate\n"
|
||||
+ " nextvalue\n"
|
||||
+ " istypelate\n"
|
||||
+ " decrement\n"
|
||||
+ " ofs0156:\n"
|
||||
+ " jump ofs01e3\n"
|
||||
+ " ifgt ofs015e\n"
|
||||
+ " ofs015e:\n"
|
||||
+ " pushbyte 2\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ifstricteq ofs0169\n"
|
||||
+ " jump ofs0178\n"
|
||||
+ " ofs0169:\n"
|
||||
+ " pushbyte 1\n"
|
||||
+ " jump ofs01e3\n"
|
||||
+ " jump ofs0173\n"
|
||||
+ " ofs0173:\n"
|
||||
+ " dup\n"
|
||||
+ " callsuper QName(PackageNamespace(\"xxx\"),\"aaa\"), 27\n"
|
||||
+ " pop\n"
|
||||
+ " ofs0178:\n"
|
||||
+ " pushbyte 3\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ifstricteq ofs0183\n"
|
||||
+ " jump ofs018b\n"
|
||||
+ " ofs0183:\n"
|
||||
+ " pushbyte 2\n"
|
||||
+ " jump ofs01e3\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal0\n"
|
||||
+ " ofs018b:\n"
|
||||
+ " pushbyte 4\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ifstrictne ofs01a2\n"
|
||||
+ " pushbyte 3\n"
|
||||
+ " jump ofs01e3\n"
|
||||
+ " jump ofs019c\n"
|
||||
+ " ofs019c:\n"
|
||||
+ " convert_s\n"
|
||||
+ " construct 110\n"
|
||||
+ " pushwith\n"
|
||||
+ " nextvalue\n"
|
||||
+ " setlocal2\n"
|
||||
+ " ofs01a2:\n"
|
||||
+ " pushbyte 5\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ifstricteq ofs01ad\n"
|
||||
+ " jump ofs01b5\n"
|
||||
+ " ofs01ad:\n"
|
||||
+ " pushbyte 4\n"
|
||||
+ " jump ofs01e3\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal2\n"
|
||||
+ " ofs01b5:\n"
|
||||
+ " pushbyte 6\n"
|
||||
+ " jump ofs01bf\n"
|
||||
+ " ifgt ofs01bf\n"
|
||||
+ " ofs01bf:\n"
|
||||
+ " getlocal1\n"
|
||||
+ " ifstrictne ofs01d4\n"
|
||||
+ " pushbyte 5\n"
|
||||
+ " jump ofs01e3\n"
|
||||
+ " jump ofs01ce\n"
|
||||
+ " ofs01ce:\n"
|
||||
+ " popscope\n"
|
||||
+ " pushwith\n"
|
||||
+ " newfunction 49\n"
|
||||
+ " pop\n"
|
||||
+ " checkfilter\n"
|
||||
+ " ofs01d4:\n"
|
||||
+ " jump ofs01e1\n"
|
||||
+ " throw\n"
|
||||
+ " setlocal3\n"
|
||||
+ " getlocal2\n"
|
||||
+ " pushbyte 6\n"
|
||||
+ " jump ofs01e1\n"
|
||||
+ " ofs01e1:\n"
|
||||
+ " pushbyte 6\n"
|
||||
+ " ofs01e3:\n"
|
||||
+ " kill 1\n"
|
||||
+ " lookupswitch ofs00df, [ofs002a, ofs0040, ofs0061, ofs0083, ofs009a, ofs00c9, ofs00df]\n"
|
||||
+ " ofs01ff:\n"
|
||||
+ " getlocal0\n"
|
||||
+ " pushbyte 0\n"
|
||||
+ " initproperty QName(PackageNamespace(\"\"),\"testX\")\n"
|
||||
+ " jump ofs020e\n"
|
||||
+ " popscope\n"
|
||||
+ " pushwith\n"
|
||||
+ " setlocal1\n"
|
||||
+ " bitxor\n"
|
||||
+ " convert_d\n"
|
||||
+ " setlocal2\n"
|
||||
+ " ofs020e:\n"
|
||||
+ " pushfalse\n"
|
||||
+ " iffalse ofs021a\n"
|
||||
+ " returnvoid\n"
|
||||
+ " typeof\n"
|
||||
+ " checkfilter\n"
|
||||
+ " bitand\n"
|
||||
+ " in\n"
|
||||
+ " convert_s\n"
|
||||
+ " nextvalue\n"
|
||||
+ " ofs021a:\n"
|
||||
+ " jump ofs0222\n"
|
||||
+ " ifgt ofs0222\n"
|
||||
+ " ofs0222:\n"
|
||||
+ " pushtrue\n"
|
||||
+ " iftrue ofs022d\n"
|
||||
+ " returnvoid\n"
|
||||
+ " setlocal2\n"
|
||||
+ " callsuper QName(PackageNamespace(\"xxx\"),\"aaa\"), 15\n"
|
||||
+ " throw\n"
|
||||
+ " ofs022d:", " this.testA = 0;\n"
|
||||
+ " switch(Abc.value)\n"
|
||||
+ " {\n"
|
||||
+ " case 1:\n"
|
||||
+ " this.test();\n"
|
||||
+ " break;\n"
|
||||
+ " case 2:\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " break;\n"
|
||||
+ " case 3:\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " break;\n"
|
||||
+ " case 4:\n"
|
||||
+ " this.test();\n"
|
||||
+ " break;\n"
|
||||
+ " case 5:\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " break;\n"
|
||||
+ " case 6:\n"
|
||||
+ " this.test();\n"
|
||||
+ " break;\n"
|
||||
+ " default:\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " this.test();\n"
|
||||
+ " }\n"
|
||||
+ " this.testX = 0;\n");
|
||||
}
|
||||
|
||||
// TODO: JPEXS @Test
|
||||
public void testNotRemoveParams() throws Exception {
|
||||
String res = recompile("function tst(p1,p2){"
|
||||
|
||||
@@ -1937,6 +1937,35 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchBig() {
|
||||
decompileMethod("classic_air", "testSwitchBig", "var k:int = 10;\r\n"
|
||||
+ "switch(k)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "case \"A\":\r\n"
|
||||
+ "trace(\"A\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"B\":\r\n"
|
||||
+ "case \"C\":\r\n"
|
||||
+ "trace(\"BC\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"D\":\r\n"
|
||||
+ "default:\r\n"
|
||||
+ "case \"E\":\r\n"
|
||||
+ "trace(\"D-default-E\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"F\":\r\n"
|
||||
+ "trace(\"F no break\");\r\n"
|
||||
+ "case \"G\":\r\n"
|
||||
+ "trace(\"G\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"H\":\r\n"
|
||||
+ "trace(\"H last\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after switch\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchComma() {
|
||||
decompileMethod("classic_air", "testSwitchComma", "var b:int = 5;\r\n"
|
||||
@@ -1948,7 +1977,7 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
+ "break;\r\n"
|
||||
+ "case \"B\":\r\n"
|
||||
+ "trace(\"is B\");\r\n"
|
||||
+ "case \"C\":\r\n"
|
||||
+ "case 7, \"C\":\r\n"
|
||||
+ "trace(\"is C\");\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
|
||||
@@ -424,8 +424,8 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
decompileMethod("classic", "testDefaultNotLastGrouped", "var k:* = 10;\r\n"
|
||||
+ "switch(k)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "case \"six\":\r\n"
|
||||
+ "default:\r\n"
|
||||
+ "case \"six\":\r\n"
|
||||
+ "trace(\"def and 6\");\r\n"
|
||||
+ "case \"five\":\r\n"
|
||||
+ "trace(\"def and 6 and 5\");\r\n"
|
||||
@@ -1924,6 +1924,35 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchBig() {
|
||||
decompileMethod("classic", "testSwitchBig", "var k:* = 10;\r\n"
|
||||
+ "switch(k)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "case \"A\":\r\n"
|
||||
+ "trace(\"A\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"B\":\r\n"
|
||||
+ "case \"C\":\r\n"
|
||||
+ "trace(\"BC\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"D\":\r\n"
|
||||
+ "default:\r\n"
|
||||
+ "case \"E\":\r\n"
|
||||
+ "trace(\"D-default-E\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"F\":\r\n"
|
||||
+ "trace(\"F no break\");\r\n"
|
||||
+ "case \"G\":\r\n"
|
||||
+ "trace(\"G\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case \"H\":\r\n"
|
||||
+ "trace(\"H last\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after switch\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchComma() {
|
||||
decompileMethod("classic", "testSwitchComma", "var b:int = 5;\r\n"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -118,6 +118,7 @@ package
|
||||
TestStringConcat;
|
||||
TestStrings;
|
||||
TestSwitch;
|
||||
TestSwitchBig;
|
||||
TestSwitchContinue;
|
||||
TestSwitchComma;
|
||||
TestSwitchDefault;
|
||||
|
||||
34
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestSwitchBig.as
vendored
Normal file
34
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestSwitchBig.as
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package tests
|
||||
{
|
||||
|
||||
public class TestSwitchBig
|
||||
{
|
||||
public function run():*
|
||||
{
|
||||
var k:* = 10;
|
||||
switch (k)
|
||||
{
|
||||
case "A":
|
||||
trace("A");
|
||||
break;
|
||||
case "B":
|
||||
case "C":
|
||||
trace("BC");
|
||||
break;
|
||||
case "D":
|
||||
default:
|
||||
case "E":
|
||||
trace("D-default-E");
|
||||
break;
|
||||
case "F":
|
||||
trace("F no break");
|
||||
case "G":
|
||||
trace("G");
|
||||
break;
|
||||
case "H":
|
||||
trace("H last");
|
||||
}
|
||||
trace("after switch");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user