mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-17 14:58:57 +00:00
Added #2090 Support for Mochicrypt packed binarydata tags - loading SWF as subtree
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- [#2090] Support for Mochicrypt packed binarydata tags - loading SWF as subtree
|
||||
|
||||
## [19.0.0] - 2023-10-01
|
||||
### Added
|
||||
@@ -3118,6 +3120,7 @@ Major version of SWF to XML export changed to 2.
|
||||
[alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9
|
||||
[alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8
|
||||
[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7
|
||||
[#2090]: https://www.free-decompiler.com/flash/issues/2090
|
||||
[#1449]: https://www.free-decompiler.com/flash/issues/1449
|
||||
[#2070]: https://www.free-decompiler.com/flash/issues/2070
|
||||
[#2073]: https://www.free-decompiler.com/flash/issues/2073
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2023 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.packers;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MochiCryptPacker implements Packer {
|
||||
|
||||
@Override
|
||||
public Boolean suitableForBinaryData(DefineBinaryDataTag dataTag) {
|
||||
if (dataTag.getClassNames().contains("mochicrypt.Payload")) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decrypt(InputStream is, OutputStream os) throws IOException {
|
||||
byte payload[] = Helper.readStream(is);
|
||||
if (!handleXor(payload)) {
|
||||
return false;
|
||||
}
|
||||
Helper.copyStream(new InflaterInputStream(new ByteArrayInputStream(payload)), os);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleXor(byte payload[]) {
|
||||
if (payload.length < 32) {
|
||||
return false;
|
||||
}
|
||||
int[] S = new int[256];
|
||||
int i = 0;
|
||||
int j;
|
||||
int k;
|
||||
int n;
|
||||
int u;
|
||||
int v;
|
||||
|
||||
n = payload.length - 32;
|
||||
while (i < 256) {
|
||||
S[i] = i;
|
||||
i++;
|
||||
}
|
||||
j = 0;
|
||||
i = 0;
|
||||
while (i < 256) {
|
||||
j = (j + S[i] + (payload[n + (i & 31)] & 0xff) ) & 255;
|
||||
u = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = u;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (n > 0x20000) {
|
||||
n = 0x20000;
|
||||
}
|
||||
j = 0;
|
||||
i = 0;
|
||||
k = 0;
|
||||
while (k < n) {
|
||||
i = (i + 1) & 255;
|
||||
u = S[i];
|
||||
j = (j + u) & 255;
|
||||
v = S[j];
|
||||
S[i] = v;
|
||||
S[j] = u;
|
||||
payload[k] = (byte) ((payload[k] & 0xff) ^ S[u + v & 255]);
|
||||
k++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encrypt(InputStream is, OutputStream os) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream def = new DeflaterOutputStream(baos);
|
||||
Helper.copyStream(is, def);
|
||||
def.finish();
|
||||
byte payload[] = baos.toByteArray();
|
||||
|
||||
if (!handleXor(payload)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
os.write(payload);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MochiCrypt";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2023 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.packers;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Packer interface.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface Packer {
|
||||
|
||||
/**
|
||||
* Is this DefineBinaryData packed with this packer?
|
||||
*
|
||||
* @param dataTag
|
||||
* @return true = it definitely is encrypted with this, false = it definitely is not encrypted with this, null = it is unknown that it will work
|
||||
*/
|
||||
public Boolean suitableForBinaryData(DefineBinaryDataTag dataTag);
|
||||
|
||||
/**
|
||||
* Unpack the data
|
||||
* @param is
|
||||
* @param os
|
||||
* @return True if it was unpacked correctly, False if it is not suitable for unpacking or an error happened.
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public boolean decrypt(InputStream is, OutputStream os) throws IOException;
|
||||
|
||||
/**
|
||||
* Pack the data
|
||||
* @param is
|
||||
* @param os
|
||||
* @return True if packed successfully, False if error happened.
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public boolean encrypt(InputStream is, OutputStream os) throws IOException;
|
||||
|
||||
/**
|
||||
* Human readable name of this packer
|
||||
* @return
|
||||
*/
|
||||
public String getName();
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys;
|
||||
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
|
||||
import com.jpexs.decompiler.flash.packers.MochiCryptPacker;
|
||||
import com.jpexs.decompiler.flash.packers.Packer;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
@@ -58,6 +60,13 @@ public class DefineBinaryDataTag extends CharacterTag {
|
||||
@Internal
|
||||
public SWF innerSwf;
|
||||
|
||||
@Internal
|
||||
public Packer usedPacker;
|
||||
|
||||
private final Packer[] PACKERS = {
|
||||
new MochiCryptPacker()
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -81,10 +90,10 @@ public class DefineBinaryDataTag extends CharacterTag {
|
||||
binaryData = sis.readByteRangeEx(sis.available(), "binaryData");
|
||||
|
||||
if (Configuration.autoLoadEmbeddedSwfs.get()) {
|
||||
String path = getSwf().getShortPathTitle()+"/DefineBinaryData (" + getCharacterId() + ")";
|
||||
String path = getSwf().getShortPathTitle() + "/DefineBinaryData (" + getCharacterId() + ")";
|
||||
SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(path);
|
||||
String charset = conf == null ? Charset.defaultCharset().name() : conf.getCustomData(CustomConfigurationKeys.KEY_CHARSET, Charset.defaultCharset().name());
|
||||
|
||||
|
||||
try {
|
||||
InputStream is = new ByteArrayInputStream(binaryData.getArray(), binaryData.getPos(), binaryData.getLength());
|
||||
SWF bswf = new SWF(is, null, "(SWF Data)", Configuration.parallelSpeedUp.get(), charset);
|
||||
@@ -119,6 +128,15 @@ public class DefineBinaryDataTag extends CharacterTag {
|
||||
this.tag = characterId;
|
||||
}
|
||||
|
||||
public void detectPacker() {
|
||||
for (Packer packer : PACKERS) {
|
||||
if (packer.suitableForBinaryData(this) == Boolean.TRUE) {
|
||||
usedPacker = packer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSwfData() {
|
||||
try {
|
||||
if (binaryData.getLength() > 8) {
|
||||
@@ -129,8 +147,10 @@ public class DefineBinaryDataTag extends CharacterTag {
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
detectPacker();
|
||||
|
||||
return usedPacker != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.jpexs.decompiler.flash.gui;
|
||||
|
||||
import com.jpexs.decompiler.flash.gui.hexview.HexView;
|
||||
import com.jpexs.decompiler.flash.packers.MochiCryptPacker;
|
||||
import com.jpexs.decompiler.flash.packers.Packer;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
@@ -44,6 +46,8 @@ public final class BinaryPanel extends JPanel {
|
||||
private DefineBinaryDataTag binaryDataTag = null;
|
||||
|
||||
private final MainPanel mainPanel;
|
||||
|
||||
private final JLabel swfInsideLabel;
|
||||
|
||||
public BinaryPanel(final MainPanel mainPanel) {
|
||||
super(new BorderLayout());
|
||||
@@ -64,10 +68,13 @@ public final class BinaryPanel extends JPanel {
|
||||
setBinaryData(binaryDataTag);
|
||||
}
|
||||
});*/
|
||||
|
||||
swfInsideLabel = new JLabel(AppStrings.translate("binarydata.swfInside"));
|
||||
|
||||
swfInsidePanel = new JPanel();
|
||||
swfInsidePanel.setBackground(new Color(253, 205, 137));
|
||||
swfInsidePanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
swfInsidePanel.add(new JLabel(AppStrings.translate("binarydata.swfInside")));
|
||||
swfInsidePanel.add(swfInsideLabel);
|
||||
swfInsidePanel.setFocusable(true);
|
||||
swfInsidePanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
|
||||
swfInsidePanel.addMouseListener(new MouseAdapter() {
|
||||
@@ -88,7 +95,15 @@ public final class BinaryPanel extends JPanel {
|
||||
data = binaryDataTag == null ? null : binaryDataTag.binaryData.getRangeData();
|
||||
if (data != null) {
|
||||
hexEditor.setData(data, null, null);
|
||||
swfInsidePanel.setVisible(binaryDataTag.innerSwf == null && binaryDataTag.isSwfData());
|
||||
boolean isSwfData = binaryDataTag.isSwfData();
|
||||
if (isSwfData) {
|
||||
if (binaryDataTag.usedPacker != null) {
|
||||
swfInsideLabel.setText(AppStrings.translate("binarydata.swfInside.packer").replace("%packer%", binaryDataTag.usedPacker.getName()));
|
||||
} else {
|
||||
swfInsideLabel.setText(AppStrings.translate("binarydata.swfInside"));
|
||||
}
|
||||
}
|
||||
swfInsidePanel.setVisible(binaryDataTag.innerSwf == null && isSwfData);
|
||||
} else {
|
||||
hexEditor.setData(new byte[0], null, null);
|
||||
swfInsidePanel.setVisible(false);
|
||||
|
||||
@@ -162,7 +162,13 @@ public abstract class MainFrameMenu implements MenuBuilder {
|
||||
try {
|
||||
openable.saveTo(baos);
|
||||
SWF swf = (SWF) openable;
|
||||
swf.binaryData.binaryData = new ByteArrayRange(baos.toByteArray());
|
||||
byte data[] = baos.toByteArray();
|
||||
if (swf.binaryData.usedPacker != null) {
|
||||
ByteArrayOutputStream encBaos = new ByteArrayOutputStream();
|
||||
swf.binaryData.usedPacker.encrypt(new ByteArrayInputStream(data), encBaos);
|
||||
data = encBaos.toByteArray();
|
||||
}
|
||||
swf.binaryData.binaryData = new ByteArrayRange(data);
|
||||
swf.binaryData.setModified(true);
|
||||
saved = saveOpenable(swf.binaryData.getSwf()); //save parent swf
|
||||
} catch (IOException ex) {
|
||||
|
||||
@@ -4978,8 +4978,16 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
try {
|
||||
SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(path);
|
||||
String charset = conf == null ? Charset.defaultCharset().name() : conf.getCustomData(CustomConfigurationKeys.KEY_CHARSET, Charset.defaultCharset().name());
|
||||
InputStream is = new ByteArrayInputStream(binaryDataTag.binaryData.getRangeData());
|
||||
SWF bswf = new SWF(is, null, "(SWF Data)", new ProgressListener() {
|
||||
byte data[] = binaryDataTag.binaryData.getRangeData();
|
||||
String packerAdd = "";
|
||||
if (binaryDataTag.usedPacker != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
binaryDataTag.usedPacker.decrypt(new ByteArrayInputStream(data), baos);
|
||||
data = baos.toByteArray();
|
||||
packerAdd = " - " + binaryDataTag.usedPacker.getName();
|
||||
}
|
||||
InputStream is = new ByteArrayInputStream(data);
|
||||
SWF bswf = new SWF(is, null, "(SWF Data" + packerAdd +")", new ProgressListener() {
|
||||
@Override
|
||||
public void progress(int p) {
|
||||
Main.loadingDialog.setPercent(p);
|
||||
|
||||
@@ -1157,4 +1157,7 @@ menu.tools.abcexplorer = ABC Explorer
|
||||
|
||||
contextmenu.abcexplorer = Explore ABC
|
||||
|
||||
button.abcexploretrait = Show trait in ABC Explorer
|
||||
button.abcexploretrait = Show trait in ABC Explorer
|
||||
|
||||
#after 19.0.0
|
||||
binarydata.swfInside.packer = It looks like there is SWF inside this binary data tag packed with %packer%. Click here to unpack the SWF and load it as subtree.
|
||||
|
||||
@@ -1142,4 +1142,7 @@ menu.tools.abcexplorer = Pr\u016fzkumn\u00edk ABC
|
||||
|
||||
contextmenu.abcexplorer = Prozkoumat ABC
|
||||
|
||||
button.abcexploretrait = Zobrazit vlastnost v pr\u016fzkumn\u00edku ABC
|
||||
button.abcexploretrait = Zobrazit vlastnost v pr\u016fzkumn\u00edku ABC
|
||||
|
||||
#after 19.0.0
|
||||
binarydata.swfInside.packer = Vypad\u00e1 to, \u017ee uvnit\u0159 v tomto BinaryData tagu se nach\u00e1z\u00ed SWF soubor zabalen\u00fd pomoc\u00ed %packer%. Klikn\u011bte zde pro jeho rozbalen\u00ed a na\u010dten\u00ed jako podstrom.
|
||||
|
||||
Reference in New Issue
Block a user