From 829b1342a761f448430da5580878b74189103c71 Mon Sep 17 00:00:00 2001 From: alterdekim Date: Sun, 5 Jan 2025 07:16:53 +0300 Subject: [PATCH] Decompiler fix and compiler fix (not works for now) --- pom.xml | 60 ++++++++++++++++--- .../flash/decompiler/FlashDecompiler.java | 56 +++++++++++------ .../com/alterdekim/flash/decompiler/Main.java | 7 ++- .../decompiler/compiler/FlashCompiler.java | 18 +++--- .../flash/decompiler/tag/DoAction.java | 10 ++-- .../decompiler/translator/Flash2Java.java | 48 +++++---------- .../decompiler/translator/Java2Flash.java | 16 +++-- 7 files changed, 133 insertions(+), 82 deletions(-) diff --git a/pom.xml b/pom.xml index d7ea83a..b449be9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,12 +6,36 @@ com.alterdekim.game actionScriptDecompiler - 1.0-SNAPSHOT + 0.0.2 jar + SWFDissect + + + This project is a library for swf editing in Java. + DON'T USE THIS IN PRODUCTION. IT WAS CREATED FOR INTERNAL PURPOSES ONLY. + + https://blog.awain.net + + + + Michael Wain + alterwain@protonmail.com + The God + https://blog.awain.net + + + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + - 11 - 11 + 14 + 14 UTF-8 com.alterdekim.flash.decompiler.Main @@ -54,15 +78,35 @@ 2.17.2 + - org.apache.maven.plugins + maven-clean-plugin + + + maven-resources-plugin + + maven-compiler-plugin - - 14 - 14 - + + + maven-surefire-plugin + + + maven-jar-plugin + + + maven-install-plugin + + + maven-deploy-plugin + + + maven-site-plugin + + + maven-project-info-reports-plugin diff --git a/src/main/java/com/alterdekim/flash/decompiler/FlashDecompiler.java b/src/main/java/com/alterdekim/flash/decompiler/FlashDecompiler.java index 7123b1a..af817fa 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/FlashDecompiler.java +++ b/src/main/java/com/alterdekim/flash/decompiler/FlashDecompiler.java @@ -5,14 +5,12 @@ import com.alterdekim.flash.decompiler.item.*; import com.alterdekim.flash.decompiler.tag.DoAction; import com.alterdekim.flash.decompiler.tag.ShockwaveTag; import com.alterdekim.flash.decompiler.tag.TagType; -import com.alterdekim.flash.decompiler.util.ActionField; -import com.alterdekim.flash.decompiler.util.Bits; -import com.alterdekim.flash.decompiler.util.PayloadCompression; -import com.alterdekim.flash.decompiler.util.StringUtils; +import com.alterdekim.flash.decompiler.util.*; import lombok.extern.slf4j.Slf4j; import org.javatuples.Triplet; import java.io.*; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; @@ -48,6 +46,21 @@ public class FlashDecompiler { return processPayload(data); } + public byte[] uncompressSWF(byte[] swfBytes) throws IOException { + compression = PayloadCompression.getByTag(swfBytes[0]); + byte[] data = Arrays.copyOfRange(swfBytes, 8, swfBytes.length); + switch (compression) { + case DEFLATE: + data = decompressDEFLATE(data); + break; + } + byte[] o = new byte[8 + data.length]; + byte[] b = Arrays.copyOfRange(swfBytes, 0, 8); + System.arraycopy(b, 0, o, 0, 8); + System.arraycopy(data, 0, o, 8, data.length); + return o; + } + private ShockwaveFile processPayload(byte[] payload) { BitSet bitSet = BitSet.valueOf(payload); int c = (payload.length * 8); @@ -74,6 +87,7 @@ public class FlashDecompiler { len = Bits.convert(bitSet.get(i, i+32), 32, true); i += 32; } + log.info("Len: {}", len); TagType tagType = TagType.fromId(type); if( tagType == TagType.DoAction ) { int g = i / 8; @@ -131,7 +145,13 @@ public class FlashDecompiler { i++; tag.getActions().add(new ActionGetMember()); break; + case Add: + log.info("Add"); + i++; + tag.getActions().add(new ActionAdd()); + break; case Unknown: + log.info("Unknown tag has been hit: {} / {}", i, tag.getActions().get(tag.getActions().size()-1)); return tag; default: log.error("Unknown action field type: {}", StringUtils.bytesToHex(new byte[] {data[i]})); @@ -139,20 +159,22 @@ public class FlashDecompiler { break; } } + log.info("Out of loop"); return tag; } private Triplet findNull(byte[] data, int i, int u) { int s = i; - while( data[i] != 0x00 ) { + while(data[i] != 0x00 ) { i++; u++; } - return Triplet.with(Arrays.copyOfRange(data, s, i), i, u); + i++; + u++; + return Triplet.with(Arrays.copyOfRange(data, s, i-1), i, u); } private int parseActionPush(byte[] data, int i, DoAction tag) { - //int start_action_index = i; // for debug i++; int len_in_bytes = bytesToIntRev(Arrays.copyOfRange(data, i, i+2)); int u = 0; @@ -166,8 +188,11 @@ public class FlashDecompiler { // implement other types (float especially) case STRING: i++; + u++; + log.info("S0: {}", i); var result = findNull(data, i, u); - push.getItems().add(new StringItem(new String(result.getValue0()))); + push.getItems().add(new StringItem(new String(result.getValue0(), StandardCharsets.UTF_8))); + log.info("STRING: {} {}", new String(result.getValue0(), StandardCharsets.UTF_8), result.getValue1()); i = result.getValue1(); u = result.getValue2(); break; @@ -215,12 +240,6 @@ public class FlashDecompiler { } } tag.getActions().add(push); - /*byte[] bv = Arrays.copyOfRange(data, start_action_index, i); - List s = IntStream.range(0, bv.length) - .map(v -> bv[v]) - .mapToObj(v -> Integer.toHexString(v)) - .collect(Collectors.toList()); - log.info("Push data block: {}", s);*/ return i; } @@ -229,19 +248,18 @@ 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(); + List s = new ArrayList<>(); while( u <= count ) { if( data[i] == 0x00 ) { - actionPool.add(s.toString()); - s = new StringBuilder(); + actionPool.add(new String( ByteUtil.toPrimitive(s), StandardCharsets.UTF_8 )); + s.clear(); u++; i++; continue; } - s.append((char) data[i]); + s.add(data[i]); i++; } tag.setActionPool(actionPool); diff --git a/src/main/java/com/alterdekim/flash/decompiler/Main.java b/src/main/java/com/alterdekim/flash/decompiler/Main.java index 8628317..3085281 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/Main.java +++ b/src/main/java/com/alterdekim/flash/decompiler/Main.java @@ -17,7 +17,12 @@ import java.nio.file.StandardOpenOption; 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")); // + + + /*byte[] g = decompiler.uncompressSWF(Files.readAllBytes(new File("D:\\Documents\\rtmpSpring\\static\\swf\\cache\\rus\\resources[19].swf").toPath())); + Files.write(new File("res.swf").toPath(), g, StandardOpenOption.CREATE);*/ + + ShockwaveFile file = decompiler.loadFromFile(new File("D:\\Documents\\rtmpSpring\\static\\swf\\cache\\rus\\resources[19].swf")); DoAction da = (DoAction) file.getTags() .stream() diff --git a/src/main/java/com/alterdekim/flash/decompiler/compiler/FlashCompiler.java b/src/main/java/com/alterdekim/flash/decompiler/compiler/FlashCompiler.java index c8afb3e..44da65b 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/compiler/FlashCompiler.java +++ b/src/main/java/com/alterdekim/flash/decompiler/compiler/FlashCompiler.java @@ -9,8 +9,8 @@ import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Queue; import java.util.stream.Collectors; +import java.util.stream.Stream; @RequiredArgsConstructor @Slf4j @@ -18,21 +18,19 @@ public class FlashCompiler { private final Java2Flash pcode; public byte[] compile() { - List data = new ArrayList<>(); - data.addAll(List.of((byte) 0x46, (byte) 0x57, (byte) 0x53)); + List data = new ArrayList<>(List.of((byte) 0x46, (byte) 0x57, (byte) 0x53)); data.add((byte) 0x08); // swf version (8) List d1 = new ArrayList<>(); d1.addAll(List.of((byte) 0x30, (byte) 0x0A, (byte) 0x00, (byte) 0xA0)); // rect d1.addAll(List.of((byte) 0x00, (byte) 0x19)); // frameRate d1.addAll(ByteUtil.intToBytes(1)); // frames Count - //List tags = List.of(new SetBackgroundColor(new byte[] {0,0,0}), new DoAction(pcode.getPool(), pcode.getActions()), new ShowFrame(), new End()); - //d1.addAll(tags.stream().map(CompileObject::compile).flatMap(Collection::stream).collect(Collectors.toList())); - d1.addAll(new SetBackgroundColor(new byte[] {0,0,0}).compile()); - d1.addAll(new DoAction(pcode.getPool(), pcode.getActions()).compile()); - d1.addAll(new ShowFrame().compile()); - d1.addAll(new End().compile()); + d1.addAll( + Stream.of(new SetBackgroundColor(new byte[] {0,0,0}), new DoAction(pcode.getPool(), pcode.getActions()), new ShowFrame(), new End()) + .map(CompileObject::compile) + .flatMap(Collection::stream) + .collect(Collectors.toList()) + ); // fileSize u32 - log.info("fileSize u32: {}", d1.size()); data.addAll(ByteUtil.intToBytes32(d1.size()+data.size()+4)); data.addAll(d1); return ByteUtil.toPrimitive(data); diff --git a/src/main/java/com/alterdekim/flash/decompiler/tag/DoAction.java b/src/main/java/com/alterdekim/flash/decompiler/tag/DoAction.java index 1ff74be..4fb3f61 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/tag/DoAction.java +++ b/src/main/java/com/alterdekim/flash/decompiler/tag/DoAction.java @@ -48,7 +48,7 @@ public class DoAction extends ShockwaveTag implements CompileObject { case INTEGER: data.addAll(ByteUtil.intToBytes32((Integer) item.getValue())); break; - case POOL_INDEX: + case POOL_INDEX: // todo: make distiction between small POOL_INDEX and large POOL_INDEX Integer index = (Integer) item.getValue(); data.addAll(index < 256 ? ByteUtil.intToBytes8(index) : ByteUtil.intToBytes(index)); break; @@ -66,9 +66,7 @@ public class DoAction extends ShockwaveTag implements CompileObject { case ConstantPool: ActionConstantPool pool = (ActionConstantPool) action; data.addAll(ByteUtil.intToBytes(pool.getPool().size())); - pool.getPool().forEach(s -> { - data.addAll(fromString(s)); - }); + pool.getPool().forEach(s -> data.addAll(fromString(s))); bytes.addAll(ByteUtil.intToBytes(data.size())); bytes.addAll(data); break; @@ -82,8 +80,8 @@ public class DoAction extends ShockwaveTag implements CompileObject { private List fromString(String s) { List l = new ArrayList<>(); - for( char c : s.toCharArray() ) { - l.add((byte) c); + for( byte c : s.getBytes() ) { + l.add(c); } l.add((byte) 0x0); return l; diff --git a/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java b/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java index dd2cb0c..e379dea 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java +++ b/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java @@ -61,15 +61,13 @@ public class Flash2Java { case GetMember: getMember(); break; - default: - // ignore } } return this.vars; } private void initObject() { - int numberOfEntries = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way + int numberOfEntries = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way todo: rewrite HashMap obj = new HashMap<>(); for( int i = 0; i < numberOfEntries; i++ ) { Object val = valConverter( this.stack.pop() ); @@ -80,7 +78,7 @@ public class Flash2Java { } private void initArray() { - int numberOfElements = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way + int numberOfElements = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way todo: rewrite HashMap obj = new HashMap<>(); for( int i = 0; i < numberOfElements; i++ ) { Object val = valConverter( this.stack.pop() ); @@ -90,22 +88,9 @@ public class Flash2Java { } private void reduceViaAdder() { - /* - // get last 2 elements from stack - List si = new ArrayList<>(); - List g = new ArrayList<>(); - for( int i = this.stack.size()-1; i >= 0; i-- ) { - ByteCodeAction e = this.stack.get(i); - if( e.getType() != ActionField.Push ) continue; - ActionPush push = (ActionPush) e; - if( push.getItems().size() >= 2 ) { - StringItem from = (StringItem) push.getItems().get(push.getItems().size()-1); - StringItem to = (StringItem) push.getItems().get(push.getItems().size()-2); - /*push.getItems().remove() - ((String) to.getValue()) + ((String) from.getValue())*//* - } - } - */ + String s1 = valToString( this.stack.pop() ); + String s2 = valToString( this.stack.pop() ); + this.stack.push(new StringItem(s2 + s1)); } private void getMember() { @@ -117,7 +102,7 @@ public class Flash2Java { this.stack.push(new GetMemberItem(l)); return; } - String key = valToString(val); + String key = (String) val.getValue(); this.stack.push(new GetMemberItem(new ArrayDeque<>(List.of(key, property)))); } @@ -126,11 +111,7 @@ public class Flash2Java { String index = valToString( this.stack.pop() ); ByteCodeItem varOrMember = this.stack.pop(); if( varOrMember.getType() == ActionPushType.GET_VARIABLE ) { - Map m = (Map) this.vars.get(valToString( varOrMember )); - if( val.getType() == ActionPushType.GET_VARIABLE ) { - m.put(index, this.vars.get(valToString(val))); - return; - } + Map m = (Map) valConverter(varOrMember); m.put(index, valConverter(val)); return; } @@ -156,16 +137,19 @@ public class Flash2Java { return fromPool( (Integer) item.getValue() ); case STRING: return (String) item.getValue(); + case GET_VARIABLE: + return (String) vars.get((String) item.getValue()); default: return String.valueOf( item.getValue() ); } } private Object valConverter(ByteCodeItem item) { - if( item.getType() == ActionPushType.POOL_INDEX ) { - return fromPool((Integer) item.getValue()); - } - return item.getValue(); + return switch (item.getType()) { + case POOL_INDEX -> fromPool((Integer) item.getValue()); + case GET_VARIABLE -> vars.get((String) item.getValue()); + default -> item.getValue(); + }; } private void setVariable() { @@ -182,10 +166,6 @@ public class Flash2Java { private void defineLocal() { ByteCodeItem val = this.stack.pop(); 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, valConverter(val)); } diff --git a/src/main/java/com/alterdekim/flash/decompiler/translator/Java2Flash.java b/src/main/java/com/alterdekim/flash/decompiler/translator/Java2Flash.java index 81d7751..ba04fed 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/translator/Java2Flash.java +++ b/src/main/java/com/alterdekim/flash/decompiler/translator/Java2Flash.java @@ -13,13 +13,14 @@ import java.util.*; @Getter public class Java2Flash { + private int cnt = 0; // abolish private List pool; private List actions; public Java2Flash convert(Map map) { this.actions = new ArrayList<>(); this.pool = new ArrayList<>(); - this.pool.addAll(extractAllStrings(new HashSet<>(65535), map)); // maybe make a check if hashset size is bigger than initialCapacity + this.pool.addAll(extractAllStrings(new HashSet<>(65535), map)); this.actions.add(new ActionConstantPool(this.pool)); map.keySet().forEach(k -> createVariable(map, k)); map.keySet().stream().filter(k -> map.get(k).getClass().getSimpleName().equals("HashMap")).forEach(k -> setMembers(map, k)); @@ -77,7 +78,6 @@ public class Java2Flash { private void createVariable(Map map, String key) { List items = new ArrayList<>(); items.add(fromString(key)); - log.info("Type: {}", map.get(key).getClass().getSimpleName()); items.add(switch (map.get(key).getClass().getSimpleName()) { case "String" -> fromString((String) map.get(key)); case "Integer" -> new IntegerItem((Integer) map.get(key)); @@ -102,13 +102,21 @@ public class Java2Flash { try { Integer.parseInt(k); } catch (Exception e) { - pool.add(k); + if( pool.size() < 3000 ) { + pool.add(k); + cnt++; + } } }); map.values().forEach(o -> { switch (o.getClass().getSimpleName()) { case "HashMap" -> extractAllStrings(pool, (HashMap) o); - case "String" -> pool.add((String) o); + case "String" -> { + if( pool.size() < 3000 ) { + pool.add((String) o); + cnt++; + } + } } }); return pool;