mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-27 14:31:16 +00:00
New AS3 Deobfuscation method similar to that for AS1/2
This commit is contained in:
@@ -1150,7 +1150,7 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
int ret = posCache.indexOf(address);
|
||||
if (ret == -1) {
|
||||
throw new ConvertException("Bad jump try conver ofs" + Helper.formatAddress(address) + " ", -1);
|
||||
throw new ConvertException("Invalid jump to ofs" + Helper.formatAddress(address), -1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1843,7 +1843,20 @@ public class AVM2Code implements Cloneable {
|
||||
invalidateCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pos
|
||||
* @param instruction
|
||||
*/
|
||||
public void insertInstruction(int pos, AVM2Instruction instruction) {
|
||||
insertInstruction(pos, instruction, true, false);
|
||||
}
|
||||
|
||||
public void replaceInstruction(int idx, AVM2Instruction ins, MethodBody body) {
|
||||
insertInstruction(idx, ins, true, true);
|
||||
removeInstruction(idx + 1, body);
|
||||
}
|
||||
|
||||
public void insertInstruction(int pos, AVM2Instruction instruction, boolean preRefsToThis, boolean postRefsToThis) {
|
||||
if (pos < 0) {
|
||||
pos = 0;
|
||||
}
|
||||
@@ -1857,31 +1870,43 @@ public class AVM2Code implements Cloneable {
|
||||
instruction.offset = code.get(pos).offset;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pos; i++) {
|
||||
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
|
||||
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
|
||||
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
|
||||
if (target >= instruction.offset) {
|
||||
code.get(i).operands[j] += byteCount;
|
||||
{
|
||||
for (int i = 0; i < pos; i++) {
|
||||
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
|
||||
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
|
||||
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
|
||||
if (target > instruction.offset) {
|
||||
code.get(i).operands[j] += byteCount;
|
||||
}
|
||||
if (target == instruction.offset && !preRefsToThis) {
|
||||
code.get(i).operands[j] += byteCount;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = pos; i < code.size(); i++) {
|
||||
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
|
||||
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
|
||||
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
|
||||
if (target < instruction.offset) {
|
||||
code.get(i).operands[j] -= byteCount;
|
||||
{
|
||||
for (int i = pos; i < code.size(); i++) {
|
||||
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
|
||||
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
|
||||
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
|
||||
if (target < instruction.offset) {
|
||||
code.get(i).operands[j] -= byteCount;
|
||||
}
|
||||
if (target == instruction.offset && postRefsToThis) {
|
||||
code.get(i).operands[j] -= byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = pos + 1; i < code.size(); i++) {
|
||||
for (int i = pos; i < code.size(); i++) {
|
||||
code.get(i).offset += byteCount;
|
||||
}
|
||||
code.add(pos, instruction);
|
||||
invalidateCache();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -1,435 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 Deobfuscator - FIXME!!! Not ready yet!
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Deobfuscator extends AVM2DeobfuscatorSimple {
|
||||
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions, SWF swf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deobfuscate(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
removeZeroJumps(body.getCode(), body);
|
||||
}
|
||||
|
||||
private boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
|
||||
AVM2Code code = body.getCode();
|
||||
if (code.code.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
System.err.println("=============================================");
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
System.err.println("Execute from " + i);
|
||||
executeActions(classIndex, isStatic, body, scriptIndex, abc, code, i, code.code.size() - 1, result);
|
||||
|
||||
if (result.idx != -1) {
|
||||
int newIstructionCount = 1; // jump
|
||||
if (!result.stack.isEmpty()) {
|
||||
newIstructionCount++;
|
||||
}
|
||||
newIstructionCount += 2 * result.variables.size();
|
||||
|
||||
if (newIstructionCount * 2 < result.instructionsProcessed) {
|
||||
AVM2Instruction target = code.code.get(result.idx);
|
||||
AVM2Instruction prevAction = code.code.get(i);
|
||||
|
||||
for (int variableName : result.variables.keySet()) {
|
||||
Object value = result.variables.get(variableName);
|
||||
/*ActionPush push = new ActionPush(variableName);
|
||||
push.values.add(value);*/
|
||||
AVM2Instruction push = makePush(value, cpool);
|
||||
|
||||
code.insertInstruction(i++, push);
|
||||
push.offset = prevAction.offset;
|
||||
|
||||
code.insertInstruction(i++, push);
|
||||
prevAction = push;
|
||||
|
||||
/*if (result.defines.contains(variableName)) {
|
||||
//ActionDefineLocal defineLocal = new ActionDefineLocal();
|
||||
AVM2Instruction defineLocal = new AVM2Instruction(prevAction.offset, new SetLocalIns(), new int[]{});
|
||||
defineLocal.setAddress(prevAction.getAddress());
|
||||
code.addAction(i++, defineLocal);
|
||||
prevAction = defineLocal;
|
||||
} else {
|
||||
ActionSetVariable setVariable = new ActionSetVariable();
|
||||
setVariable.setAddress(prevAction.getAddress());
|
||||
code.addAction(i++, setVariable);
|
||||
prevAction = setVariable;
|
||||
}*/
|
||||
AVM2Instruction setVariable = new AVM2Instruction(prevAction.offset, new SetLocalIns(), new int[]{});
|
||||
code.insertInstruction(i++, setVariable);
|
||||
prevAction = setVariable;
|
||||
}
|
||||
|
||||
if (!result.stack.isEmpty()) {
|
||||
//ActionPush push = new ActionPush(0);
|
||||
//push.values.clear();
|
||||
long ofs = prevAction.offset;
|
||||
for (GraphTargetItem graphTargetItem : result.stack) {
|
||||
//DirectValueActionItem dv = (DirectValueActionItem) graphTargetItem;
|
||||
//push.values.add(dv.value);
|
||||
AVM2Instruction push = makePush(cpool, graphTargetItem);
|
||||
push.offset = ofs;
|
||||
code.insertInstruction(i++, push);
|
||||
ofs += push.getBytes().length;
|
||||
prevAction = push;
|
||||
}
|
||||
}
|
||||
|
||||
//ctionJump jump = new ActionJump(0);
|
||||
AVM2Instruction jump = new AVM2Instruction(prevAction.offset, new JumpIns(), new int[]{0});
|
||||
//jump.setAddress(prevAction.getAddress());
|
||||
jump.operands[0] = (int) (target.offset - jump.offset - jump.getBytes().length);
|
||||
code.insertInstruction(i++, jump);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) {
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
localData.isStatic = isStatic;
|
||||
localData.classIndex = classIndex;
|
||||
localData.localRegs = new HashMap<>();
|
||||
localData.scopeStack = new ScopeStack();
|
||||
localData.constants = cpool;
|
||||
localData.methodInfo = abc.method_info;
|
||||
localData.methodBody = body;
|
||||
localData.abc = abc;
|
||||
localData.localRegNames = new HashMap<>();
|
||||
localData.fullyQualifiedNames = new ArrayList<>();
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
localData.finallyJumps = new HashMap<>();
|
||||
localData.ignoredSwitches = new HashMap<>();
|
||||
localData.ignoredSwitches2 = new ArrayList<>();
|
||||
localData.scriptIndex = scriptIndex;
|
||||
localData.localRegAssignmentIps = new HashMap<>();
|
||||
localData.ip = 0;
|
||||
localData.refs = new HashMap<>();
|
||||
localData.code = body.getCode();
|
||||
return localData;
|
||||
}
|
||||
|
||||
private void executeActions(int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
|
||||
localData.localRegs.put(0, new NullAVM2Item(null));//this
|
||||
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
|
||||
int instructionsProcessed = 0;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (idx > endIdx) {
|
||||
break;
|
||||
}
|
||||
|
||||
AVM2Instruction action = code.code.get(idx);
|
||||
instructionsProcessed++;
|
||||
|
||||
if (instructionsProcessed > executionLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*if (action instanceof ActionDefineLocal) {
|
||||
GraphTargetItem top = stack.pop();
|
||||
String variableName = stack.peek().getResult().toString();
|
||||
result.defines.add(variableName);
|
||||
stack.push(top);
|
||||
}*/
|
||||
if (action.definition instanceof GetLocalTypeIns) {
|
||||
int regId = ((GetLocalTypeIns) action.definition).getRegisterId(action);//stack.peek().getResult().toString();
|
||||
if (!localData.localRegs.containsKey(regId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*if (action instanceof ActionCallFunction) {
|
||||
String functionName = stack.pop().getResult().toString();
|
||||
long numArgs = EcmaScript.toUint32(stack.pop().getResult());
|
||||
if (numArgs == 0) {
|
||||
if (fakeFunctions != null && fakeFunctions.containsKey(functionName)) {
|
||||
stack.push(new DirectValueActionItem(fakeFunctions.get(functionName)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
}*/
|
||||
System.err.println("Translating " + action);
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
Class allowedDefs[] = new Class[]{
|
||||
PushByteIns.class,
|
||||
PushShortIns.class,
|
||||
PushIntIns.class,
|
||||
PushDoubleIns.class,
|
||||
PushStringIns.class,
|
||||
PushNullIns.class,
|
||||
PushUndefinedIns.class,
|
||||
PushFalseIns.class,
|
||||
PushTrueIns.class,
|
||||
DupIns.class,
|
||||
SwapIns.class,
|
||||
AddIns.class,
|
||||
AddIIns.class,
|
||||
SubtractIns.class,
|
||||
SubtractIIns.class,
|
||||
ModuloIns.class,
|
||||
MultiplyIns.class,
|
||||
BitAndIns.class,
|
||||
BitXorIns.class,
|
||||
BitOrIns.class,
|
||||
LShiftIns.class,
|
||||
RShiftIns.class,
|
||||
URShiftIns.class,
|
||||
EqualsIns.class,
|
||||
NotIns.class,
|
||||
IfTypeIns.class,
|
||||
JumpIns.class,
|
||||
IncrementIns.class,
|
||||
IncrementIIns.class,
|
||||
DecrementIns.class,
|
||||
DecrementIIns.class,
|
||||
SetLocalTypeIns.class,
|
||||
GetLocalTypeIns.class,
|
||||
GreaterEqualsIns.class,
|
||||
GreaterThanIns.class,
|
||||
LessThanIns.class,
|
||||
LessEqualsIns.class,
|
||||
StrictEqualsIns.class,
|
||||
IfTypeIns.class,
|
||||
ReturnVoidIns.class,
|
||||
ReturnValueIns.class,
|
||||
NewFunctionIns.class,
|
||||
PopIns.class,
|
||||
PushScopeIns.class
|
||||
};
|
||||
|
||||
InstructionDefinition def = action.definition;
|
||||
|
||||
boolean ok = false;
|
||||
for (Class<?> s : allowedDefs) {
|
||||
if (s.isAssignableFrom(def.getClass())) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
System.err.println("Broken");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*for (String variable : localData.variables.keySet()) {
|
||||
System.out.println(Helper.byteArrToString(variable.getBytes()));
|
||||
}*/
|
||||
idx++;
|
||||
|
||||
if (action.definition instanceof JumpIns) {
|
||||
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (action.definition instanceof IfTypeIns) {
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("If target not found: " + address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (/*localData.variables.size() == 1 && */stack.allItemsFixed()) {
|
||||
result.idx = idx == code.code.size() ? idx - 1 : idx;
|
||||
result.instructionsProcessed = instructionsProcessed;
|
||||
result.variables.clear();
|
||||
for (int variableName : localData.localRegs.keySet()) {
|
||||
Object value = localData.localRegs.get(variableName).getResult();
|
||||
result.variables.put(variableName, value);
|
||||
}
|
||||
result.stack.clear();
|
||||
result.stack.addAll(stack);
|
||||
}
|
||||
|
||||
if (action.definition instanceof ReturnValueIns) {
|
||||
if (output.size() > 0) {
|
||||
ReturnValueAVM2Item ret = (ReturnValueAVM2Item) output.get(output.size() - 1);
|
||||
result.resultValue = ret.value.getResult();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (action.definition instanceof ReturnVoidIns) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
|
||||
//ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/*private Map<String, Object> getFakeFunctionResults(ActionList actions) {
|
||||
|
||||
Map<String, Object> results = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action action = actions.get(i);
|
||||
if (action instanceof ActionDefineFunction) {
|
||||
ActionDefineFunction def = (ActionDefineFunction) action;
|
||||
if (def.paramNames.isEmpty()) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
List<Action> lastActions = actions.getContainerLastActions(action);
|
||||
int lastActionIdx = actions.indexOf(lastActions.get(0));
|
||||
executeActions(actions, i + 1, lastActionIdx, null, result, null);
|
||||
if (result.resultValue != null) {
|
||||
results.put(def.functionName, result.resultValue);
|
||||
for (int j = i; j <= lastActionIdx; j++) {
|
||||
actions.removeAction(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] proxyFileCatched(byte[] data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swfParsed(SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abcParsed(ABC abc, SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodBodyParsed(MethodBody body, SWF swf) {
|
||||
}*/
|
||||
class ExecutionResult {
|
||||
|
||||
public int idx = -1;
|
||||
|
||||
public int instructionsProcessed = -1;
|
||||
|
||||
//public ActionConstantPool constantPool;
|
||||
public Map<Integer, Object> variables = new HashMap<>();
|
||||
|
||||
//public Set<String> defines = new HashSet<>();
|
||||
public TranslateStack stack = new TranslateStack("?");
|
||||
|
||||
public ScopeStack scopeStack = new ScopeStack();
|
||||
|
||||
public Object resultValue;
|
||||
}
|
||||
}
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.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.graph.AVM2GraphSource;
|
||||
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.IfTypeIns;
|
||||
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.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.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.EmptyStackException;
|
||||
import java.util.HashMap;
|
||||
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 AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
|
||||
|
||||
//private final int executionLimit = 30000;
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions, SWF swf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
|
||||
body.getCode().markMappedOffsets();
|
||||
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
Map<Integer, GraphTargetItem> singleRegisters = getSingleUseRegisters(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
replaceSingleUseRegisters(singleRegisters, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
super.deobfuscate(path, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
}
|
||||
|
||||
private void replaceSingleUseRegisters(Map<Integer, GraphTargetItem> singleRegisters, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
|
||||
AVM2Code code = body.getCode();
|
||||
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
AVM2Instruction ins = code.code.get(i);
|
||||
if (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, new DeobfuscatePopIns(), new int[]{}), body);
|
||||
}
|
||||
}
|
||||
if (ins.definition instanceof GetLocalTypeIns) {
|
||||
GetLocalTypeIns glt = (GetLocalTypeIns) ins.definition;
|
||||
int regId = glt.getRegisterId(ins);
|
||||
if (singleRegisters.containsKey(regId)) {
|
||||
code.replaceInstruction(i, makePush(singleRegisters.get(regId).getResult(), cpool), body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Integer, GraphTargetItem> getSingleUseRegisters(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
|
||||
AVM2Code code = body.getCode();
|
||||
Map<Integer, GraphTargetItem> ret = new HashMap<>();
|
||||
|
||||
if (code.code.isEmpty()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ExecutionResult res = new ExecutionResult();
|
||||
visitCode(new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, res);
|
||||
for (int reg : res.assignCount.keySet()) {
|
||||
if (res.assignCount.get(reg) == 1) {
|
||||
ret.put(reg, res.lastAssigned.get(reg));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void visitCode(Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
|
||||
localData.localRegs.put(0, new NullAVM2Item(null));//this
|
||||
int instructionsProcessed = 0;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (idx > endIdx) {
|
||||
break;
|
||||
}
|
||||
if (visited.contains(idx)) {
|
||||
break;
|
||||
}
|
||||
visited.add(idx);
|
||||
|
||||
AVM2Instruction action = code.code.get(idx);
|
||||
instructionsProcessed++;
|
||||
|
||||
|
||||
/*if (action.definition instanceof GetLocalTypeIns) {
|
||||
int regId = ((GetLocalTypeIns) action.definition).getRegisterId(action);//stack.peek().getResult().toString();
|
||||
if (!localData.localRegs.containsKey(regId)) {
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
InstructionDefinition def = action.definition;
|
||||
|
||||
if (def instanceof SetLocalTypeIns) {
|
||||
SetLocalTypeIns slt = (SetLocalTypeIns) def;
|
||||
int regId = slt.getRegisterId(action);
|
||||
if (!result.assignCount.containsKey(regId)) {
|
||||
result.assignCount.put(regId, 0);
|
||||
}
|
||||
|
||||
result.assignCount.put(regId, result.assignCount.get(regId) + 1);
|
||||
|
||||
GraphTargetItem regVal = localData.localRegs.get(regId);
|
||||
if (regVal == null || !regVal.getNotCoerced().isCompileTime()) {
|
||||
result.assignCount.put(regId, Integer.MAX_VALUE);
|
||||
} else {
|
||||
result.lastAssigned.put(regId, regVal.getNotCoerced());
|
||||
}
|
||||
//assignCount
|
||||
}
|
||||
|
||||
idx++;
|
||||
|
||||
if (action.definition instanceof JumpIns) {
|
||||
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (action.isBranch()) {
|
||||
List<Integer> branches = action.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);
|
||||
}
|
||||
}
|
||||
/*if (action.definition instanceof IfTypeIns) {
|
||||
long address = action.offset + action.getBytes().length + action.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 (action.definition instanceof ReturnValueIns) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (action.definition instanceof ThrowIns) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (action.definition instanceof ReturnVoidIns) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
class ExecutionResult {
|
||||
|
||||
public Map<Integer, Integer> assignCount = new HashMap<>();
|
||||
public Map<Integer, GraphTargetItem> lastAssigned = new HashMap<>();
|
||||
}
|
||||
}
|
||||
+89
-42
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.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;
|
||||
@@ -38,6 +39,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.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;
|
||||
@@ -48,6 +50,7 @@ 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;
|
||||
@@ -63,12 +66,15 @@ 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.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.PopItem;
|
||||
import com.jpexs.decompiler.graph.model.TrueItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -145,12 +151,10 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
if (code.code.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
System.err.println("=====================================================");
|
||||
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
System.err.println("Execute from " + i);
|
||||
executeActions(code, i, code.code.size() - 1, result);
|
||||
executeActions(classIndex, isStatic, body, scriptIndex, abc, code, i, code.code.size() - 1, result);
|
||||
|
||||
if (result.idx != -1) {
|
||||
int newIstructionCount = 1; // jump
|
||||
@@ -158,44 +162,59 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
newIstructionCount += result.stack.size();
|
||||
}
|
||||
|
||||
if (newIstructionCount < result.instructionsProcessed) {
|
||||
if (newIstructionCount < result.instructionsProcessed) //if (result.isIf)
|
||||
{
|
||||
AVM2Instruction target = code.code.get(result.idx);
|
||||
AVM2Instruction prevAction = code.code.get(i);
|
||||
int idelta = 0;
|
||||
|
||||
if (result.stack.isEmpty() && prevAction.definition instanceof JumpIns) {
|
||||
prevAction.operands[0] = ((int) (target.getOffset() - prevAction.getOffset() - prevAction.getBytes().length));
|
||||
prevAction.operands[0] = ((int) (target.offset - prevAction.offset - prevAction.getBytes().length));
|
||||
} else {
|
||||
if (!result.stack.isEmpty()) {
|
||||
for (GraphTargetItem graphTargetItem : result.stack) {
|
||||
AVM2Instruction ins = makePush(cpool, graphTargetItem);
|
||||
if (ins != null) {
|
||||
code.insertInstruction(i++, ins);
|
||||
if (graphTargetItem instanceof PopItem) {
|
||||
continue;
|
||||
}
|
||||
AVM2Instruction ins = makePush(graphTargetItem.getResult(), cpool);
|
||||
if (ins != null) {
|
||||
code.insertInstruction(i + (idelta++), ins);
|
||||
//prevAction = ins;
|
||||
} else {
|
||||
throw new TranslateException("Cannot push: " + graphTargetItem);
|
||||
}
|
||||
prevAction = ins;
|
||||
//DirectValueActionItem dv = (DirectValueActionItem) graphTargetItem;
|
||||
//push.values.add(dv.value);
|
||||
}
|
||||
//push.setAddress(prevAction.getAddress());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
AVM2Instruction jump = new AVM2Instruction(0, new JumpIns(), new int[]{0});
|
||||
jump.offset = prevAction.offset;
|
||||
jump.operands[0] = ((int) (target.offset - jump.offset - jump.getBytes().length));
|
||||
code.insertInstruction(i++, jump);
|
||||
}
|
||||
code.insertInstruction(i + (idelta++), jump);
|
||||
|
||||
AVM2Instruction nextAction = code.code.size() > i ? code.code.get(i) : null;
|
||||
jump.operands[0] = ((int) (target.offset - jump.offset - jump.getBytes().length));
|
||||
|
||||
}
|
||||
|
||||
removeUnreachableActions(code, cpool, trait, minfo, body);
|
||||
removeZeroJumps(code, body);
|
||||
|
||||
if (nextAction != null) {
|
||||
int nextIdx = code.code.indexOf(nextAction);
|
||||
if (nextIdx < i) {
|
||||
i = nextIdx;
|
||||
}
|
||||
}
|
||||
i = -1;
|
||||
/*if (nextAction != null) {
|
||||
long mapped = nextAction.mappedOffset;
|
||||
int nextIdx = -1;
|
||||
for (int p = 0; p < code.code.size(); p++) {
|
||||
if (code.code.get(p).mappedOffset == mapped) {
|
||||
nextIdx = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextIdx == -1) {
|
||||
//?
|
||||
break;
|
||||
} else {
|
||||
i = nextIdx - 1;
|
||||
}
|
||||
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,9 +239,33 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void executeActions(AVM2Code code, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
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<>();
|
||||
localData.scopeStack = new ScopeStack(true);
|
||||
localData.constants = cpool;
|
||||
localData.methodInfo = abc.method_info;
|
||||
localData.methodBody = body;
|
||||
localData.abc = abc;
|
||||
localData.localRegNames = new HashMap<>();
|
||||
localData.fullyQualifiedNames = new ArrayList<>();
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
localData.finallyJumps = new HashMap<>();
|
||||
localData.ignoredSwitches = new HashMap<>();
|
||||
localData.ignoredSwitches2 = new ArrayList<>();
|
||||
localData.scriptIndex = scriptIndex;
|
||||
localData.localRegAssignmentIps = new HashMap<>();
|
||||
localData.ip = 0;
|
||||
localData.refs = new HashMap<>();
|
||||
localData.code = body.getCode();
|
||||
return localData;
|
||||
}
|
||||
|
||||
private void executeActions(int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
|
||||
|
||||
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
|
||||
int instructionsProcessed = 0;
|
||||
@@ -238,12 +281,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
}
|
||||
|
||||
AVM2Instruction action = code.code.get(idx);
|
||||
|
||||
/*System.out.print(action.getASMSource(actions, new ArrayList<Long>(), ScriptExportMode.PCODE));
|
||||
for (int j = 0; j < stack.size(); j++) {
|
||||
System.out.print(" '" + stack.get(j).getResult() + "'");
|
||||
}
|
||||
System.out.println();*/
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
InstructionDefinition def = action.definition;
|
||||
|
||||
Class allowedDefs[] = new Class[]{
|
||||
@@ -286,28 +324,34 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
|
||||
idx++;
|
||||
|
||||
//boolean ifed = false;
|
||||
if (def instanceof JumpIns) {
|
||||
//ActionJump jump = (ActionJump) action;
|
||||
long address = action.getOffset() + action.getBytes().length + action.operands[0];
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);
|
||||
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (def instanceof IfTypeIns) {
|
||||
} else if (def instanceof IfTypeIns) {
|
||||
//ActionIf aif = (ActionIf) action;
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
GraphTargetItem top = stack.pop();
|
||||
Object res = top.getResult();
|
||||
if (EcmaScript.toBoolean(res)) {
|
||||
long address = action.offset + action.getBytes().length + action.operands[0];
|
||||
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("If target not found: " + address);
|
||||
}
|
||||
//ifed = true;
|
||||
} else {
|
||||
//action.definition = new DeobfuscatePopIns();
|
||||
code.replaceInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), body);
|
||||
idx++;
|
||||
}
|
||||
} else {
|
||||
idx++;
|
||||
}
|
||||
|
||||
instructionsProcessed++;
|
||||
@@ -318,8 +362,12 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
result.stack.clear();
|
||||
result.stack.addAll(stack);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
|
||||
//result.idx = -1;
|
||||
//result.isIf = false;
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +389,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|
||||
}
|
||||
|
||||
public void deobfuscate(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
|
||||
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
|
||||
removeZeroJumps(body.getCode(), body);
|
||||
@@ -355,6 +403,5 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|
||||
public TranslateStack stack = new TranslateStack("?");
|
||||
|
||||
public Object resultValue;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -39,6 +39,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.NotCompileTimeItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.model.PopItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
@@ -58,7 +59,9 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S
|
||||
} else {
|
||||
localRegs.put(regId, value);
|
||||
}*/
|
||||
localRegs.put(regId, value);
|
||||
if (!(value instanceof PopItem)) {
|
||||
localRegs.put(regId, value);
|
||||
}
|
||||
if (!regAssignCount.containsKey(regId)) {
|
||||
regAssignCount.put(regId, 0);
|
||||
}
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ public class LocalRegAVM2Item extends AVM2Item {
|
||||
|
||||
@Override
|
||||
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
|
||||
return isCT;
|
||||
return false; //isCT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import java.util.Stack;
|
||||
/**
|
||||
* This class is a scanner generated by
|
||||
* <a href="http://www.jflex.de/">JFlex</a> 1.6.0
|
||||
* from the specification file <tt>C:/Dropbox/Programovani/JavaSE/FFDec/libsrc/ffdec_lib/lexers/actionscript3_script.flex</tt>
|
||||
* from the specification file <tt>D:/Dropbox/Programovani/JavaSE/FFDec/libsrc/ffdec_lib/lexers/actionscript3_script.flex</tt>
|
||||
*/
|
||||
public final class ActionScriptLexer {
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Deobfuscator;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2DeobfuscatorRegisters;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2DeobfuscatorSimple;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
@@ -202,6 +203,7 @@ public final class MethodBody implements Cloneable {
|
||||
if (exportMode != ScriptExportMode.AS) {
|
||||
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
|
||||
} else {
|
||||
//if (!path.contains("@")) {
|
||||
if (!Configuration.decompile.get()) {
|
||||
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
|
||||
return;
|
||||
@@ -245,6 +247,7 @@ public final class MethodBody implements Cloneable {
|
||||
if (exportMode != ScriptExportMode.AS) {
|
||||
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
|
||||
} else {
|
||||
//if (!path.contains("@")) {
|
||||
if (!Configuration.decompile.get()) {
|
||||
//writer.startMethod(this.method_info);
|
||||
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
|
||||
@@ -276,12 +279,19 @@ public final class MethodBody implements Cloneable {
|
||||
|
||||
public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, AVM2ConstantPool constants, List<MethodInfo> method_info, ScopeStack scopeStack, boolean isStaticInitializer, List<String> fullyQualifiedNames, Traits initTraits) throws InterruptedException {
|
||||
MethodBody b = clone();
|
||||
AVM2Code deobfuscated = b.getCode();
|
||||
deobfuscated.markMappedOffsets();
|
||||
//deobfuscated.inlineJumpExit();
|
||||
b.getCode().markMappedOffsets();
|
||||
|
||||
if (Configuration.autoDeobfuscate.get()) {
|
||||
AVM2Deobfuscator deo = new AVM2Deobfuscator();
|
||||
deo.deobfuscate(classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
|
||||
if (Configuration.deobfuscationMode.get() == 0) {
|
||||
try {
|
||||
b.getCode().removeTraps(constants, trait, method_info.get(this.method_info), b, abc, scriptIndex, classIndex, isStatic, path);
|
||||
} catch (Throwable ex) {
|
||||
logger.log(Level.SEVERE, "Error during old deobfuscation: " + path, ex);
|
||||
}
|
||||
} else {
|
||||
new AVM2DeobfuscatorSimple().deobfuscate(path, classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
|
||||
new AVM2DeobfuscatorRegisters().deobfuscate(path, classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
|
||||
Reference in New Issue
Block a user