From 8c8be0737fc3c9fe79f2142cc4d48dc45626c053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 24 Oct 2015 10:09:39 +0200 Subject: [PATCH] Open loaded SWFs during playback feature --- .../flash/debugger/DebugConnection.as | 55 +++++++++- .../decompiler/flash/debugger/DebugLoader.as | 22 ++++ .../decompiler/flash/debugger/DebugMain.as | 1 + .../decompiler/flash/debugger/debugAlert.as | 9 +- .../decompiler/flash/debugger/debugConsole.as | 9 +- .../decompiler/flash/debugger/debugSocket.as | 13 +-- .../decompiler/flash/debugger/debugTrace.as | 8 +- .../flash/configuration/Configuration.java | 4 + .../decompiler/flash/gui/DebugLogDialog.java | 12 +++ src/com/jpexs/decompiler/flash/gui/Main.java | 54 ++++++++++ .../decompiler/flash/gui/MainFrameMenu.java | 18 +++- .../decompiler/flash/gui/PreviewPanel.java | 18 ++++ .../flash/gui/debugger/DebugListener.java | 4 + .../flash/gui/debugger/Debugger.java | 101 +++++++++++++++++- .../flash/gui/debugger/DebuggerTools.java | 35 +++++- .../decompiler/flash/gui/debugger/debug.swf | Bin 1748 -> 2322 bytes .../locales/AdvancedSettingsDialog.properties | 3 + .../AdvancedSettingsDialog_cs.properties | 3 + .../flash/gui/locales/MainFrame.properties | 3 +- .../flash/gui/locales/MainFrame_cs.properties | 3 +- 20 files changed, 344 insertions(+), 31 deletions(-) create mode 100644 libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as index 0a5e01a62..b0787dda0 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as @@ -12,17 +12,30 @@ private static var first:Boolean = true; private static var inited:Boolean = false; private static var name:String; + public static const DEBUG_VERSION_MAJOR = 1; + public static const DEBUG_VERSION_MINOR = 1; + public static const MSG_STRING = 0; + public static const MSG_LOADER_URL = 1; + public static const MSG_LOADER_BYTES = 2; + private static function sendQueue(){ var qo = q; q = []; for each(var m in qo){ - writeMsg(m); + writeMsg(m.data,m.type); } } + private static function writeStringNull(msg){ + var b:ByteArray = new ByteArray(); + b.writeUTFBytes(msg); + s.writeBytes(b,0,b.length); + s.writeByte(0); + } + private static function writeString(msg){ var b:ByteArray = new ByteArray(); b.writeUTFBytes(msg); @@ -31,6 +44,14 @@ s.writeBytes(b,0,b.length); } + private static function writeBytes(b:ByteArray){ + s.writeByte((b.length>>24) & 0xff); + s.writeByte((b.length>>16) & 0xff); + s.writeByte((b.length>>8) & 0xff); + s.writeByte(b.length & 0xff); + s.writeBytes(b,0,b.length); + } + public static function initClient(sname){ if(inited){ return; @@ -47,19 +68,43 @@ inited = true; } - public static function writeMsg(msg){ + + public static function writeLoaderURL(url){ + writeMsg(url,MSG_LOADER_URL); + } + + + public static function writeLoaderBytes(data:ByteArray){ + writeMsg(data,MSG_LOADER_BYTES); + } + + + + public static function writeMsg(msg,msgType=0){ if(!inited){ initClient(""); } if(s.connected){ if(first){ - s.writeByte(0); + //s.writeByte(0); + writeStringNull("debug.version.major="+DEBUG_VERSION_MAJOR+";debug.version.minor="+DEBUG_VERSION_MINOR); writeString(name); first = false; + } + s.writeByte(msgType); + switch(msgType){ + case MSG_STRING: + writeString(msg); + break; + case MSG_LOADER_URL: + writeString(msg); + break; + case MSG_LOADER_BYTES: + writeBytes(msg); + break; } - writeString(msg); }else{ - q.push(msg); + q.push({type:msgType,data:msg}); } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as new file mode 100644 index 000000000..cdcf3f3f4 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as @@ -0,0 +1,22 @@ +package com.jpexs.decompiler.flash.debugger { + + import flash.display.Loader; + import flash.net.URLRequest; + import flash.system.LoaderContext; + import flash.utils.ByteArray; + + public class DebugLoader extends Loader { + + + public override function load(request:URLRequest, context:LoaderContext = null):void { + DebugConnection.writeLoaderURL(request.url); + super.load(request,context); + } + + public override function loadBytes(bytes:ByteArray, context:LoaderContext = null):void { + DebugConnection.writeLoaderBytes(bytes); + super.loadBytes(bytes,context); + } + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as index 0ac6bac75..a78ed0a95 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as @@ -11,6 +11,7 @@ debugConsole("test console"); debugSocket("test proxy"); debugTrace("test trace"); + var loader:DebugLoader = new DebugLoader(); } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as index 7a35251ec..ecb897385 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as @@ -2,10 +2,11 @@ import flash.external.ExternalInterface; - public function debugAlert(msg):*{ - if(ExternalInterface.available) - ExternalInterface.call("alert",""+msg); - return msg; + public function debugAlert(...msg):void{ + for each(var n in msg){ + if(ExternalInterface.available) + ExternalInterface.call("alert",""+n); + } } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as index 121ab0867..ae40b66fc 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as @@ -2,10 +2,11 @@ import flash.external.ExternalInterface; - public function debugConsole(msg):*{ - if(ExternalInterface.available) - ExternalInterface.call("console.log",""+msg); - return msg; + public function debugConsole(...msg):*{ + for each(var n in msg){ + if(ExternalInterface.available) + ExternalInterface.call("console.log",""+n); + } } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as index 0f93d6137..6bf16b0e1 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as @@ -1,13 +1,14 @@ package com.jpexs.decompiler.flash.debugger { import flash.system.Capabilities; - public function debugSocket(msg):*{ - //only on webpages or activex - if(Capabilities.playerType == 'PlugIn' - || Capabilities.playerType == 'ActiveX'){ - DebugConnection.writeMsg(msg); + public function debugSocket(...msg):*{ + for each(var n in msg){ + //only on webpages or activex + if(Capabilities.playerType == 'PlugIn' + || Capabilities.playerType == 'ActiveX'){ + DebugConnection.writeMsg(n); + } } - return msg; } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as index 58ee09b11..885581190 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as @@ -1,9 +1,11 @@ package com.jpexs.decompiler.flash.debugger { - public function debugTrace(name){ - debugConsole(name); - debugSocket(name); + public function debugTrace(...msg){ + for each(var n in msg){ + debugConsole(n); + debugSocket(n); + } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index e4059bc82..f2004fbe7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -494,6 +494,10 @@ public class Configuration { @ConfigurationCategory("script") public static final ConfigurationItem enableScriptInitializerDisplay = null; + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem autoOpenLoadedSWFs = null; + private enum OSId { WINDOWS, OSX, UNIX diff --git a/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java index 3f8509df6..b0a28f7cc 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.gui.debugger.DebugListener; import com.jpexs.decompiler.flash.gui.debugger.Debugger; import java.awt.BorderLayout; @@ -24,6 +25,7 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; +import java.io.ByteArrayInputStream; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -61,6 +63,16 @@ public class DebugLogDialog extends AppDialog { public void onFinish(String clientId) { } + + @Override + public void onLoaderURL(String clientId, String url) { + log(translate("msg.header").replace("%clientid%", clientId) + " LOADURL:" + url); + } + + @Override + public void onLoaderBytes(String clientId, byte[] data) { + log(translate("msg.header").replace("%clientid%", clientId) + " LOADBYTES: " + data.length + "B"); + } }); Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 4d68cc83a..7d6459a34 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -30,6 +30,8 @@ import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; import com.jpexs.decompiler.flash.console.ContextMenuTools; import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; +import com.jpexs.decompiler.flash.gui.debugger.DebugListener; +import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; @@ -60,6 +62,7 @@ import java.awt.event.MouseEvent; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -77,9 +80,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.logging.ConsoleHandler; @@ -910,6 +915,20 @@ public class Main { ErrorLogFrame.getInstance().setVisible(true); } + private static String md5(byte data[]) { + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); + byte[] array = md.digest(data); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < array.length; ++i) { + sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + } catch (java.security.NoSuchAlgorithmException e) { + } + return null; + } + private static void initGui() { if (GraphicsEnvironment.isHeadless()) { System.err.println("Error: Your system does not support Graphic User Interface"); @@ -942,6 +961,41 @@ public class Main { autoCheckForUpdates(); offerAssociation(); loadingDialog = new LoadingDialog(); + + DebuggerTools.initDebugger().addMessageListener(new DebugListener() { + + @Override + public void onMessage(String clientId, String msg) { + } + + @Override + public void onLoaderURL(String clientId, String url) { + } + + @Override + public void onLoaderBytes(String clientId, byte[] data) { + String hash = md5(data); + for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { + for (int s = 0; s < sl.size(); s++) { + String t = sl.get(s).getFileTitle(); + if (t == null) { + t = ""; + } + if (t.endsWith(":" + hash)) { //this one is already opened + return; + } + } + } + SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); + + String title = swf == null ? "?" : swf.getFileTitle(); + openFile(new SWFSourceInfo(new ByteArrayInputStream(data), null, title + ":" + hash)); + } + + @Override + public void onFinish(String clientId) { + } + }); } public static void showModeFrame() { diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 6ade11fd5..015d6699c 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -374,6 +374,11 @@ public abstract class MainFrameMenu implements MenuBuilder { DebuggerTools.debuggerShowLog(); } + protected void debuggerInjectLoader(ActionEvent evt) { + DebuggerTools.injectDebugLoader(swf); + refreshDecompiled(); + } + protected void debuggerReplaceTraceCallsActionPerformed(ActionEvent evt) { ReplaceTraceDialog rtd = new ReplaceTraceDialog(Configuration.lastDebuggerReplaceFunction.get()); rtd.setVisible(true); @@ -518,6 +523,13 @@ public abstract class MainFrameMenu implements MenuBuilder { Configuration.gotoMainClassOnStartup.set(selected); } + protected void autoOpenLoadedSWFsActionPerformed(ActionEvent evt) { + AbstractButton button = (AbstractButton) evt.getSource(); + boolean selected = button.isSelected(); + + Configuration.autoOpenLoadedSWFs.set(selected); + } + protected void autoRenameIdentifiersActionPerformed(ActionEvent evt) { AbstractButton button = (AbstractButton) evt.getSource(); boolean selected = button.isSelected(); @@ -672,6 +684,7 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuEnabled("/tools/debugger/debuggerSwitch", hasAbc); setMenuChecked("/tools/debugger/debuggerSwitch", hasDebugger); setMenuEnabled("/tools/debugger/debuggerReplaceTrace", hasAbc && hasDebugger); + //setMenuEnabled("/tools/debugger/debuggerInjectLoader", hasAbc && hasDebugger); setMenuEnabled("_/checkUpdates", !isWorking); setMenuEnabled("/help/checkUpdates", !isWorking); @@ -780,6 +793,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("/tools/debugger", translate("menu.debugger"), null, null, 0, null, false); addToggleMenuItem("/tools/debugger/debuggerSwitch", translate("menu.debugger.switch"), null, "debugger32", this::debuggerSwitchActionPerformed, PRIORITY_TOP); addMenuItem("/tools/debugger/debuggerReplaceTrace", translate("menu.debugger.replacetrace"), "debuggerreplace16", this::debuggerReplaceTraceCallsActionPerformed, PRIORITY_MEDIUM, null, true); + //addMenuItem("/tools/debugger/debuggerInjectLoader", "Inject Loader", "debuggerreplace16", this::debuggerInjectLoader, PRIORITY_MEDIUM, null, true); addMenuItem("/tools/debugger/debuggerShowLog", translate("menu.debugger.showlog"), "debuggerlog16", this::debuggerShowLogActionPerformed, PRIORITY_MEDIUM, null, true); finishMenu("/tools/debugger"); @@ -796,7 +810,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addToggleMenuItem("/settings/cacheOnDisk", translate("menu.settings.cacheOnDisk"), null, null, this::cacheOnDiskActionPerformed, 0); addToggleMenuItem("/settings/gotoMainClassOnStartup", translate("menu.settings.gotoMainClassOnStartup"), null, null, this::gotoDucumentClassOnStartupActionPerformed, 0); addToggleMenuItem("/settings/autoRenameIdentifiers", translate("menu.settings.autoRenameIdentifiers"), null, null, this::autoRenameIdentifiersActionPerformed, 0); - + addToggleMenuItem("/settings/autoOpenLoadedSWFs", translate("menu.settings.autoOpenLoadedSWFs"), null, null, this::autoOpenLoadedSWFsActionPerformed, 0); if (Platform.isWindows()) { addToggleMenuItem("/settings/associate", translate("menu.settings.addtocontextmenu"), null, null, this::associateActionPerformed, 0); } @@ -858,6 +872,7 @@ public abstract class MainFrameMenu implements MenuBuilder { if (externalFlashPlayerUnavailable) { setMenuEnabled("/settings/internalViewer", false); + setMenuEnabled("/settings/autoOpenLoadedSWFs", false); } /*int deobfuscationMode = Configuration.deobfuscationMode.get(); @@ -954,6 +969,7 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuChecked("/tools/debugger/debuggerSwitch", false); } setMenuEnabled("/tools/debugger/debuggerReplaceTrace", isMenuChecked("/tools/debugger/debuggerSwitch")); + //setMenuEnabled("/tools/debugger/debuggerInjectLoader", isMenuChecked("/tools/debugger/debuggerSwitch")); } private void timelineActionPerformed(ActionEvent evt) { diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index d534e8e54..1ae410f1a 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; +import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; import com.jpexs.decompiler.flash.gui.player.MediaDisplay; @@ -79,6 +80,7 @@ import java.awt.event.ActionEvent; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -1072,9 +1074,25 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { swf.saveTo(fos); } + //Inject Loader + if (swf.isAS3() && Configuration.autoOpenLoadedSWFs.get() && !Configuration.internalFlashViewer.get() && !DebuggerTools.hasDebugger(swf)) { + SWF instrSWF = null; + try (FileInputStream fis = new FileInputStream(tempFile)) { + instrSWF = new SWF(fis, false, false); + } + if (instrSWF != null) { + DebuggerTools.switchDebugger(instrSWF); + DebuggerTools.injectDebugLoader(instrSWF); + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { + instrSWF.saveTo(fos); + } + } + } flashPanel.displaySWF(tempFile.getAbsolutePath(), backgroundColor, swf.frameRate); } catch (IOException iex) { Logger.getLogger(PreviewPanel.class.getName()).log(Level.SEVERE, "Cannot create tempfile", iex); + } catch (InterruptedException ex) { + } } diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java index 6fcae2c67..1882c30c0 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java @@ -24,5 +24,9 @@ public interface DebugListener { public void onMessage(String clientId, String msg); + public void onLoaderURL(String clientId, String url); + + public void onLoaderBytes(String clientId, byte data[]); + public void onFinish(String clientId); } diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java index ee3440253..76f7da65b 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java @@ -25,10 +25,12 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; +import java.util.regex.Pattern; /** * @@ -57,6 +59,30 @@ public class Debugger { private final int id; public boolean finished = false; + private final Map parameters = new HashMap<>(); + + public static final int MSG_STRING = 0; + public static final int MSG_LOADER_URL = 1; + public static final int MSG_LOADER_BYTES = 2; + + public String getParameter(String name, String defValue) { + if (parameters.containsKey(name)) { + return parameters.get(name); + } + return defValue; + } + + public int getVersionMajor() { + return Integer.parseInt(getParameter("debug.version.major", "1")); + } + + public int getVersionMinor() { + return Integer.parseInt(getParameter("debug.version.major", "0")); + } + + public boolean hasMsgType() { + return getVersionMajor() > 1 || getVersionMinor() > 0; + } public DebugHandler(int serverPort, Socket s) { this.s = s; @@ -72,6 +98,42 @@ public class Debugger { } } + private int readType(InputStream is) throws IOException { + int type = is.read(); + if (type == -1) { + throw new EOFException(); + } + return type; + } + + private byte[] readBytes(InputStream is) throws IOException { + int len = is.read(); + if (len == -1) { + throw new EOFException(); + } + int len2 = is.read(); + if (len2 == -1) { + throw new EOFException(); + } + int len3 = is.read(); + if (len3 == -1) { + throw new EOFException(); + } + int len4 = is.read(); + if (len4 == -1) { + throw new EOFException(); + } + len = (len << 24) + (len2 << 16) + (len3 << 8) + len4; + byte data[] = new byte[len]; + int cnt; + int off = 0; + while (len > 0 && (cnt = is.read(data, off, len)) > 0) { + len -= cnt; + off += cnt; + } + return data; + } + private String readString(InputStream is) throws IOException { int len = is.read(); if (len == -1) { @@ -115,14 +177,47 @@ public class Debugger { os.write(("").getBytes("UTF-8")); } } else { + if (!ret.isEmpty()) { + String param[] = (ret.contains(";") ? ret.split(";") : new String[]{ret}); + for (String p : param) { + if (p.contains("=")) { + String key = p.substring(0, p.indexOf("=")); + String val = p.substring(p.indexOf("=") + 1); + parameters.put(key, val); + } else { + parameters.put(p, "true"); + } + } + } + boolean hasType = hasMsgType(); String name = readString(is); if (!name.isEmpty()) { clientName = name; } while (true) { - ret = readString(is); - for (DebugListener l : listeners) { - l.onMessage(clientName, ret); + int type = 0; + if (hasType) { + type = readType(is); + } + switch (type) { + case MSG_STRING: + ret = readString(is); + for (DebugListener l : listeners) { + l.onMessage(clientName, ret); + } + break; + case MSG_LOADER_URL: + ret = readString(is); + for (DebugListener l : listeners) { + l.onLoaderURL(clientName, ret); + } + break; + case MSG_LOADER_BYTES: + byte retB[] = readBytes(is); + for (DebugListener l : listeners) { + l.onLoaderBytes(clientName, retB); + } + break; } } } diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java index 37a354014..fc78acfa4 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java @@ -85,6 +85,27 @@ public class DebuggerTools { return tested.matches(Pattern.quote(DEBUGGER_PACKAGE) + "(\\.pkg[a-f0-9]+)?" + cls); } + public static void injectDebugLoader(SWF swf) { + if (hasDebugger(swf)) { + ScriptPack dsp = getDebuggerScriptPack(swf); + String debuggerPkg = dsp.getClassPath().packageStr.toRawString(); + for (ABCContainerTag ct : swf.getAbcList()) { + ABC a = ct.getABC(); + if (dsp.abc == a) { //do not replace Loader in debugger itself + continue; + } + for (int i = 1; i < a.constants.constant_multiname.size(); i++) { + Multiname m = a.constants.constant_multiname.get(i); + if ("flash.display.Loader".equals(m.getNameWithNamespace(a.constants).toRawString())) { + m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId(debuggerPkg, true)), 0, true); + m.name_index = a.constants.getStringId("DebugLoader", true); + ((Tag) ct).setModified(true); + } + } + } + } + } + public static void replaceTraceCalls(SWF swf, String fname) { if (hasDebugger(swf)) { String debuggerPkg = getDebuggerScriptPack(swf).getClassPath().packageStr.toRawString(); @@ -111,7 +132,7 @@ public class DebuggerTools { swf.tags.remove((Tag) tag); swf.getAbcList().remove(tag); - //Change all debugger calls to normal trace + //Change all debugger calls to normal trace / Loader for (ABCContainerTag ct : swf.getAbcList()) { ABC a = ct.getABC(); for (int i = 1; i < a.constants.constant_multiname.size(); i++) { @@ -124,6 +145,9 @@ public class DebuggerTools { m.name_index = a.constants.getStringId("trace", true); m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId("", true)), 0, true); ((Tag) ct).setModified(true); + } else if (isDebuggerClass(packageStr, "DebugLoader")) { + m.name_index = a.constants.getStringId("Loader", true); + m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId("flash.display", true)), 0, true); } } } @@ -136,7 +160,11 @@ public class DebuggerTools { //load debug swf SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false); - ABCContainerTag firstAbc = swf.getAbcList().get(0); + List al = swf.getAbcList(); + ABCContainerTag firstAbc = al.isEmpty() ? null : al.get(0); + if (firstAbc == null) { //nothing to instrument? + return; + } String newdebuggerpkg = DEBUGGER_PACKAGE; if (Configuration.randomDebuggerPackage.get()) { @@ -174,7 +202,7 @@ public class DebuggerTools { initDebugger(); } - private static void initDebugger() { + public static Debugger initDebugger() { if (debugger == null) { synchronized (Main.class) { if (debugger == null) { @@ -184,6 +212,7 @@ public class DebuggerTools { } } } + return debugger; } public static void debuggerShowLog() { diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf b/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf index 4eeec885b8fb64d77935a1aa15d2ab16ced128de..2bd76b1576dcd7cf9cb33f5e41bfb78f25660101 100644 GIT binary patch literal 2322 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 literal 1748 zcmV;_1}phPS5py%3;+OloTXLWa@)og-d+4G0g~dMOe;#9(2{J$Hc5b_NJ*@$m?kAx znJRQGwe<}ZuE?c?1O!+B)X!Brev({uI+KS;FZuwaGj(60kI)%)7odJ@sTn1~NZ{GC z-}m9{w+D+8Abkx$>^lHvAZR3J004hU#U%jNoNllBs6?~YWuvEahn_d6YTEJf zasIfJx19s6u)4ac=|!zr%rQjHJ+(Y?lC#|Tx%G^%(4cO|F$SJtTNyqk`}WX#IyX0w zJ?RfFWGy#Oy7oTJckI4)LIzqPuWMX~fvRoR#_ zX6ieYOfIuOG|XJYI(I6Jn}wyWw)?W)t9TK<*VfPuoJr7HF~GFB3~jiYuX1+-p<=@=fc{-&@uh}>UK10 z(mu63m)TqJ?d^7|J=^IMZ=DPVrqLl>P&>)Fhj!=NV{$}uJ#O`yb_x8YC9#!lZ~yd$ z_xsv8+Vx)1-cO_5-O~ZpUQyQ`IvvX3^OJ_z-mY$0u1Bm6-D<3}MBXsE)y;CHqHip% zEN_-KHkJy7mF3b#t@vCoR8}j+&B~JR{rl8&wT9gpa^EIu-JhX$g?g^mbc_Rowd@V5 zg{9?6t-MrTSt-}K>hnTrvsT~O*sM2}8%w47x#|rP7qwEyIHKK6$L{;PFd&Xgxl>Q) z&aL7$`Tkao>o(O&D`kDTsMl7@jhh#Cje4%u{Ur;!Mm<-ve~nH5S0ZzzqB2B0?2S~UO7fS$PdE@kn+ zFsYOG-y)XSA08Y~C)VIW-L@>+;ZFl{bN?F_mTtkVe!x}y@isB6=mcoE1CyL8+xC$` z>!vZt-CC8aKvxN-Eb7TS>=d9L{Ik?E9M{9o**QvyB^#FE(XMEbK9zSo$FL3*ms;K5 z59yGGj~zA{WK|AiB{1tletO$Ih;%3QyG%><2fGgGOu`x~%?tZs@a(Ce7<%GShwWry zV-jpx?6=2w3OOQ%N%l<|?gXNF(>@S8#55(s)gpm{d+K_$AE}c8**8qXGpMU_pQyuM z4*8`yJlL{ujd^-RUxx$E&@)U|d4B5An&XhusK16k>~8XmE1T3h@D3F}$usIj1U|60qNi)X> zL-+9h=_EUx+IO;_W`*&0&AVv)TUH^vkTB9;uxb!P#zuN8F>WScYkJ(AhAb^yBE;)j znJZe-B~s>Ea|}7t`zX8c{o_OkfJgq|!S_jaAhzMS8Hb#NFG(T9N=}XRJ^V*N@LuR4 z3GJziL}gP7k_53d((k`{*T!%D6(APCzsGMnVm!*`_r)LQ-@I$Z-!j>vC?x)Kb`}yt z0;8&;Acz&Vtl2MT!Cz?~{el-yWR7zc=p%!^?O9uwnC4&JHs#MY$Di zMgbc|n3Vi-r2pyhJDtLDAGXyb+uj#@VG2!1!h7mNqV7p8`AZoPsV%iX>t&vWoA(ig z3!u;LIoL;SDa*(vYR(}a{{o*_CDrwi4M@zY(%k)(Nd-_BYKWCncGdvN+Ny;98IL_G7*M qL~m#Hc1~}L?C&+a7hH$j!7oz9$(wMCPfY&e69b+x#{U4sv0=MLy<7