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