ARSCLib icon indicating copy to clipboard operation
ARSCLib copied to clipboard

Pseudo xml header

Open developer-krushna opened this issue 11 months ago • 8 comments

Hello sir..I was the one who made the first issue related to the arsc lib I hope you remember me..

Now I have made an Axml Printer library.. https://github.com/developer-krushna/AXMLPrinter

This project have everything but it couldn't read the unknown header like 0x80000 etc

But I see your project can read it easily.. can you please help me with it.. I not understand where I need to start 😞

developer-krushna avatar Jan 22 '25 21:01 developer-krushna

Start from AOSP: ResourceTypes.h

REAndroid avatar Jan 31 '25 12:01 REAndroid

Thank u sir for your reply but I still don't know how can I use this feature.. but sir can you tell me how you made

Your project first modifying the 0x80000 based XML header to convert it 0x80003 to make it readable?? Or it directly processing??? My XML parser is something different way.. if you have noticed

developer-krushna avatar Jan 31 '25 18:01 developer-krushna

Read again ResourceTypes.h LINE 213. I believe you missing core points. Where you got "0x80003" ? i assumed you got from first bytes of header 03 00 08 00

All resource headers have this base structure (xml, resource table , package ...)

struct ResChunk_header
{
    uint16_t type; // 2 bytes
    uint16_t headerSize; // 2 bytes
    uint32_t size; // 4 bytes
};

I ported this to java HeaderBlock.java

    private final ShortItem mType;
    private final ShortItem mHeaderSize;
    private final IntegerItem mChunkSize;

Thus the proper way of parsing is: type = 0x0003 headerSize = 0x0008 // 2 + 2 + 4

REAndroid avatar Jan 31 '25 19:01 REAndroid

But sir you can use it easily but I my project I still don't understand where I need to make changes 😔 [AxmlParser] (https://github.com/developer-krushna/AXMLPrinter/blob/ca30445d4168298fe579a305b430813e882de122/library/src/main/java/mt/modder/hub/axmlTools/AXmlResourceParser.java#L335)

 private void doNext() throws IOException {
        int readInt = 0;
        if (this.stringBlock == null) {
            ChunkUtil.readCheckType(this.mReader, 0x80003); // you can add comma to inckude more 
            this.mReader.skipInt();
            this.stringBlock = StringBlock.read(this.mReader);
            this.mNamespaces.increaseDepth();
            this.mOperational = true;
        }
        if (this.eventType == XmlPullParser.END_DOCUMENT) {
            return;
        }
        int previousEvent = this.eventType;
        resetEventInfo();
        while (true) {
            if (this.mDecreaseDepth) {
                this.mDecreaseDepth = false;
                this.mNamespaces.decreaseDepth();
            }
            if (previousEvent == XmlPullParser.END_TAG && this.mNamespaces.getDepth() == 1 && this.mNamespaces.getCurrentCount() == 0) {
                this.eventType = XmlPullParser.END_DOCUMENT;
                return;
            }
            int chunkType = previousEvent == XmlPullParser.START_DOCUMENT ? 0x100102 : this.mReader.readInt();
            if (chunkType == 0x80180) {
                readInt = this.mReader.readInt();
                if (readInt < 8 || readInt % 4 != 0) {
                    break;
                }
                this.mResourceIDs = this.mReader.readIntArray((readInt / 4) - 2);
				resourceMap = new String[mResourceIDs.length];
            } else if (chunkType < 1048832 || chunkType > 1048836) {
                break;
            } else if (chunkType == 0x100102 && previousEvent == -1) {
                this.eventType = XmlPullParser.START_DOCUMENT;
                return;
            } else {
                this.mReader.skipInt();
                int lineNumber = this.mReader.readInt();
                this.mReader.skipInt();
                if (chunkType != 1048832 && chunkType != 0x100101) {
                    this.mLineNumber = lineNumber;
                    if (chunkType == 0x100102) {
                        this.mNamespaceUri = this.mReader.readInt();
                        this.mName = this.mReader.readInt();
                        this.mReader.skipInt();
                        int attributeCount = this.mReader.readInt();
                        this.mIdAttribute = (attributeCount >>> 16) - 1;
                        int classAttr = this.mReader.readInt();
                        this.mClassAttribute = classAttr;
                        this.mStyleAttribute = (classAttr >>> 16) - 1;
                        this.mClassAttribute = (65535 & classAttr) - 1;
                        this.mAttributes = this.mReader.readIntArray((attributeCount & 65535) * 5);
                        int i = 3;
                        while (true) {
                            int[] attributes = this.mAttributes;
                            if (i >= attributes.length) {
                                this.mNamespaces.increaseDepth();
                                this.eventType = 2;
                                return;
                            }
                            attributes[i] = attributes[i] >>> 24;
                            i += 5;
                        }
                    } else if (chunkType == 0x100103) {
                        this.mNamespaceUri = this.mReader.readInt();
                        this.mName = this.mReader.readInt();
                        this.eventType = 3;
                        this.mDecreaseDepth = true;
                        return;
                    } else if (chunkType == 1048836) {
                        this.mName = this.mReader.readInt();
                        this.mReader.skipInt();
                        this.mReader.skipInt();
                        this.eventType = 4;
                        return;
                    }
                } else if (chunkType == 1048832) {
                    this.mNamespaces.push(this.mReader.readInt(), this.mReader.readInt());
                } else { 
                    this.mReader.skipInt();
                    this.mReader.skipInt();
                    this.mNamespaces.pop();
                }
            }
        }
        throw new IOException("Invalid resource ids size (" + readInt + ").");
    }

developer-krushna avatar Feb 01 '25 03:02 developer-krushna

Sorry I can't go thru all your codes and fix for you. I guess you ignored my previous comment and come back again with 0x80003 stuff. Anyways your code has some similarity with old Apktool that i am a little familiar with, thus here is my suggestion:

Modify your ChunkUtil.readCheckType()

public static void readCheckType(YourReader reader, int expectedType) throws IOException {
    int type = reader.readUShort();
    if (type != expectedType) {
       throw new IOException("Expecting chunk type " + expectedType + ", but found " + type + ", near " + reader.getPosition())
    }
}
        int readInt = 0;
        if (this.stringBlock == null) {
            if (this.mReader.getFileName().equals("AndroidManifest.xml")) {
                 int chunkType = this.mReader.readUShort();
                 // if chunkType != 0x0003, validate the first element tag is "<manifest>"
            } else {
                ChunkUtil.readCheckType(this.mReader, 0x0003); 
            }
            int headerSize = this.mReader.readUShort(); // value is >= 8, but not always 8
            int chunkSize = this.mReader.readInt();
            int unknownHeaderBytes = headerSize - 8;
            this.mReader.skipBytes(unknownHeaderBytes);

            this.stringBlock = StringBlock.read(this.mReader); // Are you sure here is always StringBlock ? See an apk protected by APKEditor
            this.mNamespaces.increaseDepth();
            this.mOperational = true;
        }
       .
       .
       .

REAndroid avatar Feb 01 '25 12:02 REAndroid

Sir my Reader don't have readUShort() method.. what should i do please tell me

This is what I am getting exception java.io.IOException: Expecting chunk type 524291, but found 524288, near 4 at mt.modder.hub.axmlTools.ChunkUtil.readCheckType(ChunkUtil.java:46)

developer-krushna avatar Feb 01 '25 17:02 developer-krushna

Sir my Reader don't have readUShort() method

Sorry you are asking very basic things, take a pause and refresh yourself with:

  • Java primitive data types
  • C data types
  • Endianness, specially "Little Endian"
  • Open simple binary xml file with "Hex Editor/Viewer" study the bytes

This is off topic, even unrelated to ARSCLib thus going to close it

REAndroid avatar Feb 03 '25 11:02 REAndroid

Sir take a look at this.. I did this by using apktool codes but it is not working perfectly and XML files header with 0x80000 parsing but only the first manifest tag then it is ending the document resulting in broken XML text

private void doNext() throws IOException {
        if (this.stringBlock == null) {
			mReader.skipInt(); // XML Chunk AXML Type
            mReader.skipInt(); // Chunk Size

            stringBlock = StringBlock2.readWithChunk(mReader);
            mNamespaces.increaseDepth();
            mOperational = true;
        }
        if (this.eventType == XmlPullParser.END_DOCUMENT) {
            return;
        }
        int previousEvent = this.eventType;
        resetEventInfo();
        while (true) {
            if (this.mDecreaseDepth) {
                this.mDecreaseDepth = false;
                this.mNamespaces.decreaseDepth();
            }
			// Fake END_DOCUMENT event.
            if (previousEvent == XmlPullParser.END_TAG && this.mNamespaces.getDepth() == 1 && this.mNamespaces.getCurrentCount() == 0) {
                this.eventType = XmlPullParser.END_DOCUMENT;
                break;
            }
			// #2070 - Some applications have 2 start namespaces, but only 1 end namespace.
            if (mReader.available() == 0) {
                System.out.println(String.format("AXML hit unexpected end of file at byte: 0x%X", mReader.position()));
                eventType = XmlPullParser.END_DOCUMENT;
                break;
            }
			
			int chunkType;
            int headerSize = 0;
            if (previousEvent == XmlPullParser.START_DOCUMENT) {
                // Fake event, see CHUNK_XML_START_TAG handler.
                chunkType = 0x0102;
            } else {
                chunkType = mReader.readShort();
                headerSize = mReader.readShort();
            }
			
			if (chunkType == 0x0180) {
                int chunkSize = mReader.readInt();
                if (chunkSize < 8 || (chunkSize % 4) != 0) {
                    throw new IOException("Invalid resource ids size (" + chunkSize + ").");
                }
                this.mResourceIDs = mReader.readIntArray(chunkSize / 4 - 2);
				resourceMap = new String[mResourceIDs.length]; // extra
                continue;
            }
			
			if (chunkType < 0x0100 || chunkType > 0x017f) {
                int chunkSize = mReader.readInt();
                mReader.skipBytes(chunkSize - 8);
                System.out.println(String.format("Unknown chunk type at: (0x%08x) skipping...", mReader.position()));
                break;
            }

            // Fake START_DOCUMENT event.
            if (chunkType == 0x0102 && previousEvent == -1) {
                eventType = XmlPullParser.START_DOCUMENT;
                break;
            }

            // Read remainder of ResXMLTree_node
            mReader.skipInt(); // chunkSize
            mLineNumber = mReader.readInt();
            mReader.skipInt(); // Optional XML Comment
			
			if (chunkType == 0x0100 || chunkType == 0x0101) {
                if (chunkType == 0x0100) {
                    int prefix = mReader.readInt();
                    int uri = mReader.readInt();
                    mNamespaces.push(prefix, uri);
                } else {
                    mReader.skipInt(); // prefix
                    mReader.skipInt(); // uri
                    mNamespaces.pop();
                }

                // Check for larger header than we read. We know the current header is 0x10 bytes, but some apps
                // are packed with a larger header of unknown data.
                if (headerSize > 0x10) {
                    int bytesToSkip = headerSize - 0x10;
                    System.out.println(String.format("AXML header larger than 0x10 bytes, skipping %d bytes.", bytesToSkip));
                    mReader.skipBytes(bytesToSkip);
                }
                continue;
            }
			
			if (chunkType == 0x0102) {
                mNamespaceUri = mReader.readInt();
                mName = mReader.readInt();
                mReader.skipShort(); // attributeStart
                int attributeSize = mReader.readShort();
                int attributeCount = mReader.readShort();
                mIdAttribute = mReader.readShort();
                mClassAttribute = mReader.readShort();
                mStyleAttribute = mReader.readShort();
                mAttributes = mReader.readIntArray(attributeCount * ATTRIBUTE_LENGTH);
                for (int i = ATTRIBUTE_IX_VALUE_TYPE; i < mAttributes.length;) {
                    mAttributes[i] = (mAttributes[i] >>> 24);
                    i += ATTRIBUTE_LENGTH;
                }

                int byteAttrSizeRead = (attributeCount * ATTRIBUTE_LENGTH) * 4;
                int byteAttrSizeReported = (attributeSize * attributeCount);

                // Check for misleading chunk sizes
                if (byteAttrSizeRead < byteAttrSizeReported) {
                    int bytesToSkip = byteAttrSizeReported - byteAttrSizeRead;
                    mReader.skipBytes(bytesToSkip);
                    System.out.println("Skipping " + bytesToSkip + " unknown bytes in attributes area.");
                }

                mNamespaces.increaseDepth();
                eventType = XmlPullParser.START_TAG;
                break;
            }
			
			if (chunkType == 0x0103) {
                mNamespaceUri = mReader.readInt();
                mName = mReader.readInt();
                eventType = XmlPullParser.END_TAG;
                mDecreaseDepth = true;
                break;
            }

            if (chunkType == 0x0104) {
                mName = mReader.readInt();
                mReader.skipInt();
                mReader.skipInt();
                eventType = XmlPullParser.TEXT;
                break;
            }
		}
      }

developer-krushna avatar Feb 03 '25 13:02 developer-krushna