1 // copyright (c) 2019-2021 hors<horsicq@gmail.com>
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 //
21 #include "xandroidbinary.h"
22 
XAndroidBinary(QIODevice * pDevice)23 XAndroidBinary::XAndroidBinary(QIODevice *pDevice): XBinary(pDevice)
24 {
25 
26 }
27 
isValid()28 bool XAndroidBinary::isValid()
29 {
30     bool bIsValid=false;
31 
32     _MEMORY_MAP memoryMap=getMemoryMap();
33 
34     bIsValid=compareSignature(&memoryMap,"03000800")||compareSignature(&memoryMap,"02000C00");
35 
36     return bIsValid;
37 }
38 
isBigEndian()39 bool XAndroidBinary::isBigEndian()
40 {
41     return false;
42 }
43 
readHeader(qint64 nOffset)44 XANDROIDBINARY_DEF::HEADER XAndroidBinary::readHeader(qint64 nOffset)
45 {
46     XANDROIDBINARY_DEF::HEADER result={};
47 
48     result.type=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER,type));
49     result.header_size=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER,header_size));
50     result.data_size=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER,data_size));
51 
52     return result;
53 }
54 
readHeaderStringPool(qint64 nOffset)55 XANDROIDBINARY_DEF::HEADER_STRING_POOL XAndroidBinary::readHeaderStringPool(qint64 nOffset)
56 {
57     XANDROIDBINARY_DEF::HEADER_STRING_POOL result={};
58 
59     result.header=readHeader(nOffset);
60     result.stringCount=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL,stringCount));
61     result.styleCount=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL,styleCount));
62     result.flags=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL,flags));
63     result.stringsStart=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL,stringsStart));
64     result.stylesStart=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL,stylesStart));
65 
66     return result;
67 }
68 
readHeaderNamespace(qint64 nOffset)69 XANDROIDBINARY_DEF::HEADER_NAMESPACE XAndroidBinary::readHeaderNamespace(qint64 nOffset)
70 {
71     XANDROIDBINARY_DEF::HEADER_NAMESPACE result={};
72 
73     result.header=readHeader(nOffset);
74     result.lineNumber=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE,lineNumber));
75     result.comment=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE,comment));
76     result.prefix=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE,prefix));
77     result.uri=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE,uri));
78 
79     return result;
80 }
81 
readHeaderXmlStart(qint64 nOffset)82 XANDROIDBINARY_DEF::HEADER_XML_START XAndroidBinary::readHeaderXmlStart(qint64 nOffset)
83 {
84     XANDROIDBINARY_DEF::HEADER_XML_START result={};
85 
86     result.header=readHeader(nOffset);
87     result.lineNumber=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,lineNumber));
88     result.comment=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,comment));
89     result.ns=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,ns));
90     result.name=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,name));
91     result.attributeStart=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,attributeStart));
92     result.attributeSize=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,attributeSize));
93     result.attributeCount=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,attributeCount));
94     result.idIndex=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,idIndex));
95     result.classIndex=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,classIndex));
96     result.styleIndex=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_START,styleIndex));
97 
98     return result;
99 }
100 
readHeaderXmlAttribute(qint64 nOffset)101 XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE XAndroidBinary::readHeaderXmlAttribute(qint64 nOffset)
102 {
103     XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE result={};
104 
105     result.ns=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,ns));
106     result.name=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,name));
107     result.rawValue=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,rawValue));
108     result.size=read_uint16(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,size));
109     result.reserved=read_uint8(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,reserved));
110     result.dataType=read_uint8(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,dataType));
111     result.data=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE,data));
112 
113     return result;
114 }
115 
readHeaderXmlEnd(qint64 nOffset)116 XANDROIDBINARY_DEF::HEADER_XML_END XAndroidBinary::readHeaderXmlEnd(qint64 nOffset)
117 {
118     XANDROIDBINARY_DEF::HEADER_XML_END result={};
119 
120     result.header=readHeader(nOffset);
121     result.lineNumber=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_END,lineNumber));
122     result.comment=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_END,comment));
123     result.ns=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_END,ns));
124     result.name=read_uint32(nOffset+offsetof(XANDROIDBINARY_DEF::HEADER_XML_END,name));
125 
126     return result;
127 }
128 
getHeaders()129 QList<XANDROIDBINARY_DEF::HEADER> XAndroidBinary::getHeaders()
130 {
131     QList<XANDROIDBINARY_DEF::HEADER> listHeaders;
132 
133     qint64 nTotalSize=getSize();
134     qint64 nCurrentOffset=0;
135 
136     while(nCurrentOffset<nTotalSize)
137     {
138         XANDROIDBINARY_DEF::HEADER record=readHeader(nCurrentOffset);
139         listHeaders.append(record);
140 
141         nCurrentOffset+=record.data_size;
142     }
143 
144     return listHeaders;
145 }
146 
getRecord(qint64 nOffset)147 XAndroidBinary::RECORD XAndroidBinary::getRecord(qint64 nOffset)
148 {
149     RECORD result={};
150 
151     result.header=readHeader(nOffset);
152     result.nOffset=nOffset;
153 
154     if( (result.header.type==XANDROIDBINARY_DEF::RES_XML_TYPE)||
155         (result.header.type==XANDROIDBINARY_DEF::RES_TABLE_TYPE)||
156         (result.header.type==XANDROIDBINARY_DEF::RES_TABLE_PACKAGE_TYPE))
157     {
158         qint64 nCurrentOffset=nOffset+result.header.header_size;
159 
160         while(nCurrentOffset<result.header.data_size)
161         {
162             RECORD record=getRecord(nCurrentOffset);
163 
164             result.listChildren.append(record);
165 
166             nCurrentOffset+=record.header.data_size;
167         }
168     }
169 
170     return result;
171 }
172 
recordToString(XAndroidBinary::RECORD * pRecord)173 QString XAndroidBinary::recordToString(XAndroidBinary::RECORD *pRecord)
174 {
175     QString sResult;
176 
177     if(pRecord->header.type==XANDROIDBINARY_DEF::RES_XML_TYPE)
178     {
179         QXmlStreamWriter xml(&sResult);
180 
181         xml.setAutoFormatting(true);
182         xml.writeStartDocument("1.0",false);
183 
184         int nNumberOfChildren=pRecord->listChildren.count();
185         QList<QString> listStrings;
186         QList<quint32> listResources;
187         QStack<QString> stackPrefix;
188         QStack<QString> stackURI;
189 
190         for(int i=0;i<nNumberOfChildren;i++)
191         {
192             if(pRecord->listChildren.at(i).header.type==XANDROIDBINARY_DEF::RES_STRING_POOL_TYPE)
193             {
194                 XANDROIDBINARY_DEF::HEADER_STRING_POOL headerStringPool=readHeaderStringPool(pRecord->listChildren.at(i).nOffset);
195 
196                 qint64 nCurrentOffset=pRecord->listChildren.at(i).nOffset+headerStringPool.header.header_size;
197                 qint64 nStringsDataOffset=pRecord->listChildren.at(i).nOffset+headerStringPool.stringsStart;
198 
199                 for(quint32 j=0;j<headerStringPool.stringCount;j++)
200                 {
201                     qint64 nStringOffset=nStringsDataOffset+read_int32(nCurrentOffset+j*sizeof(quint32));
202 
203                     QString sString;
204                     quint16 nStringSize=read_uint16(nStringOffset);
205 
206                     if(headerStringPool.flags)
207                     {
208                         sString=read_ansiString(nStringOffset+sizeof(quint16),nStringSize);
209                     }
210                     else
211                     {
212                         sString=read_unicodeString(nStringOffset+sizeof(quint16),nStringSize);
213                     }
214 
215                     listStrings.append(sString);
216                 }
217             }
218             else if(pRecord->listChildren.at(i).header.type==XANDROIDBINARY_DEF::RES_XML_RESOURCE_MAP_TYPE)
219             {
220                 int nNumberOfResources=(pRecord->listChildren.at(i).header.data_size-sizeof(XANDROIDBINARY_DEF::HEADER))/4;
221 
222                 qint64 nCurrentOffset=pRecord->listChildren.at(i).nOffset+sizeof(XANDROIDBINARY_DEF::HEADER);
223 
224                 for(int j=0;j<nNumberOfResources;j++)
225                 {
226                     quint32 nID=read_uint32(nCurrentOffset+j*sizeof(quint32));
227 
228 //                    qDebug("Resource ID %x",nID);
229 
230                     listResources.append(nID);
231                 }
232             }
233             else if(pRecord->listChildren.at(i).header.type==XANDROIDBINARY_DEF::RES_XML_START_NAMESPACE_TYPE)
234             {
235                 XANDROIDBINARY_DEF::HEADER_NAMESPACE headerNamespace=readHeaderNamespace(pRecord->listChildren.at(i).nOffset);
236 
237                 stackPrefix.push(getStringByIndex(&listStrings,headerNamespace.prefix));
238                 stackURI.push(getStringByIndex(&listStrings,headerNamespace.uri));
239 
240                 xml.writeNamespace(stackURI.top(),stackPrefix.top());
241             }
242             else if(pRecord->listChildren.at(i).header.type==XANDROIDBINARY_DEF::RES_XML_END_NAMESPACE_TYPE)
243             {
244                 stackPrefix.pop();
245                 stackURI.pop();
246             }
247             else if(pRecord->listChildren.at(i).header.type==XANDROIDBINARY_DEF::RES_XML_START_ELEMENT_TYPE)
248             {
249                 XANDROIDBINARY_DEF::HEADER_XML_START headerXmlStart=readHeaderXmlStart(pRecord->listChildren.at(i).nOffset);
250 
251 //                qDebug("idIndex %d",headerXmlStart.idIndex);
252 //                qDebug("classIndex %d",headerXmlStart.classIndex);
253 //                qDebug("styleIndex %d",headerXmlStart.styleIndex);
254 
255                 QString sNS=getStringByIndex(&listStrings,headerXmlStart.ns);
256                 QString sName=getStringByIndex(&listStrings,headerXmlStart.name);
257 
258                 xml.writeStartElement(sNS,sName);
259 
260                 qint64 nCurrentOffset=pRecord->listChildren.at(i).nOffset+sizeof(XANDROIDBINARY_DEF::HEADER_XML_START);
261 
262                 for(int j=0;j<headerXmlStart.attributeCount;j++)
263                 {
264                     XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE headerXmlAttribute=readHeaderXmlAttribute(nCurrentOffset);
265 
266                     QString sValue;
267 
268                     if(headerXmlAttribute.dataType==1) // TODO Const
269                     {
270                         sValue="@"+QString::number(headerXmlAttribute.data,16);
271                     }
272                     else if(headerXmlAttribute.dataType==3) // TODO Const
273                     {
274                         sValue=getStringByIndex(&listStrings,headerXmlAttribute.data);
275                     }
276                     else if(headerXmlAttribute.dataType==16) // TODO Const
277                     {
278                         sValue=QString::number(headerXmlAttribute.data);
279                     }
280                     else if(headerXmlAttribute.dataType==17) // TODO Const // Flgas
281                     {
282                         sValue="0x"+QString::number(headerXmlAttribute.data,16);
283                     }
284                     else if(headerXmlAttribute.dataType==18) // TODO Const
285                     {
286                         sValue=(headerXmlAttribute.data==0xFFFFFFFF)?"true":"false";
287                     }
288 //                    else
289 //                    {
290 //                        sValue="0x"+QString::number(headerXmlAttribute.data,16);
291 //                    }
292 //                    else
293 //                    {
294 //                        qDebug("headerXmlAttribute.dataType %d %s: %x",headerXmlAttribute.dataType,getStringByIndex(&listStrings,headerXmlAttribute.name).toLatin1().data(),headerXmlAttribute.data);
295 //                        int z=0;
296 //                        z++;
297 //                    }
298                     // TODO More types
299 
300                     QString sNS_Attribute=getStringByIndex(&listStrings,headerXmlAttribute.ns);
301                     QString sName_Attribute=getStringByIndex(&listStrings,headerXmlAttribute.name);
302 
303                     if(sName_Attribute==":")
304                     {
305                         sName_Attribute="";
306                     }
307 
308                     xml.writeAttribute(sNS_Attribute,sName_Attribute,sValue);
309 
310                     nCurrentOffset+=sizeof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE);
311                 }
312             }
313             else if(pRecord->listChildren.at(i).header.type==XANDROIDBINARY_DEF::RES_XML_END_ELEMENT_TYPE)
314             {
315 //                XANDROIDBINARY_DEF::HEADER_XML_END headerXmlEnd=readHeaderXmlEnd(pRecord->listChildren.at(i).nOffset);
316 
317                 xml.writeEndElement();
318             }
319 //            else
320 //            {
321 //                qDebug("Record %x",pRecord->listChildren.at(i).header.type);
322 //            }
323         }
324 
325         xml.writeEndDocument();
326     }
327 
328     return sResult;
329 }
330 
getDecoded(QIODevice * pDevice)331 QString XAndroidBinary::getDecoded(QIODevice *pDevice)
332 {
333     QString sResult;
334 
335     XAndroidBinary xab(pDevice);
336     RECORD record=xab.getRecord(0);
337     sResult=xab.recordToString(&record);
338 
339     return sResult;
340 }
341 
getDecoded(QString sFileName)342 QString XAndroidBinary::getDecoded(QString sFileName)
343 {
344     QString sResult;
345 
346     QFile file;
347     file.setFileName(sFileName);
348 
349     if(file.open(QIODevice::ReadOnly))
350     {
351         sResult=getDecoded(&file);
352 
353         file.close();
354     }
355 
356     return sResult;
357 }
358 
getDecoded(QByteArray * pbaData)359 QString XAndroidBinary::getDecoded(QByteArray *pbaData)
360 {
361     QString sResult;
362 
363     QBuffer buffer;
364 
365     buffer.setBuffer(pbaData);
366 
367     if(buffer.open(QIODevice::ReadOnly))
368     {
369         sResult=getDecoded(&buffer);
370 
371         buffer.close();
372     }
373 
374     return sResult;
375 }
376 
377