100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com/* 200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * [The "BSD licence"] 300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke) 400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * All rights reserved. 500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without 700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions 800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * are met: 900fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright 1000fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * notice, this list of conditions and the following disclaimer. 1100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright 1200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * notice, this list of conditions and the following disclaimer in the 1300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * documentation and/or other materials provided with the distribution. 1400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products 1500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * derived from this software without specific prior written permission. 1600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 1700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1900fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2000fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com */ 2800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com 290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.compackage org.jf.dexlib.Code.Analysis; 300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport org.jf.dexlib.*; 320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 33a91109b8a76def18c4d0342a44a87ad270d379abBen Gruverimport java.util.ArrayList; 340c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport java.util.LinkedList; 350c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport java.util.regex.Matcher; 360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport java.util.regex.Pattern; 370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.compublic class DeodexUtil { 390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public static final int Virtual = 0; 400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public static final int Direct = 1; 410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public static final int Static = 2; 420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 43595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com private final InlineMethodResolver inlineMethodResolver; 442880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com 450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public final DexFile dexFile; 460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public DeodexUtil(DexFile dexFile) { 480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com this.dexFile = dexFile; 492880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com OdexHeader odexHeader = dexFile.getOdexHeader(); 502880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com if (odexHeader == null) { 512880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com //if there isn't an odex header, why are we creating an DeodexUtil object? 522880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com assert false; 532880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com throw new RuntimeException("Cannot create a DeodexUtil object for a dex file without an odex header"); 542880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com } 55595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com inlineMethodResolver = InlineMethodResolver.createInlineMethodResolver(this, odexHeader.version); 560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 585967598d012839eb25d50d9fa63952ac802e05ddBen Gruver public DeodexUtil(DexFile dexFile, InlineMethodResolver inlineMethodResolver) { 595967598d012839eb25d50d9fa63952ac802e05ddBen Gruver this.dexFile = dexFile; 605967598d012839eb25d50d9fa63952ac802e05ddBen Gruver this.inlineMethodResolver = inlineMethodResolver; 615967598d012839eb25d50d9fa63952ac802e05ddBen Gruver } 625967598d012839eb25d50d9fa63952ac802e05ddBen Gruver 63595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com public InlineMethod lookupInlineMethod(AnalyzedInstruction instruction) { 64595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com return inlineMethodResolver.resolveExecuteInline(instruction); 650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 67ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver public FieldIdItem lookupField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass, 68ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver int fieldOffset) { 69ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver ClassPath.FieldDef field = instanceClass.getInstanceField(fieldOffset); 700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (field == null) { 710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 74ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver return parseAndResolveField(accessingClass, instanceClass, field); 750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)"); 780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 79ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass, 80650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver int methodIndex) { 81ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver String method = instanceClass.getVirtualMethod(methodIndex); 8241265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com if (method == null) { 8341265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com return null; 8441265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com } 850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com Matcher m = shortMethodPattern.matcher(method); 870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (!m.matches()) { 880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com assert false; 890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com throw new RuntimeException("Invalid method descriptor: " + method); 900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com String methodName = m.group(1); 930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com String methodParams = m.group(2); 940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com String methodRet = m.group(3); 950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 96ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver if (instanceClass instanceof ClassPath.UnresolvedClassDef) { 97343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver //if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual 98343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver //method being looked up was a method on java.lang.Object. 99ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver instanceClass = ClassPath.getClassDef("Ljava/lang/Object;"); 100ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver } else if (instanceClass.isInterface()) { 101ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver instanceClass = instanceClass.getSuperclass(); 102ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver assert instanceClass != null; 1030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 105ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver return parseAndResolveMethod(accessingClass, instanceClass, methodName, methodParams, methodRet); 1060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 108650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass, 109650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver String methodName, String methodParams, String methodRet) { 1100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName); 1110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (methodNameItem == null) { 1120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 1130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com LinkedList<TypeIdItem> paramList = new LinkedList<TypeIdItem>(); 1160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com for (int i=0; i<methodParams.length(); i++) { 1180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com TypeIdItem typeIdItem; 1190c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1200c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com switch (methodParams.charAt(i)) { 1210c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'Z': 1220c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'B': 1230c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'S': 1240c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'C': 1250c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'I': 1260c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'J': 1270c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'F': 1280c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'D': 1290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i,i+1)); 1300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com break; 1310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'L': 1320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com { 1330c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com int end = methodParams.indexOf(';', i); 1340c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (end == -1) { 1350c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com throw new RuntimeException("invalid parameter in the method"); 1360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1)); 1390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com i = end; 1400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com break; 1410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case '[': 1430c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com { 1440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com int end; 1450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com int typeStart = i+1; 1460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com while (typeStart < methodParams.length() && methodParams.charAt(typeStart) == '[') { 1470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com typeStart++; 1480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com switch (methodParams.charAt(typeStart)) { 1500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'Z': 1510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'B': 1520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'S': 1530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'C': 1540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'I': 1550c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'J': 1560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'F': 1570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'D': 1580c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com end = typeStart; 1590c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com break; 1600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com case 'L': 1610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com end = methodParams.indexOf(';', typeStart); 1620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (end == -1) { 1630c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com throw new RuntimeException("invalid parameter in the method"); 1640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com break; 1660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com default: 1670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com throw new RuntimeException("invalid parameter in the method"); 1680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1)); 1710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com i = end; 1720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com break; 1730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com default: 1750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com throw new RuntimeException("invalid parameter in the method"); 1760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (typeIdItem == null) { 1790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 1800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com paramList.add(typeIdItem); 1820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com TypeListItem paramListItem = null; 1850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (paramList.size() > 0) { 1860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com paramListItem = TypeListItem.lookupTypeListItem(dexFile, paramList); 1870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (paramListItem == null) { 1880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 1890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com TypeIdItem retType = TypeIdItem.lookupTypeIdItem(dexFile, methodRet); 1930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (retType == null) { 1940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 1950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 1960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 1970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com ProtoIdItem protoItem = ProtoIdItem.lookupProtoIdItem(dexFile, retType, paramListItem); 1980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (protoItem == null) { 1990c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 2000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2010c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 202650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver ClassPath.ClassDef methodClassDef = definingClass; 2030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com do { 2050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType()); 2060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (classTypeItem != null) { 2080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem); 209650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver if (methodIdItem != null && checkClassAccess(accessingClass, methodClassDef)) { 2100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return methodIdItem; 2110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com methodClassDef = methodClassDef.getSuperclass(); 2150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } while (methodClassDef != null); 2160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 2170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 219650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver private static boolean checkClassAccess(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass) { 220650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver return definingClass.isPublic() || 221650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver getPackage(accessingClass.getClassType()).equals(getPackage(definingClass.getClassType())); 222650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver } 223650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver 224650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver private static String getPackage(String classRef) { 225650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver int lastSlash = classRef.lastIndexOf('/'); 226650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver if (lastSlash < 0) { 227650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver return ""; 228650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver } 229650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver return classRef.substring(1, lastSlash); 230650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver } 231650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver 232ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver /** 233ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver * 234ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver * @param accessingClass The class that contains the field reference. I.e. the class being deodexed 235ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver * @param instanceClass The inferred class type of the object that the field is being accessed on 236ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver * @param field The field being accessed 237ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver * @return The FieldIdItem of the resolved field 238ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver */ 239ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver private FieldIdItem parseAndResolveField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass, 240ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver ClassPath.FieldDef field) { 241a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver String definingClass = field.definingClass; 242a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver String fieldName = field.name; 243a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver String fieldType = field.type; 2440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com StringIdItem fieldNameItem = StringIdItem.lookupStringIdItem(dexFile, fieldName); 2460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (fieldNameItem == null) { 2470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 2480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com TypeIdItem fieldTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldType); 2510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (fieldTypeItem == null) { 2520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 2530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 255ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver ClassPath.ClassDef fieldClass = instanceClass; 2560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 257a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>(); 258a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver parents.add(fieldClass); 259a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver 260a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver while (fieldClass != null && !fieldClass.getClassType().equals(definingClass)) { 261a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver fieldClass = fieldClass.getSuperclass(); 262a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver parents.add(fieldClass); 263a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver } 264a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver 265a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver for (int i=parents.size()-1; i>=0; i--) { 266a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver fieldClass = parents.get(i); 267a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver 2680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldClass.getClassType()); 2690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (classTypeItem == null) { 2700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com continue; 2710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem); 274ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver if (fieldIdItem != null && checkClassAccess(accessingClass, fieldClass)) { 2750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return fieldIdItem; 2760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 277a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver } 2780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return null; 2790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2815967598d012839eb25d50d9fa63952ac802e05ddBen Gruver public static class InlineMethod { 2820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public final int methodType; 2830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public final String classType; 2840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public final String methodName; 2850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public final String parameters; 2860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public final String returnType; 2870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com private MethodIdItem methodIdItem = null; 2890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 290595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com InlineMethod(int methodType, String classType, String methodName, String parameters, 2910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com String returnType) { 2920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com this.methodType = methodType; 2930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com this.classType = classType; 2940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com this.methodName = methodName; 2950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com this.parameters = parameters; 2960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com this.returnType = returnType; 2970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 2980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 2995967598d012839eb25d50d9fa63952ac802e05ddBen Gruver public MethodIdItem getMethodIdItem(DeodexUtil deodexUtil) { 3000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com if (methodIdItem == null) { 3015967598d012839eb25d50d9fa63952ac802e05ddBen Gruver loadMethod(deodexUtil); 3020c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 3030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return methodIdItem; 3040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 3050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 3065967598d012839eb25d50d9fa63952ac802e05ddBen Gruver private void loadMethod(DeodexUtil deodexUtil) { 3070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com ClassPath.ClassDef classDef = ClassPath.getClassDef(classType); 3080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 309650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, classDef, methodName, parameters, 310650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver returnType); 3110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 3120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com 3130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com public String getMethodString() { 3140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com return String.format("%s->%s(%s)%s", classType, methodName, parameters, returnType); 3150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 3160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com } 3170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com} 318