Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pseudo xml header #79

Open
developer-krushna opened this issue Jan 22, 2025 · 8 comments
Open

Pseudo xml header #79

developer-krushna opened this issue Jan 22, 2025 · 8 comments

Comments

@developer-krushna
Copy link

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 😞

@REAndroid
Copy link
Owner

Start from AOSP: ResourceTypes.h

@developer-krushna
Copy link
Author

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

@REAndroid
Copy link
Owner

REAndroid commented Jan 31, 2025

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

@developer-krushna
Copy link
Author

developer-krushna commented Feb 1, 2025

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 + ").");
    }

@REAndroid
Copy link
Owner

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;
        }
       .
       .
       .

@developer-krushna
Copy link
Author

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)

@REAndroid
Copy link
Owner

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

@developer-krushna
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants