Added #2090 Support for Mochicrypt packed binarydata tags - loading SWF as subtree

This commit is contained in:
Jindra Petřík
2023-10-02 22:19:52 +02:00
parent 0725f13f5d
commit 8a92a273a5
9 changed files with 250 additions and 11 deletions

View File

@@ -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";
}
}

View File

@@ -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();
}

View File

@@ -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