From 7d22fc66b56547a345555cc4cfdc4b21dedcfe82 Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Thu, 14 Dec 2017 09:11:08 -0500 Subject: [PATCH] Initial testing of private namespace - added sample (removed attribute names) --- .../res/decoder/AXmlResourceParser.java | 27 +++++-- .../java/brut/androlib/MinifiedArscTest.java | 76 ++++++++++++++++++ .../brut/apktool/issue1157/issue1157.apk | Bin 0 -> 5323 bytes 3 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 brut.apktool/apktool-lib/src/test/java/brut/androlib/MinifiedArscTest.java create mode 100644 brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1157/issue1157.apk diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java index c1e2deae..17c6f2ae 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java @@ -19,6 +19,7 @@ package brut.androlib.res.decoder; import android.content.res.XmlResourceParser; import android.util.TypedValue; import brut.androlib.AndrolibException; +import brut.androlib.res.data.ResID; import brut.androlib.res.xml.ResXmlEncoders; import brut.util.ExtDataInput; import com.google.common.io.LittleEndianDataInputStream; @@ -288,16 +289,15 @@ public class AXmlResourceParser implements XmlResourceParser { return ""; } - // hacky: if the attribute names are proguarded, then so are the namespace - // I don't know where these are located yet in the file, but it is always - // this.android_ns in testing, so we will default to that for now. - // @todo figure out where proguarded namespaces are stored. + // Minifiers like removing the namespace, so we will default to default namespace + // unless the pkgId of the resource is private. We will grab the non-standard one. String value = m_strings.getString(namespace); if (value.length() == 0) { - int offsetName = getAttributeOffset(index); - int name = m_attributes[offsetName + ATTRIBUTE_IX_NAME]; - if (m_strings.getString(name).length() == 0) { + ResID resourceId = new ResID(getAttributeNameResource(index)); + if (resourceId.package_ == PRIVATE_PKG_ID) { + value = getNonDefaultNamespaceUri(); + } else { value = android_ns; } } @@ -305,6 +305,17 @@ public class AXmlResourceParser implements XmlResourceParser { return value; } + private String getNonDefaultNamespaceUri() { + int offset = m_namespaces.getCurrentCount() + 1; + String prefix = m_strings.getString(m_namespaces.get(offset, true)); + + if (! prefix.equalsIgnoreCase("android")) { + return m_strings.getString(m_namespaces.get(offset, false)); + } + + return android_ns; + } + @Override public String getAttributePrefix(int index) { int offset = getAttributeOffset(index); @@ -999,4 +1010,6 @@ public class AXmlResourceParser implements XmlResourceParser { CHUNK_XML_END_NAMESPACE = 0x00100101, CHUNK_XML_START_TAG = 0x00100102, CHUNK_XML_END_TAG = 0x00100103, CHUNK_XML_TEXT = 0x00100104, CHUNK_XML_LAST = 0x00100104; + + private static final int PRIVATE_PKG_ID = 0x7F; } diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/MinifiedArscTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/MinifiedArscTest.java new file mode 100644 index 00000000..31c0fb5a --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/MinifiedArscTest.java @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2017 Ryszard Wiśniewski + * Copyright (C) 2017 Connor Tumbleson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package brut.androlib; + +import brut.directory.ExtFile; +import brut.common.BrutException; +import brut.util.OS; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import static org.junit.Assert.assertEquals; + +/** + * @author Connor Tumbleson + */ +public class MinifiedArscTest { + + @BeforeClass + public static void beforeClass() throws Exception { + TestUtils.cleanFrameworkFile(); + sTmpDir = new ExtFile(OS.createTempDirectory()); + TestUtils.copyResourceDir(MinifiedArscTest.class, "brut/apktool/issue1157/", sTmpDir); + + String apk = "issue1157.apk"; + sDecodedDir = new ExtFile(sTmpDir, "issue1157"); + + // decode issue1157.apk + ApkDecoder apkDecoder = new ApkDecoder(new ExtFile(sTmpDir, apk)); + apkDecoder.setOutDir(sDecodedDir); + + // this should not raise an exception: + apkDecoder.decode(); + } + + @AfterClass + public static void afterClass() throws BrutException { + OS.rmdir(sTmpDir); + } + + @Test + public void checkIfMinifiedArscLayoutFileMatchesTest() throws IOException { + String expected = TestUtils.replaceNewlines("\n" + + ""); + + byte[] encoded = Files.readAllBytes(Paths.get(sDecodedDir + File.separator + "res" + File.separator + "xml" + File.separator + "custom.xml")); + String obtained = TestUtils.replaceNewlines(new String(encoded)); + assertEquals(expected, obtained); + } + + private static ExtFile sDecodedDir; + private static ExtFile sTmpDir; +} \ No newline at end of file diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1157/issue1157.apk b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1157/issue1157.apk new file mode 100644 index 0000000000000000000000000000000000000000..4c1e67202493b1675449053560b0110f140a9797 GIT binary patch literal 5323 zcmds5cUV)+(mzQc0i*;$kRFjHQl%-qg(^isqzKYN4JCxGfS^*84uVod5Je42lcw?_ zMLGcyL1__?rqTqY!*_yu_4U1f-S40K+&#~nnVsF4-Tj>{v&UE;M!^gK02N38phvM| zoDyRmOB?4;LX`Rz%*nxV!; zw?j8mHgf`qHeUOWM7M0z<2{h~lIf$DHSX3NSQh40)?q4ze5G+b{E;P}=6w{gY=t+L zgC-^ma@Q8x0pmJHkzS|pL1{sGjrk%&z9Ao6KoxS1Qm!uG14DOo$@7=G67&Lf?Y4{` z)gV>2Tra3cDEnVFe-Nmmn~S*c!F}QI8rv2;6cGm9O8?drauw3U+xY=-fpox_e36Q9 z`tSx6O?(9L8u4Hn{mXZ(5gpbkC>j13fsc^U3fJauC^UD`(*)I?N)8IiB_{qOU-|g( zA)Kh$F+}W=?cn9b-gf*A{=wLSk3*?(2OqK~Z(=eXa5>nr?wnVzR3-VYC}(9BYqqIB z!SON^t++_>-wrf}T-upBG-EcXg4m4HQ=B5qcIEEMZXi(Aa|5BQ-^7I%r$@wh9pE=F zu*`2AsR^imu5j__i|3825drlVqykUAoria2dLdM7Ij_%0oqoMuy{O^5WdY|tO41%d zQ_8Ez)f{|@$aeqme7xvg*Eke$N9v2zwA%DJrukx;Y=^HSv-iBMeJ75c=(GMXvwEj& zcTjjxbXr&`uZ>8uN{8}Xy&)$?`Ij(yEq9yQ3`x*}b??$_A{isXkhl9Yr-KS&wpU&w zmqkTXljL1$=WuV$duv685O#BcHrgNAdReX7=ErFI`eQ?PMwOx%@a8VLQ}H2~L3;d+ z;gO2;?I0Eru`e$eJVcvulmn?6%9tho93i;!%th^*by>GDrOnR_CFh@%;Gbw8-KpDw zJmhH0h{RMmYjO#&c83qM`HTwvHth&0fd7mH`gu$!fQUv_=!hk`0T^%F&f?MuQ?zqlU>{&eB;5EU=g{}&b<-u*q6*>ztTA4y>zis%F$Iw94L z=gDT*pL;40C77I-#YC!px@KdbdpE7~Q@oU?n|?gSP3J}Dr+J#V`t37PK9R(mHeE{2QAmuDf)` z;J!uPvA*wHcY@9fJO^{fApo!+*XN^ig8BIY3fyxS?v$=i>vDE z)r%`zTt{KlYcQ6G^WHXQw8@A7#xEUF>t4^?H23XuzJ>AkxA5mz7ok8&ygZ=FLHCYh z{4#x6JLj?flSicRlP{#`^*lIdTTgkqx^tb1e?4t{X5zHF7egu=&n-n9IzzLf<>`@x zfu#PpsN*{hH~muQu07&wFj3a4QF-lnEE`r%mAiKT7Bay|EZn$@gQrS{%6#>BL{s|t zZKN^v=f2OgmCcx%VOQ4=fe|VPgXGYMzchUapP?cAl4)1;3YH-;POc%pn3!QyslA+XYNhn2;!o14R zx7s{bP(He9wwg7m_g7C$;R1D^9KH5b?2O(x?(}4Cu&4n)x-?nd)UpV}dA`$C-kQzC zT02SWFsuAijYC?zr!c2P{d(DgY{Y0*1j@rN@F$-X;cqNY+fXlH3z0}LT-=SKcW}0a z3ag5&y~UxIZi87b{L5EgIy_w@QlS&RQwW>pE>be`fNgZe7~-14s=iG!e)gGAOEpiR|8bq%$| z4b%*Ewa_M}Vg_0s@$H@wssMVGZwq#zp2JOMCL)SP2<1}Zk7#%x1j9HLFRYf|pE>Lw zgipa6Ccd5E-Y=YwOeuXRn8n*B;^2otQ@Y>u#+z$ooie9dN8KbwVz9Jcn@cjEp>mkI zPMn!(;u}p1Q}aknJ#F2*+?r3c(j#-H*^CG`MJmIfs$ju$A0Ams^<~RWVl-CnkFsME z@H|%;bF$>F*+1VY9t%GuwD^XB-IVQ6Vl?HK`J^+t+Rk4;anD`~2+%E2cfHSP`7Zbd z{?k)uH@=y^1aUR-U3Gh%eD_=md3BEEutE|sZ+fh?jsA7r-Ly!VcN%%}s?ZG|+~Q_; zoRZN6g_>P{IWBnr5G|88$z8xu+MuV|BRhTSJ$23WhJ8m7OHieew%L2QYR}TWLSBWc zQ!2pU0p2(5Jzxofy95&QcYrm}r%lC7v^-vu!DYTQszg2ivNTRDF;lOH68hLojj?>p z(^iWUoycaqFryzUaNl3V zR*8$wY+)`7$&VIU;u%E)5&40GioQ?y$8OiO58a9KPsz?d{ueGh>hKX5|5>Iwh}zIR zcrLf5Go)E8t@3$wG`%1lNA{kG!I(EuYUkruSMHLY#J7^hUQf-4L8#>yDxNAX z72h%tZB|}wz(`n_HN<~S<%_0?Gmh4?bZp)&`Bu!#a8Kr19ZJG5%9wy-a2pIRDRp|| z4mb4Nw_c9is_J@oKkEjcTh*oR>9>Ph+-Ce`GUE5-Pra=!{6erV)}7UrE124rkAG1% zZauE|&2!}Z-@n6t9(Ln%;Lbq_?ktS|_ztH{)TCVOogBw|-IiQ7iR~@Kr*~pzQq-8< zCP?geu?%z>2j`(B9LAD5M|zQ3W_M2GH6&q- zvXjOvPTV%lFH-ZiI+!Wbd-HpIH6SqM#N(_C3Z_GegO`~2>IFKO*|8`=qPvTyi=&IZ zi=(}(J(8d34*dx2yzJd7SA|n9

|K^ZbI5aQWishIPE@Z6_d>ED?l9h zbTAd|)j_)GqBS~MIroOvV|i&uNT1t}^sU5qWq@wjFZnMIy?gq#?D`{Ai}KR1aQ)V< z$`5-S4;*bR@DwbXob?S09UFcVP4%`TY*d>*=Qw6r7~41Ehr`l3-{>lr=_*pnX}eu= z8VkQm=-=gX;+e{MkX6{;*wJ!{`$~suz^z6PC1O==X!u}^1na%b@~-lg?PZ@vi%^5m zTK}@z=?E9bIS0j9whHPCSEf?uq<1*+0t)WIHEo}!+9L`N$oVq+4khba43|cfs0433 zXRV}}JGO4bYT>bfw^$cZSem=EwDCpTOkqf6+rG6rzASiZpR7>ETmA#rS(`$P<*KV? zzeIR%u{AUmz~d5BU%PAgztmtt_{gj49eo*S>x!Kg*K4VKKpVW1zhu@;FmuktFvuR= z&>I$xDb5ydUkJI7dwr-$H`6UXwC~OSpk2*Ge2 z9cfC5nP@(Io)kL^SX${mpaRm} zaQ!HWjwWcLok4E>r96M=3@LzzenTc^0<1R*l0*b#7$hwy1R_BPrxuRXiCm?FKqx5z z2{}m?31&F#3%vIfosJ!2xl%}OUJCwWX# zTJo6m326ySRyt`g3;O$>{m&hT=ltGB2qgduj{_vaW1!*TK-!2HWxnhM>;MhR{;Lyp zs8HbWfp4v)XBrisGJIhuL0fS1kGw9v5E^WiyE6^}Dws#rDoruRc}n*)Rt^ zyPpG}Jllj;>s!xi?WvZz33GFP*PXMC4J~cQKAC0IJh6cTorj5$mvch8FbJ22EH@!& zz1=F=#hjL)6j3OM{GSlQzFls7|a!|rIcm}&C951BeDZYYLjrPxTBe_UpC;EomZ zz9w3Ti<0dNrYyf|sikur?r!N}e1xg{rxgwrM|(#Pa5@sMJb)xvrO!-PgPl;y4)cZnk!396*_>3m{zr&yPF@gdnzdps-7Wc>eIgLHlIRR*2lj<-cf>?eD*`II%>V&*U*vPe-EYuD&=l2q{sPviD^>NNi- zCN1^7ZDFKpcl*vlj7x9QNX}xoMe=5MNWi1$?O}#>VU`^rJh}NB;+S8S&PRD6S-u^5 z!}M{3sB^_j^&fN%3_R?(CWosydO5hG zq>mZvL%;<`PX9it{9Z_@clr}dxV+b?Sf&2QGf1#^FT`123oFArqtxBr1;!|#RP$NlFO{Fh-B scp?4g1@o8v_nLpd*Z#5wfV?lZi~oWD19oqi^8f$< literal 0 HcmV?d00001