mirror of
https://github.com/revanced/Apktool.git
synced 2024-08-28 18:16:41 +02:00
Remove SnakeYAML for manual YAML Parser (#3191)
* Simple straitforward yaml serialization with minimal needed functionality * Consolidate ApkInfo tests in the package brut.androlib.apk, unify interface YamlReader and add ApkInfoSerializationTest read -> write -> read test * remove dependencies from snakeyaml * remove unused methods * correct indent test value * correct style with curly braces * add test item with hieroglyph
This commit is contained in:
parent
da6ed0f729
commit
62b9eedb9e
@ -89,7 +89,6 @@ tasks.register('proguard', ProGuardTask) {
|
||||
dontwarn 'javax.xml.xpath.**'
|
||||
dontnote '**'
|
||||
// between Java 1.8 and 1.9, the signature of `flip()` changed, which trips up proguard.
|
||||
dontwarn 'org.yaml.snakeyaml.scanner.ScannerImpl'
|
||||
|
||||
def outPath = jar.getDestinationDirectory().getAsFile().get().toString()
|
||||
def extension = jar.archiveExtension.get().toString()
|
||||
|
@ -39,7 +39,6 @@ dependencies {
|
||||
|
||||
implementation depends.baksmali
|
||||
implementation depends.smali
|
||||
implementation depends.snakeyaml
|
||||
implementation depends.xmlpull
|
||||
implementation depends.guava
|
||||
implementation depends.commons_lang
|
||||
|
@ -165,7 +165,7 @@ public class ApkDecoder {
|
||||
|
||||
copyRawFiles(outDir);
|
||||
copyUnknownFiles(apkInfo, outDir);
|
||||
Collection<String> mUncompressedFiles = new ArrayList<>();
|
||||
List<String> mUncompressedFiles = new ArrayList<>();
|
||||
recordUncompressedFiles(apkInfo, resourcesDecoder.getResFileMapping(), mUncompressedFiles);
|
||||
copyOriginalFiles(outDir);
|
||||
writeApkInfo(apkInfo, outDir);
|
||||
@ -220,11 +220,7 @@ public class ApkDecoder {
|
||||
}
|
||||
|
||||
private void writeApkInfo(ApkInfo apkInfo, File outDir) throws AndrolibException {
|
||||
try {
|
||||
apkInfo.save(new File(outDir, "apktool.yml"));
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
apkInfo.save(new File(outDir, "apktool.yml"));
|
||||
}
|
||||
|
||||
private void copyManifestRaw(File outDir)
|
||||
@ -376,7 +372,7 @@ public class ApkDecoder {
|
||||
|
||||
private void recordUncompressedFiles(ApkInfo apkInfo,
|
||||
Map<String, String> resFileMapping,
|
||||
Collection<String> uncompressedFilesOrExts)
|
||||
List<String> uncompressedFilesOrExts)
|
||||
throws AndrolibException {
|
||||
try {
|
||||
Directory unk = mApkFile.getDirectory();
|
||||
|
@ -21,18 +21,14 @@ import brut.androlib.exceptions.AndrolibException;
|
||||
import brut.androlib.res.data.ResConfigFlags;
|
||||
import brut.directory.DirectoryException;
|
||||
import brut.directory.FileDirectory;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ApkInfo {
|
||||
public class ApkInfo implements YamlSerializable {
|
||||
public String version;
|
||||
|
||||
private String apkFileName;
|
||||
@ -45,7 +41,7 @@ public class ApkInfo {
|
||||
public boolean sharedLibrary;
|
||||
public boolean sparseResources;
|
||||
public Map<String, String> unknownFiles;
|
||||
public Collection<String> doNotCompress;
|
||||
public List<String> doNotCompress;
|
||||
|
||||
/** @deprecated use {@link #resourcesAreCompressed} */
|
||||
public boolean compressionType;
|
||||
@ -54,26 +50,6 @@ public class ApkInfo {
|
||||
this.version = ApktoolProperties.getVersion();
|
||||
}
|
||||
|
||||
private static Yaml getYaml() {
|
||||
DumperOptions dumpOptions = new DumperOptions();
|
||||
dumpOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
|
||||
EscapedStringRepresenter representer = new EscapedStringRepresenter();
|
||||
PropertyUtils propertyUtils = representer.getPropertyUtils();
|
||||
propertyUtils.setSkipMissingProperties(true);
|
||||
|
||||
LoaderOptions loaderOptions = new LoaderOptions();
|
||||
loaderOptions.setCodePointLimit(10 * 1024 * 1024); // 10mb
|
||||
|
||||
return new Yaml(new ClassSafeConstructor(), representer, dumpOptions, loaderOptions);
|
||||
}
|
||||
|
||||
public void save(Writer output) {
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
getYaml().dump(this, output);
|
||||
}
|
||||
|
||||
public String checkTargetSdkVersionBounds() {
|
||||
int target = mapSdkShorthandToVersion(getTargetSdkVersion());
|
||||
|
||||
@ -157,28 +133,111 @@ public class ApkInfo {
|
||||
}
|
||||
}
|
||||
|
||||
public void save(File file) throws IOException {
|
||||
try(
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
|
||||
Writer writer = new BufferedWriter(outputStreamWriter)
|
||||
public void save(File file) throws AndrolibException {
|
||||
try (
|
||||
YamlWriter writer = new YamlWriter(new FileOutputStream(file));
|
||||
) {
|
||||
save(writer);
|
||||
write(writer);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new AndrolibException("File not found");
|
||||
} catch (Exception e) {
|
||||
throw new AndrolibException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static ApkInfo load(InputStream is) {
|
||||
return getYaml().loadAs(is, ApkInfo.class);
|
||||
public static ApkInfo load(InputStream is) throws AndrolibException {
|
||||
// return getYaml().loadAs(is, ApkInfo.class);
|
||||
YamlReader reader = new YamlReader(is);
|
||||
ApkInfo apkInfo = new ApkInfo();
|
||||
reader.readRoot(apkInfo);
|
||||
return apkInfo;
|
||||
}
|
||||
|
||||
public static ApkInfo load(File appDir)
|
||||
throws AndrolibException {
|
||||
try(
|
||||
InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml")
|
||||
InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml");
|
||||
) {
|
||||
return ApkInfo.load(in);
|
||||
} catch (DirectoryException | IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readItem(YamlReader reader) throws AndrolibException {
|
||||
YamlLine line = reader.getLine();
|
||||
switch (line.getKey()) {
|
||||
case "version": {
|
||||
this.version = line.getValue();
|
||||
break;
|
||||
}
|
||||
case "apkFileName": {
|
||||
this.apkFileName = line.getValue();
|
||||
break;
|
||||
}
|
||||
case "isFrameworkApk": {
|
||||
this.isFrameworkApk = line.getValueBool();
|
||||
break;
|
||||
}
|
||||
case "usesFramework": {
|
||||
this.usesFramework = new UsesFramework();
|
||||
reader.readObject(usesFramework);
|
||||
break;
|
||||
}
|
||||
case "sdkInfo": {
|
||||
reader.readMap(sdkInfo);
|
||||
break;
|
||||
}
|
||||
case "packageInfo": {
|
||||
this.packageInfo = new PackageInfo();
|
||||
reader.readObject(packageInfo);
|
||||
break;
|
||||
}
|
||||
case "versionInfo": {
|
||||
this.versionInfo = new VersionInfo();
|
||||
reader.readObject(versionInfo);
|
||||
break;
|
||||
}
|
||||
case "compressionType":
|
||||
case "resourcesAreCompressed": {
|
||||
this.resourcesAreCompressed = line.getValueBool();
|
||||
break;
|
||||
}
|
||||
case "sharedLibrary": {
|
||||
this.sharedLibrary = line.getValueBool();
|
||||
break;
|
||||
}
|
||||
case "sparseResources": {
|
||||
this.sparseResources = line.getValueBool();
|
||||
break;
|
||||
}
|
||||
case "unknownFiles": {
|
||||
this.unknownFiles = new LinkedHashMap<>();
|
||||
reader.readMap(unknownFiles);
|
||||
break;
|
||||
}
|
||||
case "doNotCompress": {
|
||||
this.doNotCompress = new ArrayList<>();
|
||||
reader.readStringList(doNotCompress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(YamlWriter writer) {
|
||||
writer.writeString("version", version);
|
||||
writer.writeString("apkFileName", apkFileName);
|
||||
writer.writeBool("isFrameworkApk", isFrameworkApk);
|
||||
writer.writeObject("usesFramework", usesFramework);
|
||||
writer.writeStringMap("sdkInfo", sdkInfo);
|
||||
writer.writeObject("packageInfo", packageInfo);
|
||||
writer.writeObject("versionInfo", versionInfo);
|
||||
writer.writeBool("resourcesAreCompressed", resourcesAreCompressed);
|
||||
writer.writeBool("sharedLibrary", sharedLibrary);
|
||||
writer.writeBool("sparseResources", sparseResources);
|
||||
writer.writeStringMap("unknownFiles", unknownFiles);
|
||||
writer.writeList("doNotCompress", doNotCompress);
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
* Copyright (C) 2010 Connor Tumbleson <connor.tumbleson@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package brut.androlib.apk;
|
||||
|
||||
import org.yaml.snakeyaml.constructor.AbstractConstruct;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode;
|
||||
import org.yaml.snakeyaml.nodes.Tag;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ClassSafeConstructor extends Constructor {
|
||||
protected final List<Class<?>> allowableClasses = new ArrayList<>();
|
||||
|
||||
public ClassSafeConstructor() {
|
||||
super(new LoaderOptions());
|
||||
this.yamlConstructors.put(Tag.STR, new ConstructStringEx());
|
||||
|
||||
this.allowableClasses.add(ApkInfo.class);
|
||||
this.allowableClasses.add(PackageInfo.class);
|
||||
this.allowableClasses.add(UsesFramework.class);
|
||||
this.allowableClasses.add(VersionInfo.class);
|
||||
}
|
||||
|
||||
protected Object newInstance(Node node) {
|
||||
if (this.yamlConstructors.containsKey(node.getTag()) || this.allowableClasses.contains(node.getType())) {
|
||||
return super.newInstance(node);
|
||||
}
|
||||
throw new YAMLException("Invalid Class attempting to be constructed: " + node.getTag());
|
||||
}
|
||||
|
||||
protected Object finalizeConstruction(Node node, Object data) {
|
||||
if (this.yamlConstructors.containsKey(node.getTag()) || this.allowableClasses.contains(node.getType())) {
|
||||
return super.finalizeConstruction(node, data);
|
||||
}
|
||||
|
||||
return this.newInstance(node);
|
||||
}
|
||||
|
||||
private class ConstructStringEx extends AbstractConstruct {
|
||||
public Object construct(Node node) {
|
||||
String val = constructScalar((ScalarNode) node);
|
||||
return YamlStringEscapeUtils.unescapeString(val);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,31 @@
|
||||
*/
|
||||
package brut.androlib.apk;
|
||||
|
||||
public class PackageInfo {
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
|
||||
public class PackageInfo implements YamlSerializable {
|
||||
public String forcedPackageId;
|
||||
public String renameManifestPackage;
|
||||
|
||||
@Override
|
||||
public void readItem(YamlReader reader) throws AndrolibException {
|
||||
YamlLine line = reader.getLine();
|
||||
switch (line.getKey()) {
|
||||
case "forcedPackageId": {
|
||||
forcedPackageId = line.getValue();
|
||||
break;
|
||||
}
|
||||
case "renameManifestPackage": {
|
||||
renameManifestPackage = line.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(YamlWriter writer) {
|
||||
writer.writeString("forcedPackageId", forcedPackageId);
|
||||
writer.writeString("renameManifestPackage", renameManifestPackage);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,9 +16,34 @@
|
||||
*/
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UsesFramework {
|
||||
public class UsesFramework implements YamlSerializable {
|
||||
public List<Integer> ids;
|
||||
public String tag;
|
||||
|
||||
@Override
|
||||
public void readItem(YamlReader reader) throws AndrolibException {
|
||||
YamlLine line = reader.getLine();
|
||||
switch (line.getKey()) {
|
||||
case "ids": {
|
||||
ids = new ArrayList<>();
|
||||
reader.readIntList(ids);
|
||||
break;
|
||||
}
|
||||
case "tag": {
|
||||
tag = line.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(YamlWriter writer) {
|
||||
writer.writeList("ids", ids);
|
||||
writer.writeString("tag", tag);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,30 @@
|
||||
*/
|
||||
package brut.androlib.apk;
|
||||
|
||||
public class VersionInfo {
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
|
||||
public class VersionInfo implements YamlSerializable {
|
||||
public String versionCode;
|
||||
public String versionName;
|
||||
|
||||
@Override
|
||||
public void readItem(YamlReader reader) throws AndrolibException {
|
||||
YamlLine line = reader.getLine();
|
||||
switch (line.getKey()) {
|
||||
case "versionCode": {
|
||||
versionCode = line.getValue();
|
||||
break;
|
||||
}
|
||||
case "versionName": {
|
||||
versionName = line.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(YamlWriter writer) {
|
||||
writer.writeString("versionCode", versionCode);
|
||||
writer.writeString("versionName", versionName);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class YamlLine {
|
||||
|
||||
public int indent = 0;
|
||||
private String key = "";
|
||||
private String value = "";
|
||||
public boolean isComment;
|
||||
public boolean isEmpty;
|
||||
public boolean hasColon;
|
||||
public boolean isNull;
|
||||
public boolean isItem;
|
||||
|
||||
public YamlLine(String line) {
|
||||
// special end line marker
|
||||
isNull = Objects.isNull(line);
|
||||
if (isNull) {
|
||||
return;
|
||||
}
|
||||
isEmpty = line.trim().isEmpty();
|
||||
if (isEmpty) {
|
||||
return;
|
||||
}
|
||||
// count indent - space only
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
if (line.charAt(i) == ' ') {
|
||||
indent++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// remove whitespace
|
||||
line = line.trim();
|
||||
char first = line.charAt(0);
|
||||
|
||||
isComment = first == '#' || first == '!';
|
||||
isItem = first == '-';
|
||||
if (isComment) {
|
||||
// for comment fill value
|
||||
value = line.substring(1).trim();
|
||||
} else {
|
||||
// value line
|
||||
hasColon = line.contains(":");
|
||||
if (isItem) {
|
||||
// array item line has only the value
|
||||
value = line.substring(1).trim();
|
||||
} else {
|
||||
// split line to key - value
|
||||
String[] parts = line.split(":");
|
||||
if (parts.length > 0) {
|
||||
key = parts[0].trim();
|
||||
if (parts.length > 1) {
|
||||
value = parts[1].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String unescape(String value) {
|
||||
return YamlStringEscapeUtils.unescapeString(value);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
if (value.equals("null")) {
|
||||
return null;
|
||||
}
|
||||
String res = unescape(value);
|
||||
// remove quotation marks
|
||||
res = res.replaceAll("^\"|\"$", "");
|
||||
res = res.replaceAll("^'|'$", "");
|
||||
return res;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
String res = unescape(key);
|
||||
// remove quotation marks
|
||||
res = res.replaceAll("^\"|\"$", "");
|
||||
res = res.replaceAll("^'|'$", "");
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean getValueBool() {
|
||||
return Objects.equals(value, "true");
|
||||
}
|
||||
|
||||
public int getValueInt() {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
public class YamlReader {
|
||||
|
||||
private ArrayList<YamlLine> mLines;
|
||||
private int mCurrent = 0;
|
||||
|
||||
public YamlReader(InputStream in) {
|
||||
mLines = new ArrayList<>();
|
||||
mLines.add(new YamlLine(null));
|
||||
read(in);
|
||||
}
|
||||
|
||||
public void pushLine() {
|
||||
if (mCurrent > 0) {
|
||||
mCurrent--;
|
||||
}
|
||||
}
|
||||
|
||||
public void read(InputStream in) {
|
||||
Scanner scanner = new Scanner(in);
|
||||
mLines = new ArrayList<>();
|
||||
while (scanner.hasNextLine()) {
|
||||
mLines.add(new YamlLine(scanner.nextLine()));
|
||||
}
|
||||
mLines.add(new YamlLine(null));
|
||||
}
|
||||
|
||||
public YamlLine getLine() {
|
||||
return mLines.get(mCurrent);
|
||||
}
|
||||
|
||||
public int getIndent() {
|
||||
return getLine().indent;
|
||||
}
|
||||
|
||||
public boolean isEnd() {
|
||||
return getLine().isNull;
|
||||
}
|
||||
|
||||
public boolean isCommentOrEmpty() {
|
||||
YamlLine line = getLine();
|
||||
return line.isEmpty || line.isComment;
|
||||
}
|
||||
|
||||
public void skipInsignificant() {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
while (isCommentOrEmpty()) {
|
||||
mCurrent++;
|
||||
if (isEnd()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean nextLine() {
|
||||
if (isEnd()) {
|
||||
return false;
|
||||
}
|
||||
while (true) {
|
||||
mCurrent++;
|
||||
if (isCommentOrEmpty()) {
|
||||
continue;
|
||||
}
|
||||
return !isEnd();
|
||||
}
|
||||
}
|
||||
|
||||
interface Checker {
|
||||
boolean check(YamlLine line);
|
||||
}
|
||||
|
||||
interface Updater<T> {
|
||||
void update(T items, YamlReader reader) throws AndrolibException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read root object from start to end
|
||||
*/
|
||||
public <T extends YamlSerializable> void readRoot(T obj) throws AndrolibException {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
int objIndent = 0;
|
||||
skipInsignificant();
|
||||
while (true) {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
YamlLine line = getLine();
|
||||
// skip don't checked line or lines with other indent
|
||||
if (objIndent != line.indent || !line.hasColon) {
|
||||
nextLine();
|
||||
continue;
|
||||
}
|
||||
obj.readItem(this);
|
||||
nextLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read object. Reader stand on the object name.
|
||||
* The object data should be placed on the next line
|
||||
* and have indent.
|
||||
*/
|
||||
public <T> void readObject(T obj,
|
||||
Checker check,
|
||||
Updater<T> updater) throws AndrolibException {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
int prevIndent = getIndent();
|
||||
// detect indent for the object data
|
||||
nextLine();
|
||||
YamlLine line = getLine();
|
||||
int objIndent = line.indent;
|
||||
// object data must have indent
|
||||
// otherwise stop reading
|
||||
if (objIndent <= prevIndent || !check.check(line)) {
|
||||
pushLine();
|
||||
return;
|
||||
}
|
||||
updater.update(obj, this);
|
||||
while (nextLine()) {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
line = getLine();
|
||||
if (objIndent != line.indent || !check.check(line)) {
|
||||
pushLine();
|
||||
return;
|
||||
}
|
||||
updater.update(obj, this);
|
||||
}
|
||||
}
|
||||
|
||||
<T extends YamlSerializable> void readObject(T obj) throws AndrolibException {
|
||||
readObject(obj,
|
||||
line -> line.hasColon,
|
||||
YamlSerializable::readItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read list. Reader stand on the object name.
|
||||
* The list data should be placed on the next line.
|
||||
* Data should have same indent. May by same with name.
|
||||
*/
|
||||
public <T> void readList(List<T> list,
|
||||
Updater<List<T>> updater) throws AndrolibException {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
int listIndent = getIndent();
|
||||
nextLine();
|
||||
int dataIndent = getIndent();
|
||||
while (true) {
|
||||
if (isEnd()) {
|
||||
return;
|
||||
}
|
||||
// check incorrect data indent
|
||||
if (dataIndent < listIndent) {
|
||||
pushLine();
|
||||
return;
|
||||
}
|
||||
YamlLine line = getLine();
|
||||
if (dataIndent != line.indent || !line.isItem) {
|
||||
pushLine();
|
||||
return;
|
||||
}
|
||||
updater.update(list, this);
|
||||
nextLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void readStringList(List<String> list) throws AndrolibException {
|
||||
readList(list,
|
||||
(items, reader) -> {
|
||||
items.add(reader.getLine().getValue());
|
||||
});
|
||||
};
|
||||
|
||||
public void readIntList(List<Integer> list) throws AndrolibException {
|
||||
readList(list,
|
||||
(items, reader) -> {
|
||||
items.add(reader.getLine().getValueInt());
|
||||
});
|
||||
};
|
||||
|
||||
public void readMap(Map<String, String> map) throws AndrolibException {
|
||||
readObject(map,
|
||||
line -> line.hasColon,
|
||||
(items, reader) -> {
|
||||
YamlLine line = reader.getLine();
|
||||
items.put(line.getKey(), line.getValue());
|
||||
});
|
||||
};
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
|
||||
public interface YamlSerializable {
|
||||
void readItem(YamlReader reader) throws AndrolibException;
|
||||
void write(YamlWriter writer);
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class YamlWriter implements Closeable {
|
||||
|
||||
private int mIndent = 0;
|
||||
private final PrintWriter mWriter;
|
||||
private final String QUOTE = "'";
|
||||
|
||||
public YamlWriter(OutputStream out) {
|
||||
mWriter = new PrintWriter(new BufferedWriter(
|
||||
new OutputStreamWriter(out, StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mWriter.close();
|
||||
}
|
||||
|
||||
public String getIndentString() {
|
||||
// for java 11
|
||||
// return " ".repeat(mIndent);
|
||||
// for java 8
|
||||
return String.join("", Collections.nCopies(mIndent, " "));
|
||||
}
|
||||
|
||||
public static String escape(String value) {
|
||||
return YamlStringEscapeUtils.escapeString(value);
|
||||
}
|
||||
|
||||
public void nextIndent() {
|
||||
mIndent += 2;
|
||||
}
|
||||
|
||||
public void prevIndent() {
|
||||
if (mIndent != 0) {
|
||||
mIndent -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeIndent() {
|
||||
mWriter.print(getIndentString());
|
||||
}
|
||||
|
||||
public void writeBool(String key, boolean value) {
|
||||
writeIndent();
|
||||
String val = value ? "true": "false";
|
||||
mWriter.println(escape(key) + ": " + val);
|
||||
}
|
||||
|
||||
public void writeString(String key, String value, boolean quoted) {
|
||||
writeIndent();
|
||||
if (Objects.isNull(value)) {
|
||||
mWriter.println(escape(key) + ": null");
|
||||
} else {
|
||||
if (quoted) {
|
||||
value = QUOTE + value + QUOTE;
|
||||
}
|
||||
mWriter.println(escape(key) + ": " + escape(value));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeString(String key, String value) {
|
||||
writeString(key, value, false);
|
||||
}
|
||||
|
||||
public <T> void writeList(String key, List<T> list) {
|
||||
if (Objects.isNull(list)) {
|
||||
return;
|
||||
}
|
||||
writeIndent();
|
||||
mWriter.println(escape(key) + ":");
|
||||
for (T item: list) {
|
||||
writeIndent();
|
||||
mWriter.println("- " + item);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeStringMap(String key, Map<String, String> map) {
|
||||
if (Objects.isNull(map)) {
|
||||
return;
|
||||
}
|
||||
writeIndent();
|
||||
mWriter.println(escape(key) + ":");
|
||||
nextIndent();
|
||||
for (String mapKey: map.keySet()) {
|
||||
writeString(mapKey, map.get(mapKey));
|
||||
}
|
||||
prevIndent();
|
||||
}
|
||||
|
||||
public <T extends YamlSerializable> void writeObject(String key, T obj) {
|
||||
if (Objects.isNull(obj)) {
|
||||
return;
|
||||
}
|
||||
writeIndent();
|
||||
mWriter.println(escape(key) + ":");
|
||||
nextIndent();
|
||||
obj.write(this);
|
||||
prevIndent();
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ApkInfoReaderTest {
|
||||
|
||||
private void checkStandard(ApkInfo apkInfo) {
|
||||
assertEquals("standard.apk", apkInfo.getApkFileName());
|
||||
assertFalse(apkInfo.resourcesAreCompressed);
|
||||
assertEquals(1, apkInfo.doNotCompress.size());
|
||||
assertEquals("resources.arsc", apkInfo.doNotCompress.iterator().next());
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.packageInfo);
|
||||
assertEquals("127", apkInfo.packageInfo.forcedPackageId);
|
||||
assertNull(apkInfo.packageInfo.renameManifestPackage);
|
||||
assertNotNull(apkInfo.getSdkInfo());
|
||||
assertEquals(2, apkInfo.getSdkInfo().size());
|
||||
assertEquals("25", apkInfo.getSdkInfo().get("minSdkVersion"));
|
||||
assertEquals("30", apkInfo.getSdkInfo().get("targetSdkVersion"));
|
||||
assertFalse(apkInfo.sharedLibrary);
|
||||
assertFalse(apkInfo.sparseResources);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertNotNull(apkInfo.usesFramework.ids);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
assertEquals(1, (long)apkInfo.usesFramework.ids.get(0));
|
||||
assertNull(apkInfo.usesFramework.tag);
|
||||
assertNotNull(apkInfo.versionInfo);
|
||||
assertNull(apkInfo.versionInfo.versionCode);
|
||||
assertNull(apkInfo.versionInfo.versionName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandard() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/standard.yml"));
|
||||
checkStandard(apkInfo);
|
||||
assertEquals("2.8.1", apkInfo.version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownFields() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/unknown_fields.yml"));
|
||||
checkStandard(apkInfo);
|
||||
assertEquals("2.8.1", apkInfo.version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipIncorrectIndent() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/skip_incorrect_indent.yml"));
|
||||
checkStandard(apkInfo);
|
||||
assertNotEquals("2.0.0", apkInfo.version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstIncorrectIndent() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/first_incorrect_indent.yml"));
|
||||
checkStandard(apkInfo);
|
||||
assertNotEquals("2.0.0", apkInfo.version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownFiles() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/unknown_files.yml"));
|
||||
assertEquals("2.0.0", apkInfo.version);
|
||||
assertEquals("testapp.apk", apkInfo.getApkFileName());
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
assertEquals(1, (long)apkInfo.usesFramework.ids.get(0));
|
||||
assertNotNull(apkInfo.packageInfo);
|
||||
assertEquals("127", apkInfo.packageInfo.forcedPackageId);
|
||||
assertNotNull(apkInfo.versionInfo);
|
||||
assertEquals("1", apkInfo.versionInfo.versionCode);
|
||||
assertEquals("1.0", apkInfo.versionInfo.versionName);
|
||||
assertFalse(apkInfo.resourcesAreCompressed);
|
||||
assertNotNull(apkInfo.doNotCompress);
|
||||
assertEquals(4, apkInfo.doNotCompress.size());
|
||||
assertEquals("assets/0byte_file.jpg", apkInfo.doNotCompress.get(0));
|
||||
assertEquals("arsc", apkInfo.doNotCompress.get(1));
|
||||
assertEquals("png", apkInfo.doNotCompress.get(2));
|
||||
assertEquals("mp3", apkInfo.doNotCompress.get(3));
|
||||
assertNotNull(apkInfo.unknownFiles);
|
||||
assertEquals(7, apkInfo.unknownFiles.size());
|
||||
assertEquals("8", apkInfo.unknownFiles.get("AssetBundle/assets/a.txt"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("AssetBundle/b.txt"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("hidden.file"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("non\u007Fprintable.file"));
|
||||
assertEquals("0", apkInfo.unknownFiles.get("stored.file"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("unk_folder/unknown_file"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("lib_bug603/bug603"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUlist_with_indent() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/list_with_indent.yml"));
|
||||
assertEquals("2.8.0", apkInfo.version);
|
||||
assertEquals("basic.apk", apkInfo.getApkFileName());
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
assertEquals(1, (long)apkInfo.usesFramework.ids.get(0));
|
||||
assertEquals("tag", apkInfo.usesFramework.tag);
|
||||
assertNotNull(apkInfo.packageInfo);
|
||||
assertEquals("127", apkInfo.packageInfo.forcedPackageId);
|
||||
assertEquals("com.test.basic", apkInfo.packageInfo.renameManifestPackage);
|
||||
assertNotNull(apkInfo.getSdkInfo());
|
||||
assertEquals(3, apkInfo.getSdkInfo().size());
|
||||
assertEquals("4", apkInfo.getSdkInfo().get("minSdkVersion"));
|
||||
assertEquals("30", apkInfo.getSdkInfo().get("maxSdkVersion"));
|
||||
assertEquals("22", apkInfo.getSdkInfo().get("targetSdkVersion"));
|
||||
assertFalse(apkInfo.sharedLibrary);
|
||||
assertTrue(apkInfo.sparseResources);
|
||||
assertNotNull(apkInfo.unknownFiles);
|
||||
assertEquals(1, apkInfo.unknownFiles.size());
|
||||
assertEquals("1", apkInfo.unknownFiles.get("hidden.file"));
|
||||
assertNotNull(apkInfo.versionInfo);
|
||||
assertEquals("71", apkInfo.versionInfo.versionCode);
|
||||
assertEquals("1.0.70", apkInfo.versionInfo.versionName);
|
||||
assertNotNull(apkInfo.doNotCompress);
|
||||
assertEquals(2, apkInfo.doNotCompress.size());
|
||||
assertEquals("resources.arsc", apkInfo.doNotCompress.get(0));
|
||||
assertEquals("png", apkInfo.doNotCompress.get(1));
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
* Copyright (C) 2010 Connor Tumbleson <connor.tumbleson@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ApkInfoSerializationTest {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void checkApkInfoSerialization() throws IOException, AndrolibException {
|
||||
ApkInfo control = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/unknown_files.yml"));
|
||||
check(control);
|
||||
|
||||
File savedApkInfo = folder.newFile( "saved.yml" );
|
||||
control.save(savedApkInfo);
|
||||
try (
|
||||
FileInputStream fis = new FileInputStream(savedApkInfo);
|
||||
) {
|
||||
ApkInfo saved = ApkInfo.load(fis);
|
||||
check(saved);
|
||||
}
|
||||
}
|
||||
|
||||
private void check(ApkInfo apkInfo) {
|
||||
assertEquals("2.0.0", apkInfo.version);
|
||||
assertEquals("testapp.apk", apkInfo.getApkFileName());
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
assertEquals(1, (long)apkInfo.usesFramework.ids.get(0));
|
||||
assertNotNull(apkInfo.packageInfo);
|
||||
assertEquals("127", apkInfo.packageInfo.forcedPackageId);
|
||||
assertNotNull(apkInfo.versionInfo);
|
||||
assertEquals("1", apkInfo.versionInfo.versionCode);
|
||||
assertEquals("1.0", apkInfo.versionInfo.versionName);
|
||||
assertFalse(apkInfo.resourcesAreCompressed);
|
||||
assertNotNull(apkInfo.doNotCompress);
|
||||
assertEquals(4, apkInfo.doNotCompress.size());
|
||||
assertEquals("assets/0byte_file.jpg", apkInfo.doNotCompress.get(0));
|
||||
assertEquals("arsc", apkInfo.doNotCompress.get(1));
|
||||
assertEquals("png", apkInfo.doNotCompress.get(2));
|
||||
assertEquals("mp3", apkInfo.doNotCompress.get(3));
|
||||
assertNotNull(apkInfo.unknownFiles);
|
||||
assertEquals(7, apkInfo.unknownFiles.size());
|
||||
assertEquals("8", apkInfo.unknownFiles.get("AssetBundle/assets/a.txt"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("AssetBundle/b.txt"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("hidden.file"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("non\u007Fprintable.file"));
|
||||
assertEquals("0", apkInfo.unknownFiles.get("stored.file"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("unk_folder/unknown_file"));
|
||||
assertEquals("8", apkInfo.unknownFiles.get("lib_bug603/bug603"));
|
||||
}
|
||||
}
|
@ -14,35 +14,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package brut.androlib.yaml;
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.BaseTest;
|
||||
import brut.androlib.TestUtils;
|
||||
import brut.androlib.apk.ApkInfo;
|
||||
import brut.common.BrutException;
|
||||
import brut.directory.ExtFile;
|
||||
import brut.util.OS;
|
||||
import org.junit.BeforeClass;
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import org.junit.Test;
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ConsistentPropertyTest extends BaseTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
TestUtils.cleanFrameworkFile();
|
||||
|
||||
sTmpDir = new ExtFile(OS.createTempDirectory());
|
||||
sTestNewDir = new ExtFile(sTmpDir, "yaml");
|
||||
LOGGER.info("Unpacking yaml files...");
|
||||
TestUtils.copyResourceDir(ConsistentPropertyTest.class, "decode/yaml/", sTestNewDir);
|
||||
}
|
||||
public class ConsistentPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testAssertingAllKnownApkInfoProperties() throws BrutException {
|
||||
ApkInfo apkInfo = ApkInfo.load(new File(sTestNewDir, "basic"));
|
||||
public void testAssertingAllKnownApkInfoProperties() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/basic.yml"));
|
||||
|
||||
assertEquals("2.8.0", apkInfo.version);
|
||||
assertEquals("basic.apk", apkInfo.getApkFileName());
|
@ -0,0 +1,20 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class DoNotCompressHieroglyphTest {
|
||||
|
||||
@Test
|
||||
public void testHieroglyph() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/donotcompress_with_hieroglyph.yml"));
|
||||
assertEquals("2.0.0", apkInfo.version);
|
||||
assertEquals("testapp.apk", apkInfo.getApkFileName());
|
||||
assertEquals(2, apkInfo.doNotCompress.size());
|
||||
assertEquals("assets/AllAssetBundles/Andriod/tx_1001_冰原1", apkInfo.doNotCompress.get(0));
|
||||
assertEquals("assets/AllAssetBundles/Andriod/tx_1001_冰原1.manifest", apkInfo.doNotCompress.get(1));
|
||||
}
|
||||
}
|
@ -14,17 +14,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package brut.androlib.androlib;
|
||||
package brut.androlib.apk;
|
||||
|
||||
import brut.androlib.BaseTest;
|
||||
import brut.androlib.apk.ApkInfo;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class InvalidSdkBoundingTest extends BaseTest {
|
||||
public class InvalidSdkBoundingTest {
|
||||
|
||||
@Test
|
||||
public void checkIfInvalidValuesPass() {
|
@ -16,23 +16,17 @@
|
||||
*/
|
||||
package brut.androlib.apk;
|
||||
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EscapedStringRepresenter extends Representer {
|
||||
public EscapedStringRepresenter() {
|
||||
super(new DumperOptions());
|
||||
RepresentStringEx representStringEx = new RepresentStringEx();
|
||||
multiRepresenters.put(String.class, representStringEx);
|
||||
representers.put(String.class, representStringEx);
|
||||
}
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
private class RepresentStringEx extends RepresentString {
|
||||
public class MaliciousYamlTest {
|
||||
|
||||
@Override
|
||||
public Node representData(Object data) {
|
||||
return super.representData(YamlStringEscapeUtils.escapeString(data.toString()));
|
||||
}
|
||||
@Test
|
||||
public void testMaliciousYaml() throws AndrolibException {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/cve20220476.yml"));
|
||||
assertEquals("2.6.1-ddc4bb-SNAPSHOT", apkInfo.version);
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package brut.androlib.apk;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class YamlLineTest {
|
||||
|
||||
@Test
|
||||
public void testEmptyLine() {
|
||||
YamlLine line = new YamlLine("");
|
||||
assertEquals(0, line.indent);
|
||||
assertTrue(line.isEmpty);
|
||||
|
||||
line = new YamlLine(" ");
|
||||
assertEquals(0, line.indent);
|
||||
assertTrue(line.isEmpty);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComment() {
|
||||
YamlLine line = new YamlLine("!ApkInfo.class");
|
||||
assertTrue(line.isComment);
|
||||
|
||||
line = new YamlLine("# This is comment");
|
||||
assertEquals(0, line.indent);
|
||||
assertTrue(line.isComment);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("This is comment", line.getValue());
|
||||
|
||||
line = new YamlLine(" # This is comment");
|
||||
assertEquals(2, line.indent);
|
||||
assertTrue(line.isComment);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("This is comment", line.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyLine() {
|
||||
YamlLine line = new YamlLine("name:");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(0, line.indent);
|
||||
assertEquals("name", line.getKey());
|
||||
assertEquals("", line.getValue());
|
||||
|
||||
line = new YamlLine(" name:");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(2, line.indent);
|
||||
assertEquals("name", line.getKey());
|
||||
assertEquals("", line.getValue());
|
||||
|
||||
line = new YamlLine(":value");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(0, line.indent);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("value", line.getValue());
|
||||
|
||||
line = new YamlLine(" : value ");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(2, line.indent);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("value", line.getValue());
|
||||
|
||||
line = new YamlLine("name : value ");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(0, line.indent);
|
||||
assertEquals("name", line.getKey());
|
||||
assertEquals("value", line.getValue());
|
||||
|
||||
line = new YamlLine(" name : value ");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(2, line.indent);
|
||||
assertEquals("name", line.getKey());
|
||||
assertEquals("value", line.getValue());
|
||||
|
||||
line = new YamlLine(" name : value ::");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(2, line.indent);
|
||||
assertEquals("name", line.getKey());
|
||||
assertEquals("value", line.getValue());
|
||||
|
||||
// split this gives parts.length = 0!!
|
||||
line = new YamlLine(":::");
|
||||
assertFalse(line.isComment);
|
||||
assertEquals(0, line.indent);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("", line.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemLine() {
|
||||
YamlLine line = new YamlLine("- val1");
|
||||
assertTrue(line.isItem);
|
||||
assertEquals(0, line.indent);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("val1", line.getValue());
|
||||
|
||||
line = new YamlLine(" - val1: ff");
|
||||
assertTrue(line.isItem);
|
||||
assertEquals(2, line.indent);
|
||||
assertEquals("", line.getKey());
|
||||
assertEquals("val1: ff", line.getValue());
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
* Copyright (C) 2010 Connor Tumbleson <connor.tumbleson@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package brut.androlib.yaml;
|
||||
|
||||
import brut.androlib.ApkBuilder;
|
||||
import brut.androlib.BaseTest;
|
||||
import brut.androlib.TestUtils;
|
||||
import brut.androlib.Config;
|
||||
import brut.common.BrutException;
|
||||
import brut.directory.ExtFile;
|
||||
import brut.util.OS;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.yaml.snakeyaml.constructor.ConstructorException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class MaliciousYamlTest extends BaseTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
TestUtils.cleanFrameworkFile();
|
||||
|
||||
sTmpDir = new ExtFile(OS.createTempDirectory());
|
||||
sTestNewDir = new ExtFile(sTmpDir, "cve20220476");
|
||||
LOGGER.info("Unpacking cve20220476...");
|
||||
TestUtils.copyResourceDir(MaliciousYamlTest.class, "yaml/cve20220476/", sTestNewDir);
|
||||
}
|
||||
|
||||
@Test(expected = ConstructorException.class)
|
||||
public void testMaliciousYamlNotLoaded() throws BrutException {
|
||||
Config config = Config.getDefaultConfig();
|
||||
File testApk = new File(sTmpDir, "cve20220476.apk");
|
||||
new ApkBuilder(config, sTestNewDir).build(testApk);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
version: 2.0.0
|
||||
apkFileName: testapp.apk
|
||||
doNotCompress:
|
||||
- assets/AllAssetBundles/Andriod/tx_1001_冰原1
|
||||
- assets/AllAssetBundles/Andriod/tx_1001_冰原1.manifest
|
||||
|
@ -0,0 +1,22 @@
|
||||
!!brut.androlib.meta.MetaInfo
|
||||
version: 2.0.0
|
||||
apkFileName: standard.apk
|
||||
compressionType: false
|
||||
doNotCompress:
|
||||
- resources.arsc
|
||||
isFrameworkApk: false
|
||||
packageInfo:
|
||||
forcedPackageId: '127'
|
||||
renameManifestPackage: null
|
||||
sdkInfo:
|
||||
minSdkVersion: '25'
|
||||
targetSdkVersion: '30'
|
||||
sharedLibrary: false
|
||||
sparseResources: false
|
||||
usesFramework:
|
||||
ids:
|
||||
- 1
|
||||
tag: null
|
||||
versionInfo:
|
||||
versionCode: null
|
||||
versionName: null
|
@ -0,0 +1,26 @@
|
||||
!!brut.androlib.meta.MetaInfo
|
||||
apkFileName: basic.apk
|
||||
compressionType: false
|
||||
doNotCompress:
|
||||
- resources.arsc
|
||||
- png
|
||||
isFrameworkApk: false
|
||||
packageInfo:
|
||||
forcedPackageId: '127'
|
||||
renameManifestPackage: 'com.test.basic'
|
||||
sdkInfo:
|
||||
minSdkVersion: '4'
|
||||
maxSdkVersion: '30'
|
||||
targetSdkVersion: '22'
|
||||
sharedLibrary: false
|
||||
sparseResources: true
|
||||
unknownFiles:
|
||||
hidden.file: 1
|
||||
usesFramework:
|
||||
ids:
|
||||
- 1
|
||||
tag: 'tag'
|
||||
version: 2.8.0
|
||||
versionInfo:
|
||||
versionCode: '71'
|
||||
versionName: 1.0.70
|
@ -0,0 +1,22 @@
|
||||
!!brut.androlib.meta.MetaInfo
|
||||
apkFileName: standard.apk
|
||||
version: 2.0.0
|
||||
compressionType: false
|
||||
doNotCompress:
|
||||
- resources.arsc
|
||||
isFrameworkApk: false
|
||||
packageInfo:
|
||||
forcedPackageId: '127'
|
||||
renameManifestPackage: null
|
||||
sdkInfo:
|
||||
minSdkVersion: '25'
|
||||
targetSdkVersion: '30'
|
||||
sharedLibrary: false
|
||||
sparseResources: false
|
||||
usesFramework:
|
||||
ids:
|
||||
- 1
|
||||
tag: null
|
||||
versionInfo:
|
||||
versionCode: null
|
||||
versionName: null
|
22
brut.apktool/apktool-lib/src/test/resources/apk/standard.yml
Normal file
22
brut.apktool/apktool-lib/src/test/resources/apk/standard.yml
Normal file
@ -0,0 +1,22 @@
|
||||
!!brut.androlib.meta.MetaInfo
|
||||
apkFileName: standard.apk
|
||||
compressionType: false
|
||||
doNotCompress:
|
||||
- resources.arsc
|
||||
isFrameworkApk: false
|
||||
packageInfo:
|
||||
forcedPackageId: '127'
|
||||
renameManifestPackage: null
|
||||
sdkInfo:
|
||||
minSdkVersion: '25'
|
||||
targetSdkVersion: '30'
|
||||
sharedLibrary: false
|
||||
sparseResources: false
|
||||
usesFramework:
|
||||
ids:
|
||||
- 1
|
||||
tag: null
|
||||
version: 2.8.1
|
||||
versionInfo:
|
||||
versionCode: null
|
||||
versionName: null
|
@ -0,0 +1,25 @@
|
||||
!!brut.androlib.meta.MetaInfo
|
||||
apkFileName: standard.apk
|
||||
compressionType: false
|
||||
test: test
|
||||
doNotCompress:
|
||||
- resources.arsc
|
||||
isFrameworkApk: false
|
||||
packageInfo:
|
||||
forcedPackageId: '127'
|
||||
renameManifestPackage: null
|
||||
test2: test2
|
||||
sdkInfo:
|
||||
minSdkVersion: '25'
|
||||
targetSdkVersion: '30'
|
||||
sharedLibrary: false
|
||||
sparseResources: false
|
||||
usesFramework:
|
||||
ids:
|
||||
- 1
|
||||
tag: null
|
||||
test3: test3
|
||||
version: 2.8.1
|
||||
versionInfo:
|
||||
versionCode: null
|
||||
versionName: null
|
@ -0,0 +1,25 @@
|
||||
version: 2.0.0
|
||||
apkFileName: testapp.apk
|
||||
isFrameworkApk: false
|
||||
usesFramework:
|
||||
ids:
|
||||
- 1
|
||||
packageInfo:
|
||||
forcedPackageId: '127'
|
||||
versionInfo:
|
||||
versionCode: '1'
|
||||
versionName: '1.0'
|
||||
compressionType: false
|
||||
doNotCompress:
|
||||
- assets/0byte_file.jpg
|
||||
- arsc
|
||||
- png
|
||||
- mp3
|
||||
unknownFiles:
|
||||
AssetBundle/assets/a.txt: '8'
|
||||
AssetBundle/b.txt: '8'
|
||||
hidden.file: '8'
|
||||
non\u007Fprintable.file: '8'
|
||||
stored.file: '0'
|
||||
unk_folder/unknown_file: '8'
|
||||
lib_bug603/bug603: '8'
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="30" android:compileSdkVersionCodename="11" package="com.ibotpeaches.cve20220476" platformBuildVersionCode="30" platformBuildVersionName="11">
|
||||
<application android:debuggable="true" android:forceQueryable="true">
|
||||
</application>
|
||||
</manifest>
|
@ -26,7 +26,6 @@ buildscript {
|
||||
guava : 'com.google.guava:guava:32.0.1-jre',
|
||||
junit : 'junit:junit:4.13.2',
|
||||
proguard_gradle: 'com.guardsquare:proguard-gradle:7.3.2',
|
||||
snakeyaml : 'org.yaml:snakeyaml:1.32:android',
|
||||
smali : 'com.android.tools.smali:smali:3.0.3',
|
||||
xmlpull : 'xpp3:xpp3:1.1.4c',
|
||||
xmlunit : 'xmlunit:xmlunit:1.6',
|
||||
|
Loading…
Reference in New Issue
Block a user