Skip to content

Commit

Permalink
(fix) Fully close issue #8
Browse files Browse the repository at this point in the history
All tests passing. Properly recover from a
mangled start tag. Allow injection correctly.
  • Loading branch information
strazzere committed Aug 6, 2024
1 parent d5a0900 commit 004e1bc
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 34 deletions.
44 changes: 35 additions & 9 deletions src/main/java/android/content/res/AXMLResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import android.content.res.chunk.types.AXMLHeader;
import android.content.res.chunk.types.Attribute;
import android.content.res.chunk.types.Chunk;
import android.content.res.chunk.types.NameSpace;
import android.content.res.chunk.types.StartTag;
import android.content.res.chunk.types.EndTag;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -44,14 +46,17 @@ public class AXMLResource {
AXMLHeader header;
StringSection stringSection;
ResourceSection resourceSection;
List<NameSpace> nameSpaces;
LinkedHashSet<Chunk> chunks;

public AXMLResource() {
chunks = new LinkedHashSet<Chunk>();
nameSpaces = new ArrayList<NameSpace>();
}

public AXMLResource(InputStream stream) throws IOException {
chunks = new LinkedHashSet<Chunk>();
nameSpaces = new ArrayList<NameSpace>();
if (!read(stream)) {
throw new IOException();
}
Expand Down Expand Up @@ -160,11 +165,11 @@ public void write(OutputStream outputStream) throws IOException {
}

public void print() {

log("%s", header.toXML(stringSection, resourceSection, 0));
log("%s", header.toXML(stringSection, resourceSection, nameSpaces, 0));
Iterator<Chunk> iterator = chunks.iterator();
int indents = 0;
List<String> namespaceXmlList = new ArrayList<String>();
int lastStartNameIndex = -1;

while (iterator.hasNext()) {
Chunk chunk = iterator.next();
Expand All @@ -173,14 +178,24 @@ public void print() {
}

if (chunk.getChunkType() == ChunkType.START_NAMESPACE) {
namespaceXmlList.add(chunk.toXML(stringSection, resourceSection, indents));
namespaceXmlList.add(chunk.toXML(stringSection, resourceSection, nameSpaces, indents));
nameSpaces.add((NameSpace)chunk);
} else if (chunk.getChunkType() == ChunkType.END_NAMESPACE) {
// ignore
} else {
if (chunk.getChunkType() == ChunkType.START_TAG && ((StartTag)chunk).isMangled(stringSection)) {
((StartTag)chunk).fixMangle(stringSection);
lastStartNameIndex = stringSection.getStringIndex(((StartTag)chunk).getName(stringSection));
}
if (chunk.getChunkType() == ChunkType.END_TAG && ((EndTag)chunk).isMangled(stringSection)) {
((EndTag)chunk).setName(lastStartNameIndex);
lastStartNameIndex = -1;
}

if (namespaceXmlList.isEmpty()) {
log("%s", chunk.toXML(stringSection, resourceSection, indents));
log("%s", chunk.toXML(stringSection, resourceSection, nameSpaces, indents));
} else {
log("%s", appendNameSpace(chunk.toXML(stringSection, resourceSection, indents), namespaceXmlList));
log("%s", appendNameSpace(chunk.toXML(stringSection, resourceSection, nameSpaces, indents), namespaceXmlList));
namespaceXmlList.clear();
}
}
Expand All @@ -194,26 +209,37 @@ public void print() {

public String toXML() {
StringBuilder xmlStrbui = new StringBuilder();
xmlStrbui.append(header.toXML(stringSection, resourceSection, 0)).append('\n');
xmlStrbui.append(header.toXML(stringSection, resourceSection, nameSpaces, 0)).append('\n');
Iterator<Chunk> iterator = chunks.iterator();
int indents = 0;
List<String> namespaceXmlList = new ArrayList<String>();

int lastStartNameIndex = -1;

while (iterator.hasNext()) {
Chunk chunk = iterator.next();
if (chunk.getChunkType() == ChunkType.END_TAG) {
indents--;
}

if (chunk.getChunkType() == ChunkType.START_NAMESPACE) {
namespaceXmlList.add(chunk.toXML(stringSection, resourceSection, indents));
namespaceXmlList.add(chunk.toXML(stringSection, resourceSection, nameSpaces, indents));
nameSpaces.add((NameSpace) chunk);
} else if (chunk.getChunkType() == ChunkType.END_NAMESPACE) {
// ignore
} else {
if (chunk.getChunkType() == ChunkType.START_TAG && ((StartTag)chunk).isMangled(stringSection)) {
((StartTag)chunk).fixMangle(stringSection);
lastStartNameIndex = stringSection.getStringIndex(((StartTag)chunk).getName(stringSection));
}
if (chunk.getChunkType() == ChunkType.END_TAG && ((EndTag)chunk).isMangled(stringSection)) {
((EndTag)chunk).setName(lastStartNameIndex);
lastStartNameIndex = -1;
}
if (namespaceXmlList.isEmpty()) {
xmlStrbui.append(chunk.toXML(stringSection, resourceSection, indents)).append('\n');
xmlStrbui.append(chunk.toXML(stringSection, resourceSection, nameSpaces, indents)).append('\n');
} else {
xmlStrbui.append(appendNameSpace(chunk.toXML(stringSection, resourceSection, indents), namespaceXmlList)).append('\n');
xmlStrbui.append(appendNameSpace(chunk.toXML(stringSection, resourceSection, nameSpaces, indents), namespaceXmlList)).append('\n');
namespaceXmlList.clear();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
import android.content.res.IntReader;
import android.content.res.chunk.ChunkType;
import android.content.res.chunk.types.Chunk;
import android.content.res.chunk.types.NameSpace;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

/**
* Concrete class for the section which is specifically for the resource ids.
Expand Down Expand Up @@ -86,7 +88,7 @@ public int getResourceCount() {
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.content.res.chunk.ChunkType;
import android.content.res.chunk.PoolItem;
import android.content.res.chunk.types.Chunk;
import android.content.res.chunk.types.NameSpace;

import java.io.IOException;
import java.nio.ByteBuffer;
Expand Down Expand Up @@ -175,7 +176,7 @@ public String getStyle(int index) {
}

@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.content.res.chunk.sections.StringSection;

import java.io.IOException;
import java.util.List;

/**
* ChunkType which is for the AXMLHeader, should be at the beginning and only the beginning of the files.
Expand Down Expand Up @@ -53,7 +54,7 @@ public void readHeader(IntReader inputReader) throws IOException {
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
return indent(indent) + "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
}

Expand Down
12 changes: 9 additions & 3 deletions src/main/java/android/content/res/chunk/types/Attribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;

/**
* Specific type of Chunk which contains the metadata
Expand Down Expand Up @@ -119,11 +120,16 @@ public int getStringDataIndex() {
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
StringBuffer buffer = new StringBuffer();
if ((uri - 1) > 0) {
buffer.append(stringSection.getString(uri - 1));
buffer.append(":");
for (NameSpace nameSpace : namespaceList) {
if (nameSpace.getUri() == uri) {
buffer.append(stringSection.getString(nameSpace.getPrefix()));
buffer.append(":");
break;
}
}
}

buffer.append(stringSection.getString(name));
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/android/content/res/chunk/types/Buffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.content.res.chunk.sections.StringSection;

import java.io.IOException;
import java.util.List;

/**
* This "buffer" chunk is currently being used for empty space, though it might not be needed
Expand Down Expand Up @@ -74,7 +75,7 @@ public int getSize() {
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
return null;
}

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/android/content/res/chunk/types/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.content.res.chunk.sections.StringSection;

import java.io.IOException;
import java.util.List;

/**
* Generic interface for everything that is at minimum a "chunk"
Expand Down Expand Up @@ -57,10 +58,11 @@ public interface Chunk {
/**
* @param stringSection
* @param resourceSection
* @param namespaceList
* @param indent
* @return a String representation in XML form
*/
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent);
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent);

/**
* Get the a byte[] for the chunk
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/android/content/res/chunk/types/EndTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;

/**
* Specific chunk for ending sections and/or namespaces
Expand All @@ -35,9 +36,11 @@ public class EndTag extends GenericChunk implements Chunk {
private int commentIndex;
private int namespaceUri;
private int name;
private boolean mangled;

public EndTag(ChunkType chunkType, IntReader inputReader) {
super(chunkType, inputReader);
mangled = false;
}

/*
Expand All @@ -53,14 +56,29 @@ public void readHeader(IntReader inputReader) throws IOException {
name = inputReader.readInt();
}

public boolean isMangled(StringSection stringSection) {
mangled = stringSection.getString(name).isEmpty();

return mangled;
}

public void setName(int newName) {
name = newName;
// Assume this is a fix for now
mangled = false;
}
/*
* (non-Javadoc)
*
* @see android.content.res.chunk.types.Chunk#toXML(android.content.res.chunk.sections.StringSection,
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
if (stringSection.getString(name).isEmpty()) {
mangled = true;
}

return indent(indent) + "</" + stringSection.getString(name) + ">";
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/android/content/res/chunk/types/NameSpace.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;

/**
* Namespace Chunk - used for denoting the borders of the XML boundries
Expand Down Expand Up @@ -83,7 +84,7 @@ public String toString(StringSection stringSection) {
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
if (isStart()) {
return indent(indent) + toString(stringSection);
} else {
Expand Down
30 changes: 28 additions & 2 deletions src/main/java/android/content/res/chunk/types/StartTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
* StartTag type of Chunk, differs from a Namespace as there will be specific metadata inside of it
Expand All @@ -41,9 +42,11 @@ public class StartTag extends GenericChunk implements Chunk {
private int attributeCount;
private int classAttribute;
private ArrayList<Attribute> attributes;
private boolean mangled;

public StartTag(ChunkType chunkType, IntReader inputReader) {
super(chunkType, inputReader);
mangled = false;
}

/*
Expand Down Expand Up @@ -98,14 +101,37 @@ public String getName(StringSection stringSection) {
return stringSection.getString(name);
}

public boolean isMangled(StringSection stringSection) {
mangled = stringSection.getString(name).isEmpty();

return mangled;
}

public void fixMangle(StringSection stringSection) {
int guessedTag = -1;
for (int i = 0; i < attributeCount; i++) {
if (stringSection.getString(attributes.get(i).getNameIndex()).contains("protectionLevel")) {
guessedTag = stringSection.getStringIndex("uses-permission");
break;
}
}

if (guessedTag == -1) {
// throw new IOException("Unknown start tag, unable to recover from AXML mangling");
}

mangled = false;
name = guessedTag;
}

/*
* (non-Javadoc)
*
* @see android.content.res.chunk.types.Chunk#toXML(android.content.res.chunk.sections.StringSection,
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
StringBuffer buffer = new StringBuffer();
buffer.append(indent(indent));
buffer.append("<");
Expand All @@ -114,7 +140,7 @@ public String toXML(StringSection stringSection, ResourceSection resourceSection

for (int i = 0; i < attributeCount; i++) {
buffer.append(indent(indent + 1));
buffer.append(attributes.get(i).toXML(stringSection, resourceSection, indent));
buffer.append(attributes.get(i).toXML(stringSection, resourceSection, namespaceList, indent));
buffer.append("\n");
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/android/content/res/chunk/types/TextTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;

/**
* Specific Chunk which contains a text key and value
Expand Down Expand Up @@ -63,7 +64,7 @@ public void readHeader(IntReader inputReader) throws IOException {
* android.content.res.chunk.sections.ResourceSection, int)
*/
@Override
public String toXML(StringSection stringSection, ResourceSection resourceSection, int indent) {
public String toXML(StringSection stringSection, ResourceSection resourceSection, List<NameSpace> namespaceList, int indent) {
StringBuffer buffer = new StringBuffer();

buffer.append(indent(indent));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/diff/rednaga/AXMLPrinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static void main(String[] arguments) throws IOException {

if (arguments[0].equalsIgnoreCase("-v") || arguments[0].equalsIgnoreCase("-version")) {
System.out.printf("axmlprinter %s (http://github.com/rednaga/axmlprinter2)\n", VERSION);
System.out.printf("Copyright (C) 2015 Red Naga - Tim 'diff' Strazzere (strazz@gmail.com)\n");
System.out.printf("Copyright (C) 2015-2024 Red Naga - Tim 'diff' Strazzere (diff@protonmail.com)\n");
return;
}

Expand Down
Loading

0 comments on commit 004e1bc

Please sign in to comment.