mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 04:11:13 +00:00
jump to resources view from hex view
This commit is contained in:
@@ -1,308 +1,308 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.debugger;
|
||||
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Debugger {
|
||||
|
||||
private static final Set<DebugListener> listeners = new HashSet<>();
|
||||
|
||||
public synchronized void addMessageListener(DebugListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public synchronized void removeMessageListener(DebugListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
private static class DebugHandler extends Thread {
|
||||
|
||||
private final Socket s;
|
||||
|
||||
private final int serverPort;
|
||||
|
||||
private static int maxid = 0;
|
||||
|
||||
private final int id;
|
||||
|
||||
public boolean finished = false;
|
||||
|
||||
private final Map<String, String> 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;
|
||||
id = maxid++;
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
throw new EOFException();
|
||||
}
|
||||
int len2 = is.read();
|
||||
if (len2 == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
len = (len << 8) + len2;
|
||||
|
||||
byte buf[] = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
int rd = is.read();
|
||||
if (rd == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
buf[i] = (byte) rd;
|
||||
}
|
||||
return new String(buf, Utf8Helper.charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String clientName = Integer.toString(id);
|
||||
try (InputStream is = s.getInputStream()) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
int c;
|
||||
do {
|
||||
c = is.read();
|
||||
if (c != 0) {
|
||||
baos.write(c);
|
||||
}
|
||||
|
||||
} while (c > 0);
|
||||
String ret = baos.toString("UTF-8");
|
||||
|
||||
if (ret.equals("<policy-file-request/>")) {
|
||||
try (OutputStream os = s.getOutputStream()) {
|
||||
os.write(("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + serverPort + "\" /></cross-domain-policy>").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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
finished = true;
|
||||
for (DebugListener l : listeners) {
|
||||
l.onFinish(clientName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DebugServerThread extends Thread {
|
||||
|
||||
private final int port;
|
||||
|
||||
private ServerSocket ss;
|
||||
|
||||
private final Map<Integer, DebugHandler> handlers = new WeakHashMap<>();
|
||||
|
||||
public DebugServerThread(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ss = new ServerSocket(port, 50, InetAddress.getByName("localhost"));
|
||||
ss.setReuseAddress(true);
|
||||
while (true) {
|
||||
Socket s = ss.accept();
|
||||
DebugHandler h = new DebugHandler(port, s);
|
||||
handlers.put(h.id, h);
|
||||
h.start();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final int port;
|
||||
|
||||
public Debugger(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
private DebugServerThread server = null;
|
||||
|
||||
public synchronized void start() {
|
||||
if (server == null) {
|
||||
server = new DebugServerThread(port);
|
||||
server.start();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning() {
|
||||
return server != null;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
if (server != null) {
|
||||
try {
|
||||
server.ss.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
for (DebugHandler h : server.handlers.values()) {
|
||||
h.cancel();
|
||||
}
|
||||
server.handlers.clear();
|
||||
server = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.debugger;
|
||||
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Debugger {
|
||||
|
||||
private static final Set<DebugListener> listeners = new HashSet<>();
|
||||
|
||||
public synchronized void addMessageListener(DebugListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public synchronized void removeMessageListener(DebugListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
private static class DebugHandler extends Thread {
|
||||
|
||||
private final Socket s;
|
||||
|
||||
private final int serverPort;
|
||||
|
||||
private static int maxid = 0;
|
||||
|
||||
private final int id;
|
||||
|
||||
public boolean finished = false;
|
||||
|
||||
private final Map<String, String> 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;
|
||||
id = maxid++;
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
throw new EOFException();
|
||||
}
|
||||
int len2 = is.read();
|
||||
if (len2 == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
len = (len << 8) + len2;
|
||||
|
||||
byte[] buf = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
int rd = is.read();
|
||||
if (rd == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
buf[i] = (byte) rd;
|
||||
}
|
||||
return new String(buf, Utf8Helper.charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String clientName = Integer.toString(id);
|
||||
try (InputStream is = s.getInputStream()) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
int c;
|
||||
do {
|
||||
c = is.read();
|
||||
if (c != 0) {
|
||||
baos.write(c);
|
||||
}
|
||||
|
||||
} while (c > 0);
|
||||
String ret = baos.toString("UTF-8");
|
||||
|
||||
if (ret.equals("<policy-file-request/>")) {
|
||||
try (OutputStream os = s.getOutputStream()) {
|
||||
os.write(("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + serverPort + "\" /></cross-domain-policy>").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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
finished = true;
|
||||
for (DebugListener l : listeners) {
|
||||
l.onFinish(clientName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DebugServerThread extends Thread {
|
||||
|
||||
private final int port;
|
||||
|
||||
private ServerSocket ss;
|
||||
|
||||
private final Map<Integer, DebugHandler> handlers = new WeakHashMap<>();
|
||||
|
||||
public DebugServerThread(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ss = new ServerSocket(port, 50, InetAddress.getByName("localhost"));
|
||||
ss.setReuseAddress(true);
|
||||
while (true) {
|
||||
Socket s = ss.accept();
|
||||
DebugHandler h = new DebugHandler(port, s);
|
||||
handlers.put(h.id, h);
|
||||
h.start();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final int port;
|
||||
|
||||
public Debugger(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
private DebugServerThread server = null;
|
||||
|
||||
public synchronized void start() {
|
||||
if (server == null) {
|
||||
server = new DebugServerThread(port);
|
||||
server.start();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning() {
|
||||
return server != null;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
if (server != null) {
|
||||
try {
|
||||
server.ss.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
for (DebugHandler h : server.handlers.values()) {
|
||||
h.cancel();
|
||||
}
|
||||
server.handlers.clear();
|
||||
server = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,247 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.debugger;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.gui.DebugLogDialog;
|
||||
import com.jpexs.decompiler.flash.gui.Main;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DebuggerTools {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DebuggerTools.class.getName());
|
||||
|
||||
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
|
||||
|
||||
private static volatile Debugger debugger;
|
||||
|
||||
private static ScriptPack getDebuggerScriptPack(SWF swf) {
|
||||
List<ABC> allAbcList = new ArrayList<>();
|
||||
for (ABCContainerTag ac : swf.getAbcList()) {
|
||||
allAbcList.add(ac.getABC());
|
||||
}
|
||||
for (ABCContainerTag ac : swf.getAbcList()) {
|
||||
ABC a = ac.getABC();
|
||||
for (ScriptPack m : a.getScriptPacks(DEBUGGER_PACKAGE, allAbcList)) {
|
||||
if (isDebuggerClass(m.getClassPath().packageStr.toRawString(), null)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasDebugger(SWF swf) {
|
||||
return getDebuggerScriptPack(swf) != null;
|
||||
}
|
||||
|
||||
private static boolean isDebuggerClass(String tested, String cls) {
|
||||
if (tested == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// fast check, because dynamic regex compile and match is expensive
|
||||
if (!tested.startsWith(DEBUGGER_PACKAGE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cls == null) {
|
||||
cls = "";
|
||||
} else {
|
||||
cls = "\\." + Pattern.quote(cls);
|
||||
}
|
||||
|
||||
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.getMultinameCount(); i++) {
|
||||
Multiname m = a.constants.getMultiname(i);
|
||||
if ("flash.display.Loader".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("DebugLoader", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.getDefinitionByName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugGetDefinitionByName", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.getQualifiedClassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugGetQualifiedClassName", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.getQualifiedSuperclassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugGetQualifiedSuperclassName", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.describeType".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugDescribeType", true);
|
||||
((Tag) ct).setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceTraceCalls(SWF swf, String fname) {
|
||||
if (hasDebugger(swf)) {
|
||||
String debuggerPkg = getDebuggerScriptPack(swf).getClassPath().packageStr.toRawString();
|
||||
//change trace to fname
|
||||
for (ABCContainerTag ct : swf.getAbcList()) {
|
||||
ABC a = ct.getABC();
|
||||
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
|
||||
Multiname m = a.constants.getMultiname(i);
|
||||
if ("trace".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId(fname, true);
|
||||
((Tag) ct).setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void switchDebugger(SWF swf) {
|
||||
int port = Configuration.debuggerPort.get();
|
||||
ScriptPack found = getDebuggerScriptPack(swf);
|
||||
if (found != null) {
|
||||
ABCContainerTag tag = found.abc.parentTag;
|
||||
swf.removeTag((Tag) tag);
|
||||
swf.getAbcList().remove(tag);
|
||||
|
||||
//Change all debugger calls to normal trace / Loader
|
||||
for (ABCContainerTag ct : swf.getAbcList()) {
|
||||
ABC a = ct.getABC();
|
||||
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
|
||||
Multiname m = a.constants.getMultiname(i);
|
||||
String packageStr = m.getNameWithNamespace(a.constants).toString();
|
||||
if (isDebuggerClass(packageStr, "debugTrace")
|
||||
|| isDebuggerClass(packageStr, "debugAlert")
|
||||
|| isDebuggerClass(packageStr, "debugSocket")
|
||||
|| isDebuggerClass(packageStr, "debugConsole")) {
|
||||
m.name_index = a.constants.getStringId("trace", true);
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 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(Namespace.KIND_PACKAGE, "flash.display", 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Random rnd = new Random();
|
||||
byte rb[] = new byte[16];
|
||||
rnd.nextBytes(rb);
|
||||
String rhex = Helper.byteArrayToHex(rb);
|
||||
try {
|
||||
//load debug swf
|
||||
SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false);
|
||||
|
||||
List<ABCContainerTag> 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()) {
|
||||
newdebuggerpkg += ".pkg" + rhex;
|
||||
}
|
||||
|
||||
//add debug ABC tags to main SWF
|
||||
for (ABCContainerTag ds : debugSWF.getAbcList()) {
|
||||
ABC a = ds.getABC();
|
||||
//Append random hex to Debugger package name
|
||||
for (int i = 1; i < a.constants.getNamespaceCount(); i++) {
|
||||
if (a.constants.getNamespace(i).hasName(DEBUGGER_PACKAGE, a.constants)) {
|
||||
a.constants.getNamespace(i).name_index = a.constants.getStringId(newdebuggerpkg, true);
|
||||
}
|
||||
}
|
||||
//Set debugger port to actually set port
|
||||
for (int i = 0; i < a.constants.getIntCount(); i++) {
|
||||
if (a.constants.getInt(i) == 123456L) {
|
||||
a.constants.setInt(i, (long) port);
|
||||
}
|
||||
}
|
||||
//Add to target SWF
|
||||
((Tag) ds).setSwf(swf);
|
||||
swf.addTag((Tag) ds, (Tag) firstAbc);
|
||||
swf.getAbcList().add(swf.getAbcList().indexOf(firstAbc), ds);
|
||||
((Tag) ds).setModified(true);
|
||||
|
||||
//To allow socket connection to FFDec. Is this safe?
|
||||
FileAttributesTag ft = swf.getFileAttributes();
|
||||
ft.useNetwork = true;
|
||||
ft.setModified(true);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error while attaching debugger", ex);
|
||||
//ignore
|
||||
}
|
||||
|
||||
}
|
||||
initDebugger();
|
||||
}
|
||||
|
||||
public static Debugger initDebugger() {
|
||||
if (debugger == null) {
|
||||
synchronized (Main.class) {
|
||||
if (debugger == null) {
|
||||
Debugger dbg = new Debugger(Configuration.debuggerPort.get());
|
||||
dbg.start();
|
||||
debugger = dbg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return debugger;
|
||||
}
|
||||
|
||||
public static void debuggerShowLog() {
|
||||
initDebugger();
|
||||
if (Main.debugDialog == null) {
|
||||
Main.debugDialog = new DebugLogDialog(debugger);
|
||||
}
|
||||
Main.debugDialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.debugger;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.gui.DebugLogDialog;
|
||||
import com.jpexs.decompiler.flash.gui.Main;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DebuggerTools {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DebuggerTools.class.getName());
|
||||
|
||||
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
|
||||
|
||||
private static volatile Debugger debugger;
|
||||
|
||||
private static ScriptPack getDebuggerScriptPack(SWF swf) {
|
||||
List<ABC> allAbcList = new ArrayList<>();
|
||||
for (ABCContainerTag ac : swf.getAbcList()) {
|
||||
allAbcList.add(ac.getABC());
|
||||
}
|
||||
for (ABCContainerTag ac : swf.getAbcList()) {
|
||||
ABC a = ac.getABC();
|
||||
for (ScriptPack m : a.getScriptPacks(DEBUGGER_PACKAGE, allAbcList)) {
|
||||
if (isDebuggerClass(m.getClassPath().packageStr.toRawString(), null)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasDebugger(SWF swf) {
|
||||
return getDebuggerScriptPack(swf) != null;
|
||||
}
|
||||
|
||||
private static boolean isDebuggerClass(String tested, String cls) {
|
||||
if (tested == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// fast check, because dynamic regex compile and match is expensive
|
||||
if (!tested.startsWith(DEBUGGER_PACKAGE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cls == null) {
|
||||
cls = "";
|
||||
} else {
|
||||
cls = "\\." + Pattern.quote(cls);
|
||||
}
|
||||
|
||||
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.getMultinameCount(); i++) {
|
||||
Multiname m = a.constants.getMultiname(i);
|
||||
if ("flash.display.Loader".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("DebugLoader", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.getDefinitionByName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugGetDefinitionByName", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.getQualifiedClassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugGetQualifiedClassName", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.getQualifiedSuperclassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugGetQualifiedSuperclassName", true);
|
||||
((Tag) ct).setModified(true);
|
||||
} else if ("flash.utils.describeType".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId("debugDescribeType", true);
|
||||
((Tag) ct).setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceTraceCalls(SWF swf, String fname) {
|
||||
if (hasDebugger(swf)) {
|
||||
String debuggerPkg = getDebuggerScriptPack(swf).getClassPath().packageStr.toRawString();
|
||||
//change trace to fname
|
||||
for (ABCContainerTag ct : swf.getAbcList()) {
|
||||
ABC a = ct.getABC();
|
||||
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
|
||||
Multiname m = a.constants.getMultiname(i);
|
||||
if ("trace".equals(m.getNameWithNamespace(a.constants).toRawString())) {
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
|
||||
m.name_index = a.constants.getStringId(fname, true);
|
||||
((Tag) ct).setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void switchDebugger(SWF swf) {
|
||||
int port = Configuration.debuggerPort.get();
|
||||
ScriptPack found = getDebuggerScriptPack(swf);
|
||||
if (found != null) {
|
||||
ABCContainerTag tag = found.abc.parentTag;
|
||||
swf.removeTag((Tag) tag);
|
||||
swf.getAbcList().remove(tag);
|
||||
|
||||
//Change all debugger calls to normal trace / Loader
|
||||
for (ABCContainerTag ct : swf.getAbcList()) {
|
||||
ABC a = ct.getABC();
|
||||
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
|
||||
Multiname m = a.constants.getMultiname(i);
|
||||
String packageStr = m.getNameWithNamespace(a.constants).toString();
|
||||
if (isDebuggerClass(packageStr, "debugTrace")
|
||||
|| isDebuggerClass(packageStr, "debugAlert")
|
||||
|| isDebuggerClass(packageStr, "debugSocket")
|
||||
|| isDebuggerClass(packageStr, "debugConsole")) {
|
||||
m.name_index = a.constants.getStringId("trace", true);
|
||||
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 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(Namespace.KIND_PACKAGE, "flash.display", 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Random rnd = new Random();
|
||||
byte[] rb = new byte[16];
|
||||
rnd.nextBytes(rb);
|
||||
String rhex = Helper.byteArrayToHex(rb);
|
||||
try {
|
||||
//load debug swf
|
||||
SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false);
|
||||
|
||||
List<ABCContainerTag> 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()) {
|
||||
newdebuggerpkg += ".pkg" + rhex;
|
||||
}
|
||||
|
||||
//add debug ABC tags to main SWF
|
||||
for (ABCContainerTag ds : debugSWF.getAbcList()) {
|
||||
ABC a = ds.getABC();
|
||||
//Append random hex to Debugger package name
|
||||
for (int i = 1; i < a.constants.getNamespaceCount(); i++) {
|
||||
if (a.constants.getNamespace(i).hasName(DEBUGGER_PACKAGE, a.constants)) {
|
||||
a.constants.getNamespace(i).name_index = a.constants.getStringId(newdebuggerpkg, true);
|
||||
}
|
||||
}
|
||||
//Set debugger port to actually set port
|
||||
for (int i = 0; i < a.constants.getIntCount(); i++) {
|
||||
if (a.constants.getInt(i) == 123456L) {
|
||||
a.constants.setInt(i, (long) port);
|
||||
}
|
||||
}
|
||||
//Add to target SWF
|
||||
((Tag) ds).setSwf(swf);
|
||||
swf.addTag((Tag) ds, (Tag) firstAbc);
|
||||
swf.getAbcList().add(swf.getAbcList().indexOf(firstAbc), ds);
|
||||
((Tag) ds).setModified(true);
|
||||
|
||||
//To allow socket connection to FFDec. Is this safe?
|
||||
FileAttributesTag ft = swf.getFileAttributes();
|
||||
ft.useNetwork = true;
|
||||
ft.setModified(true);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error while attaching debugger", ex);
|
||||
//ignore
|
||||
}
|
||||
|
||||
}
|
||||
initDebugger();
|
||||
}
|
||||
|
||||
public static Debugger initDebugger() {
|
||||
if (debugger == null) {
|
||||
synchronized (Main.class) {
|
||||
if (debugger == null) {
|
||||
Debugger dbg = new Debugger(Configuration.debuggerPort.get());
|
||||
dbg.start();
|
||||
debugger = dbg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return debugger;
|
||||
}
|
||||
|
||||
public static void debuggerShowLog() {
|
||||
initDebugger();
|
||||
if (Main.debugDialog == null) {
|
||||
Main.debugDialog = new DebugLogDialog(debugger);
|
||||
}
|
||||
Main.debugDialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user