Merge origin/master

This commit is contained in:
Jindra Petřík
2015-11-21 19:13:06 +01:00
40 changed files with 1351 additions and 676 deletions

View File

@@ -17,11 +17,9 @@
package com.jpexs.decompiler.flash.abc;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.ConvertException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugFileIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns;
@@ -54,7 +52,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

View File

@@ -1176,7 +1176,7 @@ public class AVM2Code implements Cloneable {
}
writer.newLine();
List<Long> offsets = new ArrayList<>();
Set<Long> importantOffsets = getImportantOffsets(body);
if (body != null) {
writer.appendNoHilight("body").newLine();
@@ -1197,28 +1197,26 @@ public class AVM2Code implements Cloneable {
writer.newLine();
for (int e = 0; e < body.exceptions.length; e++) {
ABCException exception = body.exceptions[e];
writer.appendNoHilight("try");
writer.appendNoHilight(" from ");
writer.appendNoHilight("ofs");
writer.appendNoHilight(Helper.formatAddress(body.exceptions[e].start));
offsets.add((long) body.exceptions[e].start);
writer.appendNoHilight(Helper.formatAddress(exception.start));
writer.appendNoHilight(" to ");
writer.appendNoHilight("ofs");
writer.appendNoHilight(Helper.formatAddress(body.exceptions[e].end));
offsets.add((long) body.exceptions[e].end);
writer.appendNoHilight(Helper.formatAddress(exception.end));
writer.appendNoHilight(" target ");
writer.appendNoHilight("ofs");
writer.appendNoHilight(Helper.formatAddress(body.exceptions[e].target));
offsets.add((long) body.exceptions[e].target);
writer.appendNoHilight(Helper.formatAddress(exception.target));
writer.appendNoHilight(" type ");
writer.hilightSpecial(body.exceptions[e].type_index == 0 ? "null" : constants.getMultiname(body.exceptions[e].type_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_TYPE, e);
writer.hilightSpecial(exception.type_index == 0 ? "null" : constants.getMultiname(exception.type_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_TYPE, e);
writer.appendNoHilight(" name ");
writer.hilightSpecial(body.exceptions[e].name_index == 0 ? "null" : constants.getMultiname(body.exceptions[e].name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e);
writer.hilightSpecial(exception.name_index == 0 ? "null" : constants.getMultiname(exception.name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e);
writer.newLine();
}
}
@@ -1226,21 +1224,6 @@ public class AVM2Code implements Cloneable {
writer.newLine();
writer.appendNoHilight("code").newLine();
for (AVM2Instruction ins : code) {
offsets.addAll(ins.getOffsets());
}
for (AVM2Instruction ins : code) {
if (ins.replaceWith != null) {
for (Object o : ins.replaceWith) {
if (o instanceof ControlFlowTag) {
ControlFlowTag cft = (ControlFlowTag) o;
if (cft.name.equals("appendjump")) {
offsets.add((long) pos2adr(cft.value));
}
}
}
}
}
int ip = 0;
int largeLimit = 20000;
boolean markOffsets = code.size() <= largeLimit;
@@ -1255,7 +1238,7 @@ public class AVM2Code implements Cloneable {
writer.appendNoHilight(Helper.bytesToHexString(ins.getBytes()));
writer.newLine();
}
if (Configuration.showAllAddresses.get() || offsets.contains(ofs)) {
if (Configuration.showAllAddresses.get() || importantOffsets.contains(ofs)) {
writer.appendNoHilight("ofs" + Helper.formatAddress(ofs) + ":");
}
/*for (int e = 0; e < body.exceptions.length; e++) {
@@ -1329,6 +1312,33 @@ public class AVM2Code implements Cloneable {
return writer;
}
public Set<Long> getImportantOffsets(MethodBody body) {
Set<Long> ret = new HashSet<>();
if (body != null) {
for (ABCException exception : body.exceptions) {
ret.add((long) exception.start);
ret.add((long) exception.end);
ret.add((long) exception.target);
}
}
for (AVM2Instruction ins : code) {
ret.addAll(ins.getOffsets());
if (ins.replaceWith != null) {
for (Object o : ins.replaceWith) {
if (o instanceof ControlFlowTag) {
ControlFlowTag cft = (ControlFlowTag) o;
if (cft.name.equals("appendjump")) {
ret.add((long) pos2adr(cft.value));
}
}
}
}
}
return ret;
}
public int adr2pos(long address) throws ConvertException {
return adr2pos(address, false);
}
@@ -1383,12 +1393,6 @@ public class AVM2Code implements Cloneable {
return (int) (ins.offset + ins.getBytesLength());
}
private List<Integer> unknownJumps;
private List<Integer> ignoredIns;
boolean isCatched = false;
/**
* Test for killed register. CalcKilledStats must be called before
*
@@ -1516,11 +1520,6 @@ public class AVM2Code implements Cloneable {
iploop:
while (ip <= end) {
if (ignoredIns.contains(ip)) {
ip++;
continue;
}
boolean processTry = processJumps;
//addr = pos2adr(ip);
//int ipfix = fixIPAfterDebugLine(ip);
@@ -1531,10 +1530,6 @@ public class AVM2Code implements Cloneable {
break;
}
if (unknownJumps.contains(ip)) {
unknownJumps.remove(Integer.valueOf(ip));
throw new UnknownJumpException(stack, ip, output);
}
if (visited[ip]) {
//logger.warning(path + ": Code already visited, ofs:" + Helper.formatAddress(pos2adr(ip)) + ", ip:" + ip);
break;
@@ -1840,8 +1835,6 @@ public class AVM2Code implements Cloneable {
public void initToSource() {
toSourceCount = 0;
unknownJumps = new ArrayList<>();
ignoredIns = new ArrayList<>();
}
private void injectDeclarations(List<GraphTargetItem> list, boolean[] declaredRegisters, List<Slot> declaredSlots, ABC abc, MethodBody body) {
@@ -2073,7 +2066,7 @@ public class AVM2Code implements Cloneable {
for (Long insAddr : insAddrToRemove) {
int pos = adr2posNoEx(insAddr);
if (pos > -1) {
code.get(pos).ignored = true;
code.get(pos).setIgnored(true, 0);
someIgnored = true;
}
}
@@ -2174,14 +2167,9 @@ public class AVM2Code implements Cloneable {
* @param body
*/
public void replaceInstruction(int pos, AVM2Instruction instruction, MethodBody body) {
if (pos < 0) {
pos = 0;
}
if (pos > code.size()) {
pos = code.size();
}
instruction.offset = code.get(pos).offset;
int oldByteCount = code.get(pos).getBytesLength();
AVM2Instruction oldInstruction = code.get(pos);
instruction.offset = oldInstruction.offset;
int oldByteCount = oldInstruction.getBytesLength();
int newByteCount = instruction.getBytesLength();
int byteDelta = newByteCount - oldByteCount;
@@ -2209,7 +2197,6 @@ public class AVM2Code implements Cloneable {
}, body);
}
code.set(pos, instruction);
//checkValidOffsets(body);
}
/**
@@ -2555,7 +2542,6 @@ public class AVM2Code implements Cloneable {
for (int i = 2; i < ins.operands.length; i++) {
toVisit.add(adr2pos(pos2adr(ip) + ins.operands[i]));
toVisitLast.add(ip);
//visitCode(, ip, refs);
}
ip = adr2pos(pos2adr(ip) + ins.operands[0]);
continue;
@@ -2573,7 +2559,6 @@ public class AVM2Code implements Cloneable {
try {
toVisit.add(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]));
toVisitLast.add(ip);
//visitCode(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), ip, refs);
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
@@ -2604,119 +2589,6 @@ public class AVM2Code implements Cloneable {
return refs;
}
private int visitCodeTrap(int ip, int[] visited, AVM2Instruction prev, AVM2Instruction prev2) {
int ret = 0;
while (ip < visited.length) {
visited[ip]++;
if (visited[ip] > 1) {
break;
}
AVM2Instruction ins = code.get(ip);
if (ins.definition instanceof ThrowIns) {
break;
}
if (ins.definition instanceof ReturnValueIns) {
break;
}
if (ins.definition instanceof ReturnVoidIns) {
break;
}
if (ins.definition instanceof LookupSwitchIns) {
try {
for (int i = 2; i < ins.operands.length; i++) {
ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.operands[i]), visited, prev, prev2);
}
ip = adr2pos(pos2adr(ip) + ins.operands[0]);
prev2 = prev;
prev = ins;
continue;
} catch (ConvertException ex) {
}
}
if (ins.definition instanceof JumpIns) {
try {
ip = adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]);
prev2 = prev;
prev = ins;
continue;
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
} else if (ins.definition instanceof IfTypeIns) {
if ((prev != null) && (prev2 != null)) {
if ((prev.definition instanceof PushByteIns) && (prev2.definition instanceof PushByteIns)) {
if (ins.definition instanceof IfEqIns) {
prev.ignored = true;
prev2.ignored = true;
if (prev.operands[0] == prev2.operands[0]) {
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
visited[ip]--;
} else {
ins.ignored = true;
ip++;
}
ret++;
continue;
}
if (ins.definition instanceof IfNeIns) {
prev.ignored = true;
prev2.ignored = true;
if (prev.operands[0] != prev2.operands[0]) {
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
visited[ip]--;
} else {
ins.ignored = true;
ip++;
}
ret++;
continue;
}
}
}
if ((prev != null) && ins.definition instanceof IfTrueIns) {
if (prev.definition instanceof PushTrueIns) {
prev.ignored = true;
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
visited[ip]--;
ret++;
continue;
} else if (prev.definition instanceof PushFalseIns) {
prev.ignored = true;
ins.ignored = true;
ret++;
ip++;
continue;
}
}
if ((prev != null) && ins.definition instanceof IfFalseIns) {
if (prev.definition instanceof PushFalseIns) {
prev.ignored = true;
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
visited[ip]--;
ret++;
continue;
} else if (prev.definition instanceof PushTrueIns) {
prev.ignored = true;
ins.ignored = true;
ret++;
ip++;
continue;
}
}
try {
ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), visited, prev, prev2);
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
}
ip++;
prev2 = prev;
prev = ins;
};
return ret;
}
private static class ControlFlowTag {
public String name;
@@ -2819,26 +2691,24 @@ public class AVM2Code implements Cloneable {
}
private void restoreControlFlowPass(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, boolean secondpass) throws InterruptedException {
private void restoreControlFlowPass(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
try {
HashMap<Integer, List<Integer>> refs;
int[] visited2 = new int[code.size()];
refs = visitCode(body);
HashMap<Integer, List<Object>> appended = new HashMap<>();
/*if (secondpass) {
restoreControlFlow(code.size() - 1, refs, visited2, appended);
} else*/ {
restoreControlFlow(0, refs, visited2, appended);
for (ABCException e : body.exceptions) {
try {
restoreControlFlow(adr2pos(e.start, true), refs, visited2, appended);
restoreControlFlow(adr2pos(e.target), refs, visited2, appended);
restoreControlFlow(adr2pos(e.end, true), refs, visited2, appended);
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
restoreControlFlow(0, refs, visited2, appended);
for (ABCException e : body.exceptions) {
try {
restoreControlFlow(adr2pos(e.start, true), refs, visited2, appended);
restoreControlFlow(adr2pos(e.target), refs, visited2, appended);
restoreControlFlow(adr2pos(e.end, true), refs, visited2, appended);
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
}
for (int ip : appended.keySet()) {
code.get(ip).replaceWith = appended.get(ip);
}
@@ -2861,7 +2731,6 @@ public class AVM2Code implements Cloneable {
} else {
acode.code.get(i).mappedOffset = pos2adr(tpos);
}
}
}
this.code = acode.code;
@@ -2874,38 +2743,13 @@ public class AVM2Code implements Cloneable {
}
public void restoreControlFlow(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
restoreControlFlowPass(constants, trait, info, body, false);
//restoreControlFlowPass(constants, body, true);
restoreControlFlowPass(constants, trait, info, body);
}
/*
public void removeIgnored(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
try {
List<Integer> outputMap = new ArrayList<>();
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
toASMSource(constants, trait, info, body, outputMap, ScriptExportMode.PCODE, writer);
String src = writer.toString();
AVM2Code acode = ASM3Parser.parse(new StringReader(src), constants, trait, body, info);
for (int i = 0; i < acode.code.size(); i++) {
if (outputMap.size() > i) {
int tpos = outputMap.get(i);
if (tpos == -1) {
} else if (code.get(tpos).mappedOffset >= 0) {
acode.code.get(i).mappedOffset = code.get(tpos).mappedOffset;
} else {
acode.code.get(i).mappedOffset = pos2adr(tpos);
}
}
}
this.code = acode.code;
} catch (IOException | AVM2ParseException ex) {
}
invalidateCache();
}*/
public void removeIgnored(MethodBody body) throws InterruptedException {
//System.err.println("removing ignored...");
for (int i = 0; i < code.size(); i++) {
if (code.get(i).ignored) {
if (code.get(i).isIgnored()) {
removeInstruction(i, body);
i--;
}
@@ -2918,8 +2762,7 @@ public class AVM2Code implements Cloneable {
int cnt = 0;
for (int i = code.size() - 1; i >= 0; i--) {
if (refs.get(i).isEmpty()) {
code.get(i).ignored = true;
//removeInstruction(i, body);
code.get(i).setIgnored(true, 0);
cnt++;
}
}
@@ -2930,7 +2773,7 @@ public class AVM2Code implements Cloneable {
AVM2Instruction ins = code.get(i);
if (ins.definition instanceof JumpIns) {
if (ins.operands[0] == 0) {
ins.ignored = true;
ins.setIgnored(true, 0);
cnt++;
}
}
@@ -2941,7 +2784,8 @@ public class AVM2Code implements Cloneable {
return cnt;
}
public void inlineJumpExit() {
public boolean inlineJumpExit() {
boolean modified = false;
int csize = code.size();
for (int i = 0; i < csize; i++) {
AVM2Instruction ins = code.get(i);
@@ -2955,6 +2799,7 @@ public class AVM2Code implements Cloneable {
AVM2Instruction ins2 = code.get(ni);
if (ins2.isExit()) {
code.set(i, new AVM2Instruction(ofs, ins2.definition, ins2.operands));
// todo: honfika: why to add 3 NOPs?
AVM2Instruction nopIns;
nopIns = new AVM2Instruction(ofs + 1, AVM2Instructions.Nop, null);
code.add(i + 1, nopIns);
@@ -2964,14 +2809,16 @@ public class AVM2Code implements Cloneable {
code.add(i + 3, nopIns);
i += 3;
csize = code.size();
modified = true;
}
}
} catch (ConvertException ex) {
//ignore
}
}
//ofs += insLen;
}
return modified;
}
public void markMappedOffsets() {
@@ -3436,9 +3283,7 @@ public class AVM2Code implements Cloneable {
ret.code = codeCopy;
}
ret.ignoredIns = new ArrayList<>();
ret.killedRegs = new HashMap<>();
ret.unknownJumps = new ArrayList<>();
return ret;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();

View File

@@ -16,10 +16,14 @@
*/
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.types.Decimal;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.ecma.Undefined;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.HashArrayList;
@@ -563,4 +567,36 @@ public class AVM2ConstantPool implements Cloneable {
throw new RuntimeException();
}
}
public AVM2Instruction makePush(Object ovalue) {
if (ovalue instanceof Long) {
long value = (Long) ovalue;
if (value >= -128 && value <= 127) {
return new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{(int) (long) value});
} else if (value >= -32768 && value <= 32767) {
return new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{((int) (long) value) & 0xffff});
} else {
return new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{getIntId(value, true)});
}
}
if (ovalue instanceof Double) {
return new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{getDoubleId((Double) ovalue, true)});
}
if (ovalue instanceof String) {
return new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{getStringId((String) ovalue, true)});
}
if (ovalue instanceof Boolean) {
if ((Boolean) ovalue) {
return new AVM2Instruction(0, AVM2Instructions.PushTrue, null);
}
return new AVM2Instruction(0, AVM2Instructions.PushFalse, null);
}
if (ovalue == Null.INSTANCE) {
return new AVM2Instruction(0, AVM2Instructions.PushNull, null);
}
if (ovalue == Undefined.INSTANCE) {
return new AVM2Instruction(0, AVM2Instructions.PushUndefined, null);
}
return null;
}
}

View File

@@ -33,8 +33,6 @@ public class LocalDataArea {
public Object returnValue;
public String executionException;
public AVM2RuntimeInfo runtimeInfo;
private byte[] domainMemory;
@@ -64,6 +62,5 @@ public class LocalDataArea {
localRegisters.clear();
jump = null;
returnValue = null;
executionException = null;
}
}

View File

@@ -16,14 +16,12 @@
*/
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
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.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
@@ -37,10 +35,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.action.ActionList;
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.flash.helpers.SWFDecompilerAdapter;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.NotCompileTimeItem;
@@ -59,7 +54,7 @@ import java.util.Map;
*
* @author JPEXS
*/
public class AVM2DeobfuscatorGetSet implements SWFDecompilerListener {
public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null);
@@ -67,43 +62,6 @@ public class AVM2DeobfuscatorGetSet 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, AVM2Instructions.PushByte, new int[]{(int) (long) value});
} else if (value >= -32768 && value <= 32767) {
return new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{((int) (long) value) & 0xffff});
} else {
return new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{cpool.getIntId(value, true)});
}
}
if (ovalue instanceof Double) {
return new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{cpool.getDoubleId((Double) ovalue, true)});
}
if (ovalue instanceof String) {
return new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{cpool.getStringId((String) ovalue, true)});
}
if (ovalue instanceof Boolean) {
if ((Boolean) ovalue) {
return new AVM2Instruction(0, AVM2Instructions.PushTrue, null);
}
return new AVM2Instruction(0, AVM2Instructions.PushFalse, null);
}
if (ovalue == Null.INSTANCE) {
return new AVM2Instruction(0, AVM2Instructions.PushNull, null);
}
if (ovalue == Undefined.INSTANCE) {
return new AVM2Instruction(0, AVM2Instructions.PushUndefined, null);
}
return null;
}
protected boolean removeObfuscationGetSets(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List<AVM2Instruction> inlineIns) throws InterruptedException {
AVM2Code code = body.getCode();
if (code.code.isEmpty()) {
@@ -253,28 +211,6 @@ public class AVM2DeobfuscatorGetSet implements SWFDecompilerListener {
}
}
@Override
public void actionTreeCreated(List<GraphTargetItem> tree, SWF swf) {
}
@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) {
}
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
AVM2Code code = body.getCode();

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
@@ -24,7 +23,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
import java.util.List;
import java.util.Map;
@@ -36,19 +35,11 @@ import java.util.Map;
*
* @author JPEXS
*/
public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple {
//private final int executionLimit = 30000;
@Override
public void actionListParsed(ActionList actions, SWF swf) {
}
public class AVM2DeobfuscatorJumps extends SWFDecompilerAdapter {
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
//body.getCode().markMappedOffsets();
//removeUnreachableInstructions(body.getCode(), cpool, trait, minfo, body);
AVM2Code code = body.getCode();
boolean found;
@@ -66,12 +57,10 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple {
AVM2Instruction srcIns = code.code.get(r);
if ((srcIns.definition instanceof JumpIns) || ((srcIns.definition instanceof IfTypeIns) && (r != i - 1))) {
{
int oldop = srcIns.operands[0];
srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytesLength()));
if (srcIns.operands[0] != oldop) {
found = true;
}
int oldop = srcIns.operands[0];
srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytesLength()));
if (srcIns.operands[0] != oldop) {
found = true;
}
}
}
@@ -79,7 +68,8 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple {
}
}
}
removeUnreachableInstructions(body.getCode(), body);
code.removeDeadCode(body);
} while (found);
}
}

View File

@@ -17,11 +17,11 @@
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.BaseLocalData;
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.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
@@ -31,13 +31,11 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIn
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.other.ThrowIns;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference;
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.graph.Graph;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -45,11 +43,13 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateException;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
@@ -61,11 +61,6 @@ import java.util.Set;
*/
public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
@Override
public void actionListParsed(ActionList actions, SWF swf) {
}
private Set<Integer> getRegisters(AVM2Code code) {
Set<Integer> regs = new HashSet<>();
for (AVM2Instruction ins : code.code) {
@@ -95,7 +90,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
//System.err.println("regdeo:" + path);
MethodBody originalBody = body;
removeUnreachableInstructions(body.getCode(), body);
body.getCode().removeDeadCode(body);
Set<Integer> ignoredRegs = new HashSet<>();
int localReservedCount = body.getLocalReservedCount();
@@ -116,7 +111,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
MethodBody bodybefore = body;
body = bodybefore.clone();
setReg = getFirstRegisterSetter(assignmentRef, classIndex, isStatic, scriptIndex, abc, body, ignoredRegs, ignoredRegGets);
setReg = getFirstRegisterSetter(assignmentRef, body, abc, ignoredRegs, ignoredRegGets);
//System.err.println("setreg " + setReg + " ass:" + assignmentRef.getVal());
if (setReg < 0) {
break;
@@ -140,7 +135,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
AVM2Instruction assignment = assignmentRef.getVal();
InstructionDefinition def = assignment.definition;
if ((def instanceof SetLocalTypeIns) || (def instanceof GetLocalTypeIns /*First usage -> value undefined*/)) {
super.removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, Arrays.asList(assignment));
super.removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, assignment);
}
if (def instanceof GetLocalTypeIns) {
@@ -153,7 +148,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
originalBody.exceptions = body.exceptions;
originalBody.setCode(body.getCode());
removeUnreachableInstructions(body.getCode(), body);
body.getCode().removeDeadCode(body);
//System.err.println("/deo");
}
@@ -178,31 +173,30 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
GetLocalTypeIns glt = (GetLocalTypeIns) ins.definition;
int regId = glt.getRegisterId(ins);
if (singleRegisters.containsKey(regId)) {
code.replaceInstruction(i, makePush(singleRegisters.get(regId).getResult(), cpool), body);
code.replaceInstruction(i, cpool.makePush(singleRegisters.get(regId).getResult()), body);
}
}
}
}
private int getFirstRegisterSetter(Reference<AVM2Instruction> assignment, int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, Set<Integer> ignoredRegisters, Set<Integer> ignoredGets) throws InterruptedException {
private int getFirstRegisterSetter(Reference<AVM2Instruction> assignment, MethodBody body, ABC abc, Set<Integer> ignoredRegisters, Set<Integer> ignoredGets) throws InterruptedException {
AVM2Code code = body.getCode();
if (code.code.isEmpty()) {
return -1;
}
return visitCode(assignment, new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets);
return visitCode(assignment, new HashSet<>(), new Stack<>(), body, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets);
}
private int visitCode(Reference<AVM2Instruction> assignment, Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, Set<Integer> ignored, Set<Integer> ignoredGets) throws InterruptedException {
List<GraphTargetItem> output = new ArrayList<>();
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs);
localData.localRegs.put(0, new NullAVM2Item(null, null)); // this
private int visitCode(Reference<AVM2Instruction> assignment, Set<Integer> visited, Stack<Object> stack, MethodBody body, ABC abc, AVM2Code code, int idx, int endIdx, Set<Integer> ignored, Set<Integer> ignoredGets) throws InterruptedException {
LocalDataArea localData = new LocalDataArea();
initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs, false);
localData.localRegisters.put(0, Null.INSTANCE); // this
List<Integer> toVisit = new ArrayList<>();
toVisit.add(idx);
List<TranslateStack> toVisitStacks = new ArrayList<>();
List<Stack<Object>> toVisitStacks = new ArrayList<>();
toVisitStacks.add(stack);
outer:
while (!toVisit.isEmpty()) {
@@ -227,12 +221,17 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
//System.err.println("" + idx + ": " + ins + " stack:" + stack.size());
// do not throw EmptyStackException, much faster
int requiredStackSize = ins.getStackPopCount(localData);
int requiredStackSize = def.getStackPopCount(ins, abc);
if (stack.size() < requiredStackSize) {
continue outer;
}
ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
localData.operandStack = stack;
try {
ins.definition.execute(localData, abc.constants, ins);
} catch (AVM2ExecutionException ex) {
Logger.getLogger(AVM2DeobfuscatorRegisters.class.getName()).log(Level.SEVERE, null, ex);
}
//if (!(def instanceof KillIns))
if (def instanceof SetLocalTypeIns) {
@@ -312,7 +311,9 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
continue;
}
toVisit.add(nidx);
toVisitStacks.add((TranslateStack) stack.clone());
@SuppressWarnings("unchecked")
Stack<Object> cloneStack = (Stack<Object>) stack.clone();
toVisitStacks.add(cloneStack);
}
}
/*if (ins.definition instanceof IfTypeIns) {

View File

@@ -0,0 +1,335 @@
/*
* 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.deobfuscation;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
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.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.other.ThrowIns;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference;
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.graph.Graph;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateException;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* AVM2 Deobfuscator removing single assigned local registers.
*
* Example: var a = true; var b = false; ... if(a){ ...ok }else{ not executed }
*
* @author JPEXS
*/
public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
private Set<Integer> getRegisters(AVM2Code code) {
Set<Integer> regs = new HashSet<>();
for (AVM2Instruction ins : code.code) {
InstructionDefinition def = ins.definition;
if (def instanceof SetLocalTypeIns) {
int regId = ((SetLocalTypeIns) def).getRegisterId(ins);
regs.add(regId);
} else if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(ins);
regs.add(regId);
} else {
for (int p = 0; p < ins.definition.operands.length; p++) {
int op = ins.definition.operands[p];
if (op == AVM2Code.DAT_REGISTER_INDEX || op == AVM2Code.DAT_LOCAL_REG_INDEX) {
int regId = ins.operands[p];
regs.add(regId);
}
}
}
}
return regs;
}
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
//System.err.println("regdeo:" + path);
MethodBody originalBody = body;
body.getCode().removeDeadCode(body);
Set<Integer> ignoredRegs = new HashSet<>();
int localReservedCount = body.getLocalReservedCount();
for (int i = 0; i < localReservedCount; i++) {
ignoredRegs.add(i);
}
int setReg = 0;
List<Integer> listedRegs = new ArrayList<>();
List<MethodBody> listedLastBodies = new ArrayList<>();
Set<Integer> ignoredRegGets = new HashSet<>();
Reference<AVM2Instruction> assignmentRef = new Reference<>(null);
while (setReg > -1) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
MethodBody bodybefore = body;
body = bodybefore.clone();
setReg = getFirstRegisterSetter(assignmentRef, classIndex, isStatic, scriptIndex, abc, body, ignoredRegs, ignoredRegGets);
//System.err.println("setreg " + setReg + " ass:" + assignmentRef.getVal());
if (setReg < 0) {
break;
}
// if there is second assignment
if (listedRegs.contains(setReg)) {
//System.err.println("second assignment of loc" + setReg + ", ignoring");
int lindex = listedRegs.indexOf(setReg);
body = listedLastBodies.get(lindex); // switch to body before
ignoredRegs.add(setReg); // this is not obfuscated
for (int i = listedRegs.size() - 1; i >= lindex; i--) {
int r = listedRegs.get(i);
listedRegs.remove(i);
listedLastBodies.remove(i);
ignoredRegGets.remove(r);
}
continue;
}
AVM2Instruction assignment = assignmentRef.getVal();
InstructionDefinition def = assignment.definition;
if ((def instanceof SetLocalTypeIns) || (def instanceof GetLocalTypeIns /*First usage -> value undefined*/)) {
super.removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, Arrays.asList(assignment));
}
if (def instanceof GetLocalTypeIns) {
ignoredRegGets.add(setReg);
}
listedRegs.add(setReg);
listedLastBodies.add(bodybefore);
}
originalBody.exceptions = body.exceptions;
originalBody.setCode(body.getCode());
body.getCode().removeDeadCode(body);
//System.err.println("/deo");
}
private void replaceSingleUseRegisters(Map<Integer, GraphTargetItem> singleRegisters, List<AVM2Instruction> setInss, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
AVM2Code code = body.getCode();
for (int i = 0; i < code.code.size(); i++) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
AVM2Instruction ins = code.code.get(i);
if (((setInss == null) || setInss.contains(ins)) && (ins.definition instanceof SetLocalTypeIns)) {
SetLocalTypeIns slt = (SetLocalTypeIns) ins.definition;
int regId = slt.getRegisterId(ins);
if (singleRegisters.containsKey(regId)) {
code.replaceInstruction(i, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), body);
}
}
if (ins.definition instanceof GetLocalTypeIns) {
GetLocalTypeIns glt = (GetLocalTypeIns) ins.definition;
int regId = glt.getRegisterId(ins);
if (singleRegisters.containsKey(regId)) {
code.replaceInstruction(i, cpool.makePush(singleRegisters.get(regId).getResult()), body);
}
}
}
}
private int getFirstRegisterSetter(Reference<AVM2Instruction> assignment, int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, Set<Integer> ignoredRegisters, Set<Integer> ignoredGets) throws InterruptedException {
AVM2Code code = body.getCode();
if (code.code.isEmpty()) {
return -1;
}
return visitCode(assignment, new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets);
}
private int visitCode(Reference<AVM2Instruction> assignment, Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, Set<Integer> ignored, Set<Integer> ignoredGets) throws InterruptedException {
List<GraphTargetItem> output = new ArrayList<>();
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs);
localData.localRegs.put(0, new NullAVM2Item(null, null)); // this
List<Integer> toVisit = new ArrayList<>();
toVisit.add(idx);
List<TranslateStack> toVisitStacks = new ArrayList<>();
toVisitStacks.add(stack);
outer:
while (!toVisit.isEmpty()) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
idx = toVisit.remove(0);
stack = toVisitStacks.remove(0);
while (true) {
if (idx > endIdx) {
break;
}
if (visited.contains(idx)) {
break;
}
visited.add(idx);
AVM2Instruction ins = code.code.get(idx);
InstructionDefinition def = ins.definition;
//System.err.println("" + idx + ": " + ins + " stack:" + stack.size());
// do not throw EmptyStackException, much faster
int requiredStackSize = ins.getStackPopCount(localData);
if (stack.size() < requiredStackSize) {
continue outer;
}
ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
//if (!(def instanceof KillIns))
if (def instanceof SetLocalTypeIns) {
int regId = ((SetLocalTypeIns) def).getRegisterId(ins);
if (!ignored.contains(regId)) {
assignment.setVal(ins);
return regId;
}
} else if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(ins);
if (!ignored.contains(regId) && !ignoredGets.contains(regId)) {
assignment.setVal(ins);
return regId;
}
} else {
for (int p = 0; p < ins.definition.operands.length; p++) {
int op = ins.definition.operands[p];
if (op == AVM2Code.DAT_REGISTER_INDEX/* || op == AVM2Code.DAT_LOCAL_REG_INDEX ???*/) {
int regId = ins.operands[p];
if (!ignored.contains(regId)) {
assignment.setVal(ins);
return regId;
}
}
}
}
idx++;
if (ins.definition instanceof JumpIns) {
long address = ins.offset + ins.getBytesLength() + ins.operands[0];
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
if (idx == -1) {
throw new TranslateException("Jump target not found: " + address);
}
}
if (ins.isBranch()) {
List<Integer> branches = ins.getBranches(new GraphSource() {
@Override
public int size() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public GraphSourceItem get(int pos) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public boolean isEmpty() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public List<GraphTargetItem> translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public int adr2pos(long adr) {
return code.adr2pos(adr);
}
@Override
public long pos2adr(int pos) {
return code.pos2adr(pos);
}
});
idx = branches.get(0);
for (int n = 1; n < branches.size(); n++) {
//visitCode(visited, (TranslateStack) stack.clone(), classIndex, isStatic, body, scriptIndex, abc, code, branches.get(n), endIdx, result);
int nidx = branches.get(n);
if (visited.contains(nidx)) {
continue;
}
toVisit.add(nidx);
toVisitStacks.add((TranslateStack) stack.clone());
}
}
/*if (ins.definition instanceof IfTypeIns) {
long address = ins.offset + ins.getBytes().length + ins.operands[0];
int newIdx = code.adr2pos(address);
if (newIdx == -1) {
throw new TranslateException("If target not found: " + address);
}
visitCode(visited, (TranslateStack) stack.clone(), classIndex, isStatic, body, scriptIndex, abc, code, newIdx, endIdx, result);
}*/
if (ins.definition instanceof ReturnValueIns) {
break;
}
if (ins.definition instanceof ThrowIns) {
break;
}
if (ins.definition instanceof ReturnVoidIns) {
break;
}
}
}
return -1;
}
}

View File

@@ -16,12 +16,10 @@
*/
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
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.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack;
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
@@ -71,144 +69,63 @@ 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.instructions.types.CoerceOrConvertTypeIns;
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.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.NotCompileTime;
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.NotCompileTimeItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
import com.jpexs.decompiler.flash.helpers.collections.FixItemCounterStack;
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
/**
*
* @author JPEXS
*/
public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null);
private static final NotCompileTimeItem NOT_COMPILE_TIME_UNDEFINED_ITEM = new NotCompileTimeItem(null, null, UNDEFINED_ITEM);
public class AVM2DeobfuscatorSimple extends SWFDecompilerAdapter {
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, AVM2Instructions.PushByte, new int[]{(int) (long) value});
} else if (value >= -32768 && value <= 32767) {
return new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{((int) (long) value) & 0xffff});
} else {
return new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{cpool.getIntId(value, true)});
}
}
if (ovalue instanceof Double) {
return new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{cpool.getDoubleId((Double) ovalue, true)});
}
if (ovalue instanceof String) {
return new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{cpool.getStringId((String) ovalue, true)});
}
if (ovalue instanceof Boolean) {
if ((Boolean) ovalue) {
return new AVM2Instruction(0, AVM2Instructions.PushTrue, null);
}
return new AVM2Instruction(0, AVM2Instructions.PushFalse, null);
}
if (ovalue instanceof Null) {
return new AVM2Instruction(0, AVM2Instructions.PushNull, null);
}
if (ovalue instanceof Undefined) {
return new AVM2Instruction(0, AVM2Instructions.PushUndefined, null);
}
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.getValue(), 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(Null.INSTANCE, cpool);
} else if (graphTargetItem instanceof UndefinedAVM2Item) {
return makePush(Undefined.INSTANCE, cpool);
} else {
return null;
}
}
protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List<AVM2Instruction> inlineIns) throws InterruptedException {
protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, AVM2Instruction inlineIns) throws InterruptedException {
AVM2Code code = body.getCode();
if (code.code.isEmpty()) {
return false;
}
Map<Integer, GraphTargetItem> staticRegs = new HashMap<>();
for (AVM2Instruction ins : inlineIns) {
if (ins.definition instanceof GetLocalTypeIns) {
staticRegs.put(((GetLocalTypeIns) ins.definition).getRegisterId(ins), new UndefinedAVM2Item(ins, null));
}
Map<Integer, Object> staticRegs = new HashMap<>();
if (inlineIns != null && inlineIns.definition instanceof GetLocalTypeIns) {
staticRegs.put(((GetLocalTypeIns) inlineIns.definition).getRegisterId(inlineIns), Undefined.INSTANCE);
}
if (code.code.isEmpty()) {
return false;
}
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
FixItemCounterStack stack = new FixItemCounterStack();
LocalDataArea localData = new LocalDataArea();
localData.operandStack = stack;
int localReservedCount = body.getLocalReservedCount();
for (int i = 0; i < code.code.size(); i++) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
localData.scopeStack.clear();
localData.localRegs.clear();
localData.localRegAssignmentIps.clear();
localData.localRegs.clear();
initLocalRegs(localData, localReservedCount, body.max_regs);
localData.clear();
initLocalRegs(localData, localReservedCount, body.max_regs, i == 0);
executeInstructions(staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns);
if (executeInstructions(staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns)) {
code.removeDeadCode(body);
i--;
}
}
return false;
}
protected void removeUnreachableInstructions(AVM2Code code, MethodBody body) throws InterruptedException {
code.removeDeadCode(body);
}
protected boolean removeZeroJumps(AVM2Code code, MethodBody body) throws InterruptedException {
boolean result = false;
for (int i = 0; i < code.code.size(); i++) {
@@ -228,37 +145,21 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
return result;
}
protected 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<>(body.max_regs);
localData.localRegAssignmentIps = new HashMap<>();
localData.scopeStack = new ScopeStack(true);
localData.methodBody = body;
localData.abc = abc;
localData.localRegNames = new HashMap<>();
localData.scriptIndex = scriptIndex;
localData.ip = 0;
localData.code = body.getCode();
return localData;
}
protected void initLocalRegs(AVM2LocalData localData, int localReservedCount, int maxRegs) {
protected void initLocalRegs(LocalDataArea localData, int localReservedCount, int maxRegs, boolean executeFromFirst) {
for (int i = 0; i < localReservedCount; i++) {
localData.localRegs.put(i, NOT_COMPILE_TIME_UNDEFINED_ITEM);
localData.localRegisters.put(i, NotCompileTime.INSTANCE);
}
for (int i = localReservedCount; i < maxRegs; i++) {
localData.localRegs.put(i, UNDEFINED_ITEM);
localData.localRegisters.put(i, executeFromFirst ? Undefined.INSTANCE : NotCompileTime.INSTANCE);
}
}
private void executeInstructions(Map<Integer, GraphTargetItem> staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List<AVM2Instruction> inlineIns) throws InterruptedException {
List<GraphTargetItem> output = new ArrayList<>();
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
private boolean executeInstructions(Map<Integer, Object> staticRegs, MethodBody body, ABC abc, AVM2Code code, LocalDataArea localData, int idx, int endIdx, ExecutionResult result, AVM2Instruction inlineIns) throws InterruptedException {
int instructionsProcessed = 0;
FixItemCounterStack stack = (FixItemCounterStack) localData.operandStack;
Set<Long> refs = code.getImportantOffsets(body);
boolean modified = false;
while (true) {
if (idx > endIdx) {
break;
@@ -269,56 +170,83 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
}
AVM2Instruction ins = code.code.get(idx);
if (ins.definition instanceof NewFunctionIns) {
if (idx + 1 < code.code.size()) {
if (code.code.get(idx + 1).definition instanceof PopIns) {
code.removeInstruction(idx + 1, body);
code.removeInstruction(idx, body);
continue;
}
}
} else {
// do not throw EmptyStackException, much faster
int requiredStackSize = ins.getStackPopCount(localData);
if (stack.size() < requiredStackSize) {
return;
}
ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
if (instructionsProcessed > 0 && refs.contains(ins.offset)) {
break;
}
modified = modified | code.inlineJumpExit();
InstructionDefinition def = ins.definition;
if (inlineIns.contains(ins)) {
if (inlineIns == ins) {
if (def instanceof SetLocalTypeIns) {
int regId = ((SetLocalTypeIns) def).getRegisterId(ins);
staticRegs.put(regId, localData.localRegs.get(regId).getNotCoerced());
staticRegs.put(regId, localData.localRegisters.get(regId));
code.replaceInstruction(idx, new AVM2Instruction(0, DeobfuscatePopIns.getInstance(), null), body);
}
}
if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(ins);
if (staticRegs.containsKey(regId)) {
if (stack.isEmpty()) {
return;
}
stack.pop();
AVM2Instruction pushins = makePush(abc.constants, staticRegs.get(regId));
AVM2Instruction pushins = abc.constants.makePush(staticRegs.get(regId));
if (pushins == null) {
return;
break;
}
code.replaceInstruction(idx, pushins, body);
stack.push(staticRegs.get(regId));
ins = pushins;
def = ins.definition;
}
}
if (def instanceof NewFunctionIns) {
if (idx + 1 < code.code.size()) {
if (code.code.get(idx + 1).definition instanceof PopIns) {
code.removeInstruction(idx + 1, body);
code.removeInstruction(idx, body);
modified = true;
continue;
}
}
} else {
// do not throw EmptyStackException, much faster
int requiredStackSize = def.getStackPopCount(ins, abc);
if (stack.size() < requiredStackSize) {
break;
}
if (requiredStackSize > 0 && !def.isNotCompileTimeSupported()) {
boolean notCompileTime = false;
for (int i = 0; i < requiredStackSize; i++) {
if (stack.peek(i + 1) == NotCompileTime.INSTANCE) {
notCompileTime = true;
break;
}
}
if (notCompileTime) {
break;
}
}
if (localData.scopeStack.size() < -def.getScopeStackDelta(ins, abc)) {
break;
}
boolean supported;
try {
localData.jump = null;
supported = def.execute(localData, abc.constants, ins);
} catch (AVM2ExecutionException ex) {
supported = false;
}
if (!supported) {
break;
}
}
boolean ok = false;
// todo: honfika: order by statistics
if (def instanceof PushByteIns
if (def.isNotCompileTimeSupported() || def instanceof PushByteIns
|| def instanceof PushShortIns
|| def instanceof PushIntIns
|| def instanceof PushDoubleIns
@@ -361,6 +289,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|| def instanceof StrictEqualsIns
|| def instanceof PopIns
|| def instanceof GetLocalTypeIns
|| def instanceof SetLocalTypeIns
|| def instanceof NewFunctionIns
|| def instanceof CoerceOrConvertTypeIns) {
ok = true;
@@ -370,43 +299,16 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
break;
}
if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(ins);
if (staticRegs.containsKey(regId)) {
if (stack.isEmpty()) {
return;
}
stack.pop();
stack.push(staticRegs.get(regId));
} else {
break;
}
}
boolean ifed = false;
if (def instanceof JumpIns) {
if (def instanceof IfTypeIns && !(def instanceof JumpIns)) {
long address = ins.offset + ins.getBytesLength() + ins.operands[0];
idx = code.adr2pos(address);
if (idx == -1) {
throw new TranslateException("Jump target not found: " + address);
}
} else if (def instanceof IfTypeIns) {
if (stack.isEmpty()) {
return;
}
GraphTargetItem top = stack.pop();
Object res = top.getResult();
long address = ins.offset + ins.getBytesLength() + ins.operands[0];
int nidx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
int nidx = code.adr2pos(address);
AVM2Instruction tarIns = code.code.get(nidx);
//Some IfType instructions need more than 1 operand, we must pop out all of them
int stackCount = -def.getStackDelta(ins, abc);
if (EcmaScript.toBoolean(res)) {
if (localData.jump != null) {
//System.err.println("replacing " + ins + " on " + idx + " with jump");
AVM2Instruction jumpIns = new AVM2Instruction(0, AVM2Instructions.Jump, new int[]{0});
//jumpIns.operands[0] = ins.operands[0] /*- ins.getBytes().length*/ + jumpIns.getBytes().length;
@@ -426,8 +328,9 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
//ins.definition = DeobfuscatePopIns.getInstance();
idx++;
}
modified = true;
ifed = true;
//break;
} else {
idx++;
}
@@ -444,36 +347,24 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
if (ifed) {
break;
}
if (localData.jump != null) {
idx = code.adr2pos(localData.jump);
if (idx == -1) {
throw new TranslateException("Jump target not found: " + localData.jump);
}
}
}
}
@Override
public void actionTreeCreated(List<GraphTargetItem> tree, SWF swf) {
}
@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) {
return modified;
}
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
AVM2Code code = body.getCode();
removeUnreachableInstructions(code, body);
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, new ArrayList<>());
code.removeDeadCode(body);
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, null);
removeZeroJumps(code, body);
}
@@ -483,6 +374,6 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
public int instructionsProcessed = -1;
public TranslateStack stack = new TranslateStack("?");
public Stack<Object> stack = new Stack<>();
}
}

View File

@@ -0,0 +1,422 @@
/*
* 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.deobfuscation;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
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.DivideIns;
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.MultiplyIIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIns;
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.SetLocalTypeIns;
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.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.instructions.types.CoerceOrConvertTypeIns;
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.traits.Trait;
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.SWFDecompilerAdapter;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.NotCompileTimeItem;
import com.jpexs.decompiler.graph.ScopeStack;
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.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author JPEXS
*/
public class AVM2DeobfuscatorSimpleOld extends SWFDecompilerAdapter {
private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null);
private static final NotCompileTimeItem NOT_COMPILE_TIME_UNDEFINED_ITEM = new NotCompileTimeItem(null, null, UNDEFINED_ITEM);
private final int executionLimit = 30000;
protected AVM2Instruction makePush(AVM2ConstantPool cpool, GraphTargetItem graphTargetItem) {
if (graphTargetItem instanceof IntegerValueAVM2Item) {
IntegerValueAVM2Item iv = (IntegerValueAVM2Item) graphTargetItem;
return cpool.makePush(iv.value);
} else if (graphTargetItem instanceof FloatValueAVM2Item) {
FloatValueAVM2Item fv = (FloatValueAVM2Item) graphTargetItem;
return cpool.makePush(fv.value);
} else if (graphTargetItem instanceof StringAVM2Item) {
StringAVM2Item fv = (StringAVM2Item) graphTargetItem;
return cpool.makePush(fv.getValue());
} else if (graphTargetItem instanceof TrueItem) {
return cpool.makePush(Boolean.TRUE);
} else if (graphTargetItem instanceof FalseItem) {
return cpool.makePush(Boolean.FALSE);
} else if (graphTargetItem instanceof NullAVM2Item) {
return cpool.makePush(Null.INSTANCE);
} else if (graphTargetItem instanceof UndefinedAVM2Item) {
return cpool.makePush(Undefined.INSTANCE);
}
return null;
}
protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List<AVM2Instruction> inlineIns) throws InterruptedException {
AVM2Code code = body.getCode();
if (code.code.isEmpty()) {
return false;
}
Map<Integer, GraphTargetItem> staticRegs = new HashMap<>();
for (AVM2Instruction ins : inlineIns) {
if (ins.definition instanceof GetLocalTypeIns) {
staticRegs.put(((GetLocalTypeIns) ins.definition).getRegisterId(ins), new UndefinedAVM2Item(ins, null));
}
}
if (code.code.isEmpty()) {
return false;
}
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
int localReservedCount = body.getLocalReservedCount();
for (int i = 0; i < code.code.size(); i++) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
localData.scopeStack.clear();
localData.localRegs.clear();
localData.localRegAssignmentIps.clear();
localData.localRegs.clear();
initLocalRegs(localData, localReservedCount, body.max_regs);
executeInstructions(staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns);
}
return false;
}
protected boolean removeZeroJumps(AVM2Code code, MethodBody body) throws InterruptedException {
boolean result = false;
for (int i = 0; i < code.code.size(); i++) {
AVM2Instruction ins = code.code.get(i);
if (ins.definition instanceof JumpIns) {
if (ins.operands[0] == 0) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
code.removeInstruction(i, body);
i--;
result = true;
}
}
}
return result;
}
protected 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<>(body.max_regs);
localData.localRegAssignmentIps = new HashMap<>();
localData.scopeStack = new ScopeStack(true);
localData.methodBody = body;
localData.abc = abc;
localData.localRegNames = new HashMap<>();
localData.scriptIndex = scriptIndex;
localData.ip = 0;
localData.code = body.getCode();
return localData;
}
protected void initLocalRegs(AVM2LocalData localData, int localReservedCount, int maxRegs) {
for (int i = 0; i < localReservedCount; i++) {
localData.localRegs.put(i, NOT_COMPILE_TIME_UNDEFINED_ITEM);
}
for (int i = localReservedCount; i < maxRegs; i++) {
localData.localRegs.put(i, UNDEFINED_ITEM);
}
}
private void executeInstructions(Map<Integer, GraphTargetItem> staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List<AVM2Instruction> inlineIns) throws InterruptedException {
List<GraphTargetItem> output = new ArrayList<>();
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
int instructionsProcessed = 0;
while (true) {
if (idx > endIdx) {
break;
}
if (instructionsProcessed > executionLimit) {
break;
}
AVM2Instruction ins = code.code.get(idx);
if (ins.definition instanceof NewFunctionIns) {
if (idx + 1 < code.code.size()) {
if (code.code.get(idx + 1).definition instanceof PopIns) {
code.removeInstruction(idx + 1, body);
code.removeInstruction(idx, body);
continue;
}
}
} else {
// do not throw EmptyStackException, much faster
int requiredStackSize = ins.getStackPopCount(localData);
if (stack.size() < requiredStackSize) {
return;
}
ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
}
InstructionDefinition def = ins.definition;
if (inlineIns.contains(ins)) {
if (def instanceof SetLocalTypeIns) {
int regId = ((SetLocalTypeIns) def).getRegisterId(ins);
staticRegs.put(regId, localData.localRegs.get(regId).getNotCoerced());
code.replaceInstruction(idx, new AVM2Instruction(0, DeobfuscatePopIns.getInstance(), null), body);
}
}
if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(ins);
if (staticRegs.containsKey(regId)) {
if (stack.isEmpty()) {
return;
}
stack.pop();
AVM2Instruction pushins = makePush(abc.constants, staticRegs.get(regId));
if (pushins == null) {
return;
}
code.replaceInstruction(idx, pushins, body);
stack.push(staticRegs.get(regId));
ins = pushins;
def = ins.definition;
}
}
boolean ok = false;
// todo: honfika: order by statistics
if (def instanceof PushByteIns
|| def instanceof PushShortIns
|| def instanceof PushIntIns
|| def instanceof PushDoubleIns
|| def instanceof PushStringIns
|| def instanceof PushNullIns
|| def instanceof PushUndefinedIns
|| def instanceof PushFalseIns
|| def instanceof PushTrueIns
|| def instanceof DupIns
|| def instanceof SwapIns
|| def instanceof AddIns
|| def instanceof AddIIns
|| def instanceof SubtractIns
|| def instanceof SubtractIIns
|| def instanceof ModuloIns
|| def instanceof MultiplyIns
|| def instanceof MultiplyIIns//
|| def instanceof DivideIns//
|| def instanceof BitAndIns
|| def instanceof BitXorIns
|| def instanceof BitOrIns
|| def instanceof LShiftIns
|| def instanceof RShiftIns
|| def instanceof URShiftIns
|| def instanceof EqualsIns
|| def instanceof NotIns
|| def instanceof NegateIns//
|| def instanceof NegateIIns//
|| def instanceof IncrementIns//
|| def instanceof IncrementIIns//
|| def instanceof DecrementIns//
|| def instanceof DecrementIIns //
|| def instanceof IfTypeIns
|| def instanceof JumpIns
|| def instanceof EqualsIns
|| def instanceof LessEqualsIns
|| def instanceof GreaterEqualsIns
|| def instanceof GreaterThanIns
|| def instanceof LessThanIns
|| def instanceof StrictEqualsIns
|| def instanceof PopIns
|| def instanceof GetLocalTypeIns
|| def instanceof NewFunctionIns
|| def instanceof CoerceOrConvertTypeIns) {
ok = true;
}
if (!ok) {
break;
}
if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(ins);
if (staticRegs.containsKey(regId)) {
if (stack.isEmpty()) {
return;
}
stack.pop();
stack.push(staticRegs.get(regId));
} else {
break;
}
}
boolean ifed = false;
if (def instanceof JumpIns) {
long address = ins.offset + ins.getBytesLength() + ins.operands[0];
idx = code.adr2pos(address);
if (idx == -1) {
throw new TranslateException("Jump target not found: " + address);
}
} else if (def instanceof IfTypeIns) {
if (stack.isEmpty()) {
return;
}
GraphTargetItem top = stack.pop();
Object res = top.getResult();
long address = ins.offset + ins.getBytesLength() + ins.operands[0];
int nidx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
AVM2Instruction tarIns = code.code.get(nidx);
//Some IfType instructions need more than 1 operand, we must pop out all of them
int stackCount = -def.getStackDelta(ins, abc);
if (EcmaScript.toBoolean(res)) {
//System.err.println("replacing " + ins + " on " + idx + " with jump");
AVM2Instruction jumpIns = new AVM2Instruction(0, AVM2Instructions.Jump, new int[]{0});
//jumpIns.operands[0] = ins.operands[0] /*- ins.getBytes().length*/ + jumpIns.getBytes().length;
code.replaceInstruction(idx, jumpIns, body);
jumpIns.operands[0] = (int) (tarIns.offset - jumpIns.offset - jumpIns.getBytesLength());
for (int s = 0; s < stackCount; s++) {
code.insertInstruction(idx, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), true, body);
}
idx = code.adr2pos(jumpIns.offset + jumpIns.getBytesLength() + jumpIns.operands[0]);
} else {
//System.err.println("replacing " + ins + " on " + idx + " with pop");
code.replaceInstruction(idx, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), body);
for (int s = 1 /*first is replaced*/; s < stackCount; s++) {
code.insertInstruction(idx, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), true, body);
}
//ins.definition = DeobfuscatePopIns.getInstance();
idx++;
}
ifed = true;
//break;
} else {
idx++;
}
instructionsProcessed++;
if (result != null && stack.allItemsFixed()) {
result.idx = idx == code.code.size() ? idx - 1 : idx;
result.instructionsProcessed = instructionsProcessed;
result.stack.clear();
result.stack.addAll(stack);
}
if (ifed) {
break;
}
}
}
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
AVM2Code code = body.getCode();
code.removeDeadCode(body);
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, new ArrayList<>());
removeZeroJumps(code, body);
}
class ExecutionResult {
public int idx = -1;
public int instructionsProcessed = -1;
public TranslateStack stack = new TranslateStack("?");
}
}

View File

@@ -51,7 +51,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
public String comment;
public boolean ignored = false;
private boolean ignored = false;
public long mappedOffset = -1;
@@ -303,7 +303,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
}
public String getComment() {
if (ignored) {
if (isIgnored()) {
return " ;ignored";
}
if ((comment == null) || comment.isEmpty()) {

View File

@@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -124,6 +125,10 @@ public abstract class InstructionDefinition implements Serializable {
}
}
public boolean isNotCompileTimeSupported() {
return false;
}
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) throws AVM2ExecutionException {
//throw new UnsupportedOperationException("Instruction " + instructionName + " not implemented");
return false;
@@ -164,18 +169,31 @@ public abstract class InstructionDefinition implements Serializable {
return 0;
}
protected void resolveMultiname(LocalDataArea localData, AVM2ConstantPool constants, int multinameIndex) {
if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) {
Multiname multiname = constants.getMultiname(multinameIndex);
if (multiname.needsName()) {
Object name = localData.operandStack.pop();
}
if (multiname.needsNs()) {
Object ns = localData.operandStack.pop();
}
}
}
protected FullMultinameAVM2Item resolveMultiname(AVM2LocalData localData, boolean property, TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins) {
GraphTargetItem ns = null;
GraphTargetItem name = null;
if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) {
if (constants.getMultiname(multinameIndex).needsName()) {
Multiname multiname = constants.getMultiname(multinameIndex);
if (multiname.needsName()) {
name = stack.pop();
}
if (constants.getMultiname(multinameIndex).needsNs()) {
if (multiname.needsNs()) {
ns = stack.pop();
}
}
return new FullMultinameAVM2Item(property, ins, localData.lineStartInstruction, multinameIndex, name, ns);
}

View File

@@ -52,7 +52,7 @@ public class ConstructIns extends InstructionDefinition {
passArguments.set(i, lda.operandStack.pop());
}
Object obj = lda.operandStack.pop();*/
lda.executionException = "Cannot call constructor";
//lda.executionException = "Cannot call constructor";
return false;
//call construct property of obj
//push new instance

View File

@@ -48,7 +48,7 @@ public class ConstructPropIns extends InstructionDefinition {
}*/
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
lda.executionException = "Cannot construct property";
//lda.executionException = "Cannot construct property";
return false;
//create property
//push new instance

View File

@@ -43,7 +43,7 @@ public class ConstructSuperIns extends InstructionDefinition {
passArguments.set(i, lda.operandStack.pop());
}
Object obj = lda.operandStack.pop();*/
lda.executionException = "Cannot call super constructor";
//lda.executionException = "Cannot call super constructor";
return false;
//call construct property of obj
//do not push anything

View File

@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
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.model.CallAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
@@ -35,18 +36,29 @@ public class CallIns extends InstructionDefinition {
super(0x41, "call", new int[]{AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
/*int argCount = ins.getParamAsLong(constants, 0).intValue();
List<Object> passArguments = new ArrayList<Object>();
int argCount = ins.getParamAsLong(constants, 0).intValue();
/* List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
Object receiver = lda.operandStack.pop();
Object function = lda.operandStack.pop();*/
lda.executionException = "Call to unknown function";
return false;
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
Object receiver = lda.operandStack.pop();
Object function = lda.operandStack.pop();
//push(result)
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Call to unknown function";
return true;
}
@Override

View File

@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
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.model.CallMethodAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
@@ -35,18 +36,29 @@ public class CallMethodIns extends InstructionDefinition {
super(0x43, "callmethod", new int[]{AVM2Code.DAT_METHOD_INDEX, AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
/*int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of object's method
int argCount = ins.getParamAsLong(constants, 1).intValue();
List<Object> passArguments = new ArrayList<Object>();
//int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of object's method
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
Object receiver = lda.operandStack.pop();*/
lda.executionException = "Call to unknown method";
return false;
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
Object receiver = lda.operandStack.pop();
//push(result)
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Call to unknown method";
return true;
}
@Override

View File

@@ -18,9 +18,12 @@ package com.jpexs.decompiler.flash.abc.avm2.instructions.executing;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.model.CallPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
@@ -33,6 +36,33 @@ public class CallPropLexIns extends CallPropertyIns {
instructionCode = 0x4c;
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
int multinameIndex = ins.operands[0];
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
resolveMultiname(lda, constants, multinameIndex);
Object obj = lda.operandStack.pop();
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Call to unknown property";
return true;
}
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];

View File

@@ -36,22 +36,32 @@ public class CallPropVoidIns extends InstructionDefinition {
super(0x4f, "callpropvoid", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
//same as callproperty
/*
int multinameIndex = ins.getParamAsLong(constants, 0).intValue();
int argCount = ins.getParamAsLong(constants, 1).intValue();
List<Object> passArguments = new ArrayList<Object>();
int multinameIndex = ins.operands[0];
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
Object obj = lda.operandStack.pop();*/
lda.executionException = "Call to unknown property";
return false;
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
resolveMultiname(lda, constants, multinameIndex);
Object obj = lda.operandStack.pop();
//do not push anything
//lda.executionException = "Call to unknown property";
return true;
}
@Override

View File

@@ -25,6 +25,7 @@ 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.model.CallPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
@@ -36,20 +37,31 @@ public class CallPropertyIns extends InstructionDefinition {
super(0x46, "callproperty", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
/*int multinameIndex = ins.getParamAsLong(constants, 0).intValue();
int argCount = ins.getParamAsLong(constants, 1).intValue();
List<Object> passArguments = new ArrayList<Object>();
int multinameIndex = ins.operands[0];
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
Object obj = lda.operandStack.pop();*/
lda.executionException = "Call to unknown property";
return false;
//push(result)
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
resolveMultiname(lda, constants, multinameIndex);
Object obj = lda.operandStack.pop();
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Call to unknown property";
return true;
}
@Override

View File

@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
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.model.CallStaticAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
@@ -35,18 +36,29 @@ public class CallStaticIns extends InstructionDefinition {
super(0x44, "callstatic", new int[]{AVM2Code.DAT_METHOD_INDEX, AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
/*int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of method_info
int argCount = ins.getParamAsLong(constants, 1).intValue();
List<Object> passArguments = new ArrayList<Object>();
//int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of method_info
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
Object receiver = lda.operandStack.pop();*/
lda.executionException = "Call to unknown static method";
return false;
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
Object receiver = lda.operandStack.pop();
//push(result)
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Call to unknown static method";
return true;
}
@Override

View File

@@ -25,6 +25,7 @@ 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.model.CallSuperAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
@@ -36,20 +37,31 @@ public class CallSuperIns extends InstructionDefinition {
super(0x45, "callsuper", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
/*int multinameIndex = ins.getParamAsLong(constants, 0).intValue();
int argCount = ins.getParamAsLong(constants, 1).intValue();
List<Object> passArguments = new ArrayList<Object>();
int multinameIndex = ins.operands[0];
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
Object receiver = lda.operandStack.pop();*/
lda.executionException = "Call to unknown super method";
return false;
//push(result)
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
resolveMultiname(lda, constants, multinameIndex);
Object receiver = lda.operandStack.pop();
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Call to unknown super method";
return true;
}
@Override

View File

@@ -36,20 +36,31 @@ public class CallSuperVoidIns extends InstructionDefinition {
super(0x4e, "callsupervoid", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
/*int multinameIndex = ins.getParamAsLong(constants, 0).intValue();
int argCount = ins.getParamAsLong(constants, 1).intValue();
List<Object> passArguments = new ArrayList<Object>();
int multinameIndex = ins.operands[0];
int argCount = ins.getParamAsLong(constants, 1).intValue();
/*List<Object> passArguments = new ArrayList<Object>();
for (int i = argCount - 1; i >= 0; i--) {
passArguments.set(i, lda.operandStack.pop());
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
Object receiver = lda.operandStack.pop();*/
lda.executionException = "Call to unknown super method";
return false;
}*/
for (int i = 0; i < argCount; i++) {
lda.operandStack.pop();
}
//if multiname[multinameIndex] is runtime
//pop(name) pop(ns)
resolveMultiname(lda, constants, multinameIndex);
Object receiver = lda.operandStack.pop();
//do not push anything
//lda.executionException = "Call to unknown super method";
return true;
}
@Override

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.DecLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.SubtractAVM2Item;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -40,7 +41,10 @@ public class DecLocalIIns extends InstructionDefinition {
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
int locRegIndex = ins.getParamAsLong(constants, 0).intValue();
Object obj = lda.localRegisters.get(locRegIndex);
lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) - 1);
if (obj != NotCompileTime.INSTANCE) {
lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) - 1);
}
return true;
}

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.DecLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.SubtractAVM2Item;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -40,7 +41,10 @@ public class DecLocalIns extends InstructionDefinition {
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
int locRegIndex = ins.getParamAsLong(constants, 0).intValue();
Object obj = lda.localRegisters.get(locRegIndex);
lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1);
if (obj != NotCompileTime.INSTANCE) {
lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1);
}
return true;
}

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.IncLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.AddAVM2Item;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -40,7 +41,10 @@ public class IncLocalIIns extends InstructionDefinition {
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
int locRegIndex = ins.getParamAsLong(constants, 0).intValue();
Object obj = lda.localRegisters.get(locRegIndex);
lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) + 1);
if (obj != NotCompileTime.INSTANCE) {
lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) + 1);
}
return true;
}

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.IncLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.AddAVM2Item;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -40,7 +41,10 @@ public class IncLocalIns extends InstructionDefinition {
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
int locRegIndex = ins.getParamAsLong(constants, 0).intValue();
Object obj = lda.localRegisters.get(locRegIndex);
lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1);
if (obj != NotCompileTime.INSTANCE) {
lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1);
}
return true;
}

View File

@@ -42,7 +42,7 @@ public class DeletePropertyIns extends InstructionDefinition {
//pop(name) pop(ns)
Object obj = lda.operandStack.pop();
//push true if removed*/
lda.executionException = "Cannot remove property";
//lda.executionException = "Cannot remove property";
return false;
}

View File

@@ -25,6 +25,7 @@ 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.model.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -35,12 +36,19 @@ public class FindPropertyIns extends InstructionDefinition {
super(0x5e, "findproperty", new int[]{AVM2Code.DAT_MULTINAME_INDEX}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
//int multiIndex = ins.getParamAsLong(constants, 0).intValue();
int multinameIndex = ins.operands[0];
//if is runtime
//pop(name), pop(ns)
lda.executionException = "Cannot find property";
resolveMultiname(lda, constants, multinameIndex);
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Cannot find property";
return false;
}

View File

@@ -25,6 +25,7 @@ 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.model.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -35,13 +36,20 @@ public class FindPropertyStrictIns extends InstructionDefinition {
super(0x5d, "findpropstrict", new int[]{AVM2Code.DAT_MULTINAME_INDEX}, true);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
//int multiIndex = ins.getParamAsLong(constants, 0).intValue();
int multinameIndex = ins.operands[0];
//if is runtime
//pop(name), pop(ns)
lda.executionException = "Cannot find property";
return false;
resolveMultiname(lda, constants, multinameIndex);
lda.operandStack.push(NotCompileTime.INSTANCE);
//lda.executionException = "Cannot find property";
return true;
}
@Override

View File

@@ -32,6 +32,11 @@ public class PushScopeIns extends InstructionDefinition {
super(0x30, "pushscope", new int[]{}, false);
}
@Override
public boolean isNotCompileTimeSupported() {
return true;
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
lda.scopeStack.push(lda.operandStack.pop());

View File

@@ -25,6 +25,7 @@ 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.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.AsTypeAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -40,8 +41,9 @@ public class AsTypeIns extends InstructionDefinition {
//Long typeIndex = ins.getParamAsLong(constants, 0);
Object obj = lda.operandStack.pop();
//if multiname[typeIndex]==obj
lda.operandStack.push(obj);
//lda.operandStack.push(obj);
//else push null
lda.operandStack.push(NotCompileTime.INSTANCE);
return true;
}

View File

@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
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.model.operations.AsTypeAVM2Item;
import com.jpexs.decompiler.flash.ecma.NotCompileTime;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
@@ -38,8 +39,9 @@ public class AsTypeLateIns extends InstructionDefinition {
//Object objClass = lda.operandStack.pop();
Object obj = lda.operandStack.pop();
//if obj.class=objClass
lda.operandStack.push(obj);
//lda.operandStack.push(obj);
//else push null
lda.operandStack.push(NotCompileTime.INSTANCE);
return true;
}

View File

@@ -17,12 +17,11 @@
package com.jpexs.decompiler.flash.abc.avm2.model;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.LocalData;
import java.util.ArrayList;

View File

@@ -17,9 +17,6 @@
package com.jpexs.decompiler.flash.action.deobfuscation;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
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;
@@ -78,7 +75,8 @@ import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf;
import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
import com.jpexs.decompiler.flash.action.swf6.ActionStringGreater;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
import com.jpexs.decompiler.flash.helpers.collections.FixItemCounterStack;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.model.FalseItem;
import com.jpexs.decompiler.graph.model.PushItem;
@@ -95,7 +93,7 @@ import java.util.Stack;
*
* @author JPEXS
*/
public class ActionDeobfuscator implements SWFDecompilerListener {
public class ActionDeobfuscator extends SWFDecompilerAdapter {
private final int executionLimit = 5000;
@@ -665,27 +663,6 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
}
}
@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) {
}
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
}
class ExecutionResult {
public ActionItem item;

View File

@@ -14,28 +14,19 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2;
package com.jpexs.decompiler.flash.ecma;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
import java.io.Serializable;
public class UnknownJumpException extends RuntimeException {
public class NotCompileTime implements Serializable {
public TranslateStack stack;
public static NotCompileTime INSTANCE = new NotCompileTime();
public int ip;
public List<GraphTargetItem> output;
public UnknownJumpException(TranslateStack stack, int ip, List<GraphTargetItem> output) {
this.stack = stack;
this.ip = ip;
this.output = output;
private NotCompileTime() {
}
@Override
public String toString() {
return "Unknown jump to " + ip;
return "not_compile_time";
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.helpers;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.graph.GraphTargetItem;
import java.util.List;
/**
*
* @author JPEXS
*/
public class SWFDecompilerAdapter implements SWFDecompilerListener {
@Override
public byte[] proxyFileCatched(byte[] data) {
return null;
}
@Override
public void swfParsed(SWF swf) {
}
@Override
public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException {
}
@Override
public void actionTreeCreated(List<GraphTargetItem> tree, SWF swf) throws InterruptedException {
}
@Override
public void abcParsed(ABC abc, SWF swf) {
}
@Override
public void methodBodyParsed(MethodBody body, SWF swf) {
}
/**
* This method is only called when deobfuscation is enabled and new
* deobfuscation mode is selected
*
* @param path
* @param classIndex
* @param isStatic
* @param scriptIndex
* @param abc
* @param trait
* @param methodInfo
* @param body
* @throws InterruptedException
*/
@Override
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
}
}

View File

@@ -42,6 +42,19 @@ public interface SWFDecompilerListener {
void methodBodyParsed(MethodBody body, SWF swf);
// this method is only called when deobfuscation is enabled and new deobfuscation mode is selected
/**
* this method is only called when deobfuscation is enabled and new
* deobfuscation mode is selected
*
* @param path
* @param classIndex
* @param isStatic
* @param scriptIndex
* @param abc
* @param trait
* @param methodInfo
* @param body
* @throws InterruptedException
*/
void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException;
}

View File

@@ -14,7 +14,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.action.deobfuscation;
package com.jpexs.decompiler.flash.helpers.collections;
import java.util.Stack;