Decompiler improvement, compiler start
This commit is contained in:
parent
f75c7e0534
commit
d9bfbf2bc5
@ -99,6 +99,10 @@ public class FlashDecompiler {
|
||||
case Push:
|
||||
i = parseActionPush(data, i, tag);
|
||||
break;
|
||||
case InitArray:
|
||||
tag.getActions().add(new ActionInitArray());
|
||||
i++;
|
||||
break;
|
||||
case InitObject:
|
||||
tag.getActions().add(new ActionInitObject());
|
||||
i++;
|
||||
@ -225,6 +229,7 @@ public class FlashDecompiler {
|
||||
int bytes_len = bytesToIntRev(Arrays.copyOfRange(data, i, i+2));
|
||||
i += 2;
|
||||
int count = bytesToIntRev(Arrays.copyOfRange(data, i, i+2));
|
||||
log.info("ActionPoolSize: {}", count);
|
||||
i += 2;
|
||||
int u = 1;
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
@ -3,6 +3,7 @@ package com.alterdekim.flash.decompiler;
|
||||
import com.alterdekim.flash.decompiler.tag.DoAction;
|
||||
import com.alterdekim.flash.decompiler.tag.TagType;
|
||||
import com.alterdekim.flash.decompiler.translator.Flash2Java;
|
||||
import com.alterdekim.flash.decompiler.translator.Java2Flash;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -12,7 +13,7 @@ import java.io.File;
|
||||
public class Main {
|
||||
public static void main(String[] args) throws Exception {
|
||||
FlashDecompiler decompiler = new FlashDecompiler();
|
||||
ShockwaveFile file = decompiler.loadFromFile(new File("D:\\Documents\\FlashProjects\\Untitled-2.swf")); // D:\Documents\rtmpSpring\static\swf\cache\rus\base[17].swf
|
||||
ShockwaveFile file = decompiler.loadFromFile(new File("D:\\Documents\\rtmpSpring\\static\\swf\\cache\\rus\\catalogs[18].swf")); //
|
||||
|
||||
DoAction da = (DoAction) file.getTags()
|
||||
.stream()
|
||||
@ -23,7 +24,7 @@ public class Main {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
File out = new File("dec.json");
|
||||
if( out.exists() ) out.delete();
|
||||
objectMapper.writeValue(out, new Flash2Java(da).convert());
|
||||
|
||||
//objectMapper.writeValue(out, new Flash2Java(da).convert());
|
||||
new Java2Flash().convert(new Flash2Java(da).convert());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.alterdekim.flash.decompiler.action;
|
||||
|
||||
|
||||
import com.alterdekim.flash.decompiler.util.ActionField;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
public class ActionInitArray extends ByteCodeAction {
|
||||
@Override
|
||||
public ActionField getType() {
|
||||
return ActionField.InitArray;
|
||||
}
|
||||
}
|
@ -14,10 +14,11 @@ public enum ActionPushType {
|
||||
|
||||
// these types are internal (used for decompiler's purposes)
|
||||
// they are not exist
|
||||
|
||||
INIT_OBJECT(-1),
|
||||
GET_VARIABLE(-2),
|
||||
GET_MEMBER(-3);
|
||||
GET_MEMBER(-3),
|
||||
INIT_ARRAY(-4),
|
||||
CONSTANT_POOL(-5);
|
||||
|
||||
public final int type;
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.alterdekim.flash.decompiler.item.internal;
|
||||
|
||||
import com.alterdekim.flash.decompiler.item.ActionPushType;
|
||||
import com.alterdekim.flash.decompiler.item.ByteCodeItem;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public class ConstantPoolItem extends ByteCodeItem {
|
||||
|
||||
private ArrayList<String> val;
|
||||
|
||||
@Override
|
||||
public ActionPushType getType() {
|
||||
return ActionPushType.CONSTANT_POOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.val;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.alterdekim.flash.decompiler.item.internal;
|
||||
|
||||
import com.alterdekim.flash.decompiler.item.ActionPushType;
|
||||
import com.alterdekim.flash.decompiler.item.ByteCodeItem;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public class InitArrayItem extends ByteCodeItem {
|
||||
private HashMap<String, Object> val;
|
||||
|
||||
@Override
|
||||
public ActionPushType getType() {
|
||||
return ActionPushType.INIT_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.val;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import com.alterdekim.flash.decompiler.item.*;
|
||||
import com.alterdekim.flash.decompiler.action.ByteCodeAction;
|
||||
import com.alterdekim.flash.decompiler.item.internal.GetMemberItem;
|
||||
import com.alterdekim.flash.decompiler.item.internal.GetVariableItem;
|
||||
import com.alterdekim.flash.decompiler.item.internal.InitArrayItem;
|
||||
import com.alterdekim.flash.decompiler.item.internal.InitObjectItem;
|
||||
import com.alterdekim.flash.decompiler.tag.DoAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -16,7 +17,7 @@ public class Flash2Java {
|
||||
|
||||
private final List<String> pool;
|
||||
private final List<ByteCodeAction> actions;
|
||||
private final Stack<ByteCodeItem> stack; // ByteCodeAction
|
||||
private final Stack<ByteCodeItem> stack;
|
||||
private final Map<String, Object> vars;
|
||||
|
||||
public Flash2Java(DoAction doAction) {
|
||||
@ -27,50 +28,48 @@ public class Flash2Java {
|
||||
}
|
||||
|
||||
public Map<String, Object> convert() {
|
||||
// abolish the activeness of variable inside a HashMap. Use stack instead.
|
||||
for (ByteCodeAction action : actions) {
|
||||
// try {
|
||||
//log.info("Action type: " + action.getType().toString());
|
||||
switch (action.getType()) {
|
||||
case DefineLocal2:
|
||||
defineLocalWithoutAssign();
|
||||
break;
|
||||
case DefineLocal:
|
||||
defineLocal();
|
||||
break;
|
||||
case GetVariable:
|
||||
getVariable();
|
||||
break;
|
||||
case SetMember:
|
||||
setMember();
|
||||
break;
|
||||
case Add:
|
||||
reduceViaAdder();
|
||||
break;
|
||||
case InitObject:
|
||||
initObject();
|
||||
break;
|
||||
case Push:
|
||||
this.stack.addAll(((ActionPush) action).getItems());
|
||||
break;
|
||||
case SetVariable:
|
||||
setVariable();
|
||||
break;
|
||||
case GetMember:
|
||||
getMember();
|
||||
break;
|
||||
default:
|
||||
// ignore
|
||||
}
|
||||
//} catch (Exception e) {
|
||||
//log.error(e.getMessage());
|
||||
//}
|
||||
switch (action.getType()) {
|
||||
case DefineLocal2:
|
||||
// doesn't need implementation due to HashMap's properties. (variableName)
|
||||
this.stack.pop();
|
||||
break;
|
||||
case DefineLocal:
|
||||
defineLocal();
|
||||
break;
|
||||
case GetVariable:
|
||||
getVariable();
|
||||
break;
|
||||
case SetMember:
|
||||
setMember();
|
||||
break;
|
||||
case Add:
|
||||
reduceViaAdder();
|
||||
break;
|
||||
case InitObject:
|
||||
initObject();
|
||||
break;
|
||||
case InitArray:
|
||||
initArray();
|
||||
break;
|
||||
case Push:
|
||||
this.stack.addAll(((ActionPush) action).getItems());
|
||||
break;
|
||||
case SetVariable:
|
||||
setVariable();
|
||||
break;
|
||||
case GetMember:
|
||||
getMember();
|
||||
break;
|
||||
default:
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return vars;
|
||||
return this.vars;
|
||||
}
|
||||
|
||||
private void initObject() {
|
||||
Integer numberOfEntries = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way
|
||||
int numberOfEntries = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way
|
||||
HashMap<String, Object> obj = new HashMap<>();
|
||||
for( int i = 0; i < numberOfEntries; i++ ) {
|
||||
Object val = valConverter( this.stack.pop() );
|
||||
@ -80,6 +79,16 @@ public class Flash2Java {
|
||||
this.stack.push(new InitObjectItem(obj));
|
||||
}
|
||||
|
||||
private void initArray() {
|
||||
int numberOfElements = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way
|
||||
HashMap<String, Object> obj = new HashMap<>();
|
||||
for( int i = 0; i < numberOfElements; i++ ) {
|
||||
Object val = valConverter( this.stack.pop() );
|
||||
obj.put(String.valueOf(i), val);
|
||||
}
|
||||
this.stack.push(new InitArrayItem(obj));
|
||||
}
|
||||
|
||||
private void reduceViaAdder() {
|
||||
/*
|
||||
// get last 2 elements from stack
|
||||
@ -100,7 +109,6 @@ public class Flash2Java {
|
||||
}
|
||||
|
||||
private void getMember() {
|
||||
log.info("GetMember: {}", this.stack);
|
||||
String property = valToString( this.stack.pop() );
|
||||
ByteCodeItem val = this.stack.pop();
|
||||
if( val.getType() == ActionPushType.GET_MEMBER ) {
|
||||
@ -113,56 +121,49 @@ public class Flash2Java {
|
||||
this.stack.push(new GetMemberItem(new ArrayDeque<>(List.of(key, property))));
|
||||
}
|
||||
|
||||
private void setMember() { // make recursive assignment.
|
||||
log.info("SetMember: {}", this.stack);
|
||||
private void setMember() {
|
||||
ByteCodeItem val = this.stack.pop();
|
||||
String index = valToString( this.stack.pop() );
|
||||
ByteCodeItem varOrMember = this.stack.pop();
|
||||
if( varOrMember.getType() == ActionPushType.GET_VARIABLE ) {
|
||||
Map<String, Object> m = (Map<String, Object>) this.vars.get(valToString( varOrMember ));
|
||||
if( val.getType() == ActionPushType.GET_VARIABLE ) {
|
||||
m.put(index, this.vars.get(valToString(val)));
|
||||
return;
|
||||
}
|
||||
m.put(index, val.getValue());
|
||||
this.vars.put(valToString(varOrMember), m);
|
||||
return;
|
||||
}
|
||||
// GetMemberItem recursive
|
||||
Map<String, Object> m = recursiveGet((ArrayDeque<String>) varOrMember.getValue());
|
||||
if( val.getType() == ActionPushType.GET_VARIABLE ) {
|
||||
m.put(index, this.vars.get(valToString(val)));
|
||||
return;
|
||||
}
|
||||
m.put(index, val.getValue());
|
||||
}
|
||||
|
||||
private Map<String, Object> recursiveGet(Deque<String> l) {
|
||||
Map<String, Object> m = this.vars;
|
||||
Iterator<String> i = l.iterator();
|
||||
while(i.hasNext()) {
|
||||
m = (HashMap<String, Object>) m.get(i.next());
|
||||
for (String s : l) {
|
||||
m = (HashMap<String, Object>) m.get(s);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private GetMemberItem toGetMember(ByteCodeItem item) {
|
||||
switch (item.getType()) {
|
||||
case GET_MEMBER:
|
||||
return (GetMemberItem) item;
|
||||
case STRING:
|
||||
case POOL_INDEX:
|
||||
default:
|
||||
return new GetMemberItem(new ArrayDeque<>(List.of(valToString(item))));
|
||||
}
|
||||
}
|
||||
|
||||
private String valToString(ByteCodeItem item) {
|
||||
if ( item.getType() == ActionPushType.POOL_INDEX ) {
|
||||
return fromPool( (Integer) item.getValue() );
|
||||
} else if ( item.getType() == ActionPushType.STRING ) {
|
||||
return (String) item.getValue();
|
||||
switch (item.getType()) {
|
||||
case POOL_INDEX:
|
||||
return fromPool( (Integer) item.getValue() );
|
||||
case STRING:
|
||||
return (String) item.getValue();
|
||||
default:
|
||||
return String.valueOf( item.getValue() );
|
||||
}
|
||||
return String.valueOf( item.getValue() );
|
||||
}
|
||||
|
||||
private Object valConverter(ByteCodeItem item) {
|
||||
if ( item.getType() == ActionPushType.POOL_INDEX ) {
|
||||
return fromPool( (Integer) item.getValue() );
|
||||
} else if ( item.getType() == ActionPushType.STRING ) {
|
||||
return item.getValue();
|
||||
if( item.getType() == ActionPushType.POOL_INDEX ) {
|
||||
return fromPool((Integer) item.getValue());
|
||||
}
|
||||
return item.getValue();
|
||||
}
|
||||
@ -170,7 +171,7 @@ public class Flash2Java {
|
||||
private void setVariable() {
|
||||
Object val = this.stack.pop().getValue();
|
||||
String variableName = valToString( this.stack.pop() );
|
||||
vars.put(variableName, val);
|
||||
this.vars.put(variableName, val);
|
||||
}
|
||||
|
||||
private void getVariable() {
|
||||
@ -178,18 +179,17 @@ public class Flash2Java {
|
||||
this.stack.push(new GetVariableItem(variableName));
|
||||
}
|
||||
|
||||
private void defineLocalWithoutAssign() {
|
||||
String variableName = valToString( this.stack.pop() );
|
||||
}
|
||||
|
||||
private void defineLocal() {
|
||||
ByteCodeItem val = this.stack.pop();
|
||||
String name = valToString( this.stack.pop() );
|
||||
// todo: implement assignment ability (from one value to another)
|
||||
vars.put(name, val.getValue());
|
||||
String name = valToString(this.stack.pop());
|
||||
if( val.getType() == ActionPushType.GET_VARIABLE ) {
|
||||
this.vars.put(name, this.vars.get(valToString(val)));
|
||||
return;
|
||||
}
|
||||
this.vars.put(name, val.getValue());
|
||||
}
|
||||
|
||||
private String fromPool(int index) {
|
||||
return pool.get(index);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.alterdekim.flash.decompiler.translator;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FlashVar {
|
||||
private boolean isActive = false;
|
||||
private Object val;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.alterdekim.flash.decompiler.translator;
|
||||
|
||||
import com.alterdekim.flash.decompiler.action.ByteCodeAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
public class Java2Flash {
|
||||
private Set<String> pool;
|
||||
|
||||
public List<ByteCodeAction> convert(Map<String, Object> map) {
|
||||
this.pool = new HashSet<>(65535);
|
||||
extractAllStrings(map);
|
||||
log.info("poolSet: {}", this.pool);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private void extractAllStrings(Map<String, Object> map) {
|
||||
map.keySet().forEach(k -> {
|
||||
if(k.matches("[^0-9].+")) {
|
||||
pool.add(k);
|
||||
}
|
||||
});
|
||||
map.values().forEach(o -> {
|
||||
switch( o.getClass().getSimpleName() ) {
|
||||
case "HashMap":
|
||||
extractAllStrings((HashMap<String, Object>) o);
|
||||
break;
|
||||
case "String":
|
||||
pool.add((String) o);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ public enum ActionField {
|
||||
ConstantPool((byte) 0x88),
|
||||
Push((byte) 0x96),
|
||||
InitObject((byte) 0x43),
|
||||
InitArray((byte) 0x42),
|
||||
DefineLocal((byte) 0x3C),
|
||||
DefineLocal2((byte) 0x41),
|
||||
SetMember((byte)0x4F),
|
||||
|
@ -1,8 +1,12 @@
|
||||
package com.alterdekim.flash.decompiler.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Slf4j
|
||||
public class ByteUtil {
|
||||
public static int bytesToInt(byte[] bytes) {
|
||||
int value = 0;
|
||||
@ -21,6 +25,13 @@ public class ByteUtil {
|
||||
}
|
||||
|
||||
public static double bytesToDouble(byte[] bytes) {
|
||||
return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getDouble();
|
||||
byte[] b1 = new byte[8];
|
||||
for( int i = bytes.length-1, u = 0; i >= 0; i--, u++ ) {
|
||||
b1[u] = bytes[i];
|
||||
}
|
||||
byte[] d = new byte[8];
|
||||
System.arraycopy(Arrays.copyOfRange(b1, 4, 8), 0, d, 0, 4);
|
||||
System.arraycopy(Arrays.copyOfRange(b1, 0, 4), 0, d, 4, 4);
|
||||
return ByteBuffer.wrap(d).order(ByteOrder.BIG_ENDIAN).getDouble();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user