/* * Copyright (C) 2012 Sony Mobile Communications AB * * This file is part of ApkAnalyser. * * 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 analyser.logic; import gui.Canceable; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.zip.ZipEntry; import mereflect.AbstractClassContext; import mereflect.CollaborateClassContext; import mereflect.CorruptBytecodeException; import mereflect.JarClassContext; import mereflect.MEClass; import mereflect.MEClassContext; import mereflect.MEClassResource; import mereflect.MEField; import mereflect.MEMethod; import mereflect.UnknownClass; import mereflect.UnknownContext; import mereflect.UnknownField; import mereflect.UnknownMethod; import mereflect.UnknownResContext; import mereflect.UnknownResSpec; import mereflect.UnknownResource; import mereflect.io.DescriptorParser; import org.jf.dexlib.FieldIdItem; import analyser.Analyser; import analyser.gui.Settings; import andreflect.ApkClassContext; import andreflect.DexMethod; import andreflect.DexReferenceCache; import andreflect.DexReferenceCache.LoadConstRes; import andreflect.DexResSpec; import andreflect.Util; import andreflect.xml.XmlParser; import andreflect.xml.XmlParser.XmlLine; import brut.androlib.res.data.ResResSpec; public class Resolver { /** Map with resolved context references on classpaths side, key String(ctxName), value RefContext */ protected Map<String, Reference> m_refContexts = new TreeMap<String, Reference>(); /** Map with resolved context references on midlets side, key String(ctxName), value RefContext */ protected Map<String, Reference> m_midContexts = new TreeMap<String, Reference>(); protected ResolverListener m_listener = null; protected CollaborateClassContext m_sctx; protected UnknownContext m_uCtx = null; protected UnknownResContext m_uResCtx = null; public CollaborateClassContext getReferenceContext() { return m_sctx; } public void removeMidlet(MEClassContext ctx) { m_midContexts.remove(Analyser.getContextName(ctx)); } public void setListener(ResolverListener list) { m_listener = list; } /** * Looks up all invokations on midlets side and registers them in midContext map. * All found are also mirrored in refContext map for quicker lookup. * @param c * @throws IOException * @throws ClassNotFoundException */ public void resolve(Canceable c) throws IOException, ClassNotFoundException { Analyser a = new Analyser(Settings.getSettings()); List<File> midlets = new ArrayList<File>(); List<File> apks = new ArrayList<File>(); a.getMidlets(midlets); a.getApks(apks); if (midlets.isEmpty() && apks.isEmpty()) { throw new IllegalArgumentException("No Apk or midlets found"); } int midletSize = midlets.size(); int apkSize = apks.size(); int midletIdx = 0; int apkIdx = 0; for (midletIdx = 0; c.isRunning() && midletIdx < midletSize; midletIdx++) { File midletFile = midlets.get(midletIdx); resolve(midletFile, c, apkIdx + midletIdx, midletSize + apkSize); } for (apkIdx = 0; c.isRunning() && apkIdx < apkSize; apkIdx++) { System.out.println((apks.get(apkIdx)).getName()); } for (apkIdx = 0; c.isRunning() && apkIdx < apkSize; apkIdx++) { File apkFile = apks.get(apkIdx); resolveApk(apkFile, c, apkIdx + midletIdx, midletSize + apkSize); } if (m_listener != null && midletIdx >= midletSize - 1 && apkIdx >= apkSize - 1) { m_listener.resolved(); } } public void resolve(File midletFile, Canceable c, int midletIndex, int midletCount) throws IOException, ClassNotFoundException { // Get class context for path entries if (m_sctx == null) { Analyser a = new Analyser(Settings.getSettings()); m_sctx = new CollaborateClassContext(); a.setClasspath(m_sctx); DescriptorParser.setSuperContext(m_sctx); // Set supercontext } // Resolve midlet JarClassContext midletCtx = new JarClassContext(midletFile, true); if (m_midContexts.containsKey(Analyser.getContextName(midletCtx))) { // Already resolved return; } // Go through all classes in context String[] cNames = midletCtx.getClassnames(); for (int iC = 0; c.isRunning() && iC < cNames.length; iC++) { MEClass mClass = midletCtx.getMEClass(cNames[iC]); MEMethod[] mMethods = mClass.getMethods(); if (mMethods == null) { continue; } // Go through all methods for (int iM = 0; c.isRunning() && iM < mMethods.length; iM++) { boolean methFail = false; boolean methNotFound = false; MEMethod mMethod = mMethods[iM]; if (m_listener != null) { m_listener.resolving(midletIndex, midletCount, iC, cNames.length, iM, mMethods.length, midletCtx, mClass, mMethod); } List<MEMethod.Invokation> invokations = null; // Key string(invokation), value integer(nbrOfInvokations) Iterator<MEMethod.Invokation> iI = null; try { invokations = mMethod.getInvokations(); iI = invokations.iterator(); } catch (CorruptBytecodeException cbe) { methFail = true; } if (!methFail && (iI == null || !iI.hasNext())) { // No invokations in this method buildEmptyRef(midletCtx, mClass, mMethod, null, null); } // Go through all invokations in method while (c.isRunning() && iI != null && iI.hasNext()) { MEMethod.Invokation inv = iI.next(); boolean externalInvokation = false; // Try getting invoked class from midlet jar try { MEClass rLocalClass = midletCtx.getMEClass(inv.invClassname); boolean showAllInvocations = true; if (showAllInvocations) { MEMethod rLocalMethod = rLocalClass.getMethod(inv.invMethodname, inv.invDescriptor); methNotFound = true; rLocalMethod = new UnknownMethod(inv.invMethodname, inv.invDescriptor, rLocalClass); buildRef(midletCtx, mClass, mMethod, methFail, methNotFound, null, rLocalClass, rLocalMethod, inv, null, null); } } catch (ClassNotFoundException cnfe) { externalInvokation = true; } // Could not get invoked class from midlet jar, try api classes if (externalInvokation) { try { MEClass rClass = m_sctx.getMEClass(inv.invClassname); MEMethod rMethod = rClass.getMethod(inv.invMethodname, inv.invDescriptor); if (rMethod == null) { // Invoked method not found in api class, make an unknown method reference methNotFound = true; rMethod = new UnknownMethod(inv.invMethodname, inv.invDescriptor, rClass); } MEClassResource rRsc = rClass.getResource(); MEClassContext rCtx = rRsc.getContext(); buildRef(midletCtx, mClass, mMethod, methFail, methNotFound, rCtx, rClass, rMethod, inv, null, null); } catch (ClassNotFoundException e) { // Class not found in api classes, make an unknown resource reference methNotFound = true; if (m_uCtx == null) { m_uCtx = new UnknownContext(); } UnknownClass uClass = null; try { uClass = (UnknownClass) m_uCtx.getMEClass(inv.invClassname); } catch (ClassNotFoundException cnfe) { UnknownResource uRes = new UnknownResource(inv.invClassname, m_uCtx); uClass = new UnknownClass(inv.invClassname, uRes); m_uCtx.defineClass(uClass); } UnknownMethod uMethod = null; uMethod = (UnknownMethod) uClass.getMethod(inv.invMethodname, inv.invDescriptor); if (uMethod == null) { uMethod = new UnknownMethod(inv.invMethodname, inv.invDescriptor, uClass); } buildRef(midletCtx, mClass, mMethod, methFail, methNotFound, m_uCtx, uClass, uMethod, inv, null, null); } // unknown class } // external invokation } // per invokation } // per method } // per class } public void resolveApk(File apkFile, Canceable c, int apkIndex, int apkCount) throws IOException, ClassNotFoundException { //workaround ArrayList<Object> objs = new ArrayList<Object>(); ArrayList<ReverseReference> refs = new ArrayList<ReverseReference>(); if (m_sctx == null) { Analyser a = new Analyser(Settings.getSettings()); m_sctx = new CollaborateClassContext(); a.setClasspath(m_sctx); DescriptorParser.setSuperContext(m_sctx); // Set supercontext } // Resolve apk ApkClassContext apkCtx = new ApkClassContext(apkFile, true); if (m_midContexts.containsKey(Analyser.getContextName(apkCtx))) { // Already resolved return; } if (apkCtx.getXmlParser().getManifest() != null) { RefContext midResource = (RefContext) m_midContexts.get(Analyser.getContextName(apkCtx)); if (midResource == null) { midResource = new RefContext(apkCtx); m_midContexts.put(Analyser.getContextName(apkCtx), midResource); } ZipEntry manifest = apkCtx.getXmlParser().visitFile(XmlParser.MANIFEST); RefAndroidManifest refManifest = midResource.registerManifest(manifest); objs.add(manifest); refs.add(refManifest); } String[] cNames = apkCtx.getClassnames(); for (int iC = 0; c.isRunning() && iC < cNames.length; iC++) { MEClass mClass = apkCtx.getMEClass(cNames[iC]); RefContext refContext = (RefContext) m_midContexts.get(Analyser.getContextName(apkCtx)); if (refContext == null) { refContext = new RefContext(apkCtx); m_midContexts.put(Analyser.getContextName(apkCtx), refContext); } String refPackName = mClass.getResource().getPackage(); RefPackage refPack = refContext.registerPackage(refPackName); refPack.registerClass(mClass); try { for (MEClass parent : InvSnooper.findClassParents(mClass)) { MEClass p = parent; Map<String, Reference> contextTree = m_midContexts; if (p instanceof UnknownClass) { String pname = parent.getName(); contextTree = m_refContexts; try { p = m_sctx.getMEClass(pname); } catch (ClassNotFoundException e) { if (m_uCtx == null) { m_uCtx = new UnknownContext(); } try { p = m_uCtx.getMEClass(pname); } catch (ClassNotFoundException cnfe) { UnknownResource uRes = new UnknownResource(pname, m_uCtx); p = new UnknownClass(pname, uRes); m_uCtx.defineClass((UnknownClass) p); } } } MEClassContext ctx = p.getResource().getContext(); RefContext rContext = (RefContext) contextTree.get(Analyser.getContextName(ctx)); if (rContext == null) { rContext = new RefContext(ctx); contextTree.put(Analyser.getContextName(ctx), rContext); } String packname = p.getResource().getPackage(); RefPackage refPackage = rContext.registerPackage(packname); refPackage.registerClass(p); } } catch (Throwable e1) { e1.printStackTrace(); } MEMethod[] mMethods = mClass.getMethods(); if (mMethods == null) { continue; } // Go through all methods for (int iM = 0; c.isRunning() && iM < mMethods.length; iM++) { boolean methFail = false; boolean methNotFound = false; MEMethod mMethod = mMethods[iM]; if (m_listener != null) { m_listener.resolving(apkIndex, apkCount, iC, cNames.length, iM, mMethods.length, apkCtx, mClass, mMethod); } List<MEMethod.Invokation> invokations = null; // Key string(invokation), value integer(nbrOfInvokations) Iterator<MEMethod.Invokation> iI = null; try { invokations = mMethod.getInvokations(); iI = invokations.iterator(); } catch (CorruptBytecodeException cbe) { methFail = true; } if (!methFail && (iI == null || !iI.hasNext())) { // No invokations in this method buildEmptyRef(apkCtx, mClass, mMethod, objs, refs); } // Go through all invokations in method while (c.isRunning() && iI != null && iI.hasNext()) { MEMethod.Invokation inv = iI.next(); boolean found = false; MEClass rClassFound = null; MEClass localClassFound = null; // Try getting invoked class from midlet jar try { MEClass rLocalClass = apkCtx.getMEClass(inv.invClassname); MEMethod rLocalMethod = rLocalClass.getMethod(inv.invMethodname, inv.invDescriptor); if (rLocalMethod != null) { buildRef(apkCtx, mClass, mMethod, methFail, methNotFound, null, rLocalClass, rLocalMethod, inv, objs, refs); found = true; } else { localClassFound = rLocalClass; } } catch (ClassNotFoundException cnfe) { } if (found) { continue; } // Could not get invoked class from midlet jar, try api classes try { MEClass rClass = m_sctx.getMEClass(inv.invClassname); MEMethod rMethod = rClass.getMethod(inv.invMethodname, inv.invDescriptor); if (rMethod != null) { MEClassResource rRsc = rClass.getResource(); MEClassContext rCtx = rRsc.getContext(); buildRef(apkCtx, mClass, mMethod, methFail, methNotFound, rCtx, rClass, rMethod, inv, objs, refs); found = true; } else { rClassFound = rClass; } } catch (ClassNotFoundException e) { } if (found) { continue; } if (localClassFound != null) { String unknownSuperClassName = localClassFound.getUnknownSuperClassName(); if (unknownSuperClassName != null) { try { MEClass rClass = m_sctx.getMEClass(unknownSuperClassName); MEMethod rMethod = rClass.getMethod(inv.invMethodname, inv.invDescriptor); if (rMethod != null) { MEClassResource rRsc = rClass.getResource(); MEClassContext rCtx = rRsc.getContext(); buildRef(apkCtx, mClass, mMethod, methFail, methNotFound, rCtx, rClass, rMethod, inv, objs, refs); found = true; } else if (rClassFound == null) { rClassFound = rClass; } } catch (ClassNotFoundException e) { } } } if (found) { continue; } if (localClassFound != null) { methNotFound = true; MEMethod u = new UnknownMethod(inv.invMethodname, inv.invDescriptor, localClassFound); buildRef(apkCtx, mClass, mMethod, methFail, methNotFound, null, localClassFound, u, inv, objs, refs); } else if (rClassFound != null) { methNotFound = true; MEMethod u = new UnknownMethod(inv.invMethodname, inv.invDescriptor, rClassFound); MEClassResource rRsc = rClassFound.getResource(); MEClassContext rCtx = rRsc.getContext(); buildRef(apkCtx, mClass, mMethod, methFail, methNotFound, rCtx, rClassFound, u, inv, objs, refs); } else { // Class not found in api classes, make an unknown resource reference methNotFound = true; if (m_uCtx == null) { m_uCtx = new UnknownContext(); } UnknownClass uClass = null; try { uClass = (UnknownClass) m_uCtx.getMEClass(inv.invClassname); } catch (ClassNotFoundException cnfe) { UnknownResource uRes = new UnknownResource(inv.invClassname, m_uCtx); uClass = new UnknownClass(inv.invClassname, uRes); m_uCtx.defineClass(uClass); } UnknownMethod uMethod = null; uMethod = (UnknownMethod) uClass.getMethod(inv.invMethodname, inv.invDescriptor); if (uMethod == null) { uMethod = new UnknownMethod(inv.invMethodname, inv.invDescriptor, uClass); } buildRef(apkCtx, mClass, mMethod, methFail, methNotFound, m_uCtx, uClass, uMethod, inv, objs, refs); } // unknown class } // per invokation }//per method }// per class //build field ref for (int iC = 0; c.isRunning() && iC < cNames.length; iC++) { MEClass mClass = apkCtx.getMEClass(cNames[iC]); MEField[] mFields = mClass.getFields(); if (mFields != null) { for (int iF = 0; c.isRunning() && iF < mFields.length; iF++) { if (m_listener != null) { m_listener.resolvingField(apkIndex, apkCount, iC, cNames.length, iF, mFields.length, apkCtx, mClass, mFields[iF]); } buildField(m_midContexts, apkCtx, mClass, mFields[iF], false); } } } ArrayList<DexReferenceCache.FieldAccess> accesses = apkCtx.getDexReferenceCache().getFieldAccesses(); for (int iAcc = 0; c.isRunning() && iAcc < accesses.size(); iAcc++) { DexReferenceCache.FieldAccess access = accesses.get(iAcc); if (m_listener != null) { m_listener.resolvingFieldAccess(apkIndex, apkCount, iAcc, accesses.size(), apkCtx, access); } FieldIdItem item = access.fieldIdItem; String className = Util.getClassName(item.getContainingClass().getTypeDescriptor()); String fieldType = item.getFieldType().getTypeDescriptor(); String fieldName = item.getFieldName().getStringValue(); boolean found = false; MEClass rClassFound = null; MEClass localClassFound = null; try { MEClass clazz = apkCtx.getMEClass(className); MEField field = clazz.getField(fieldName, fieldType); if (field != null) { buildFieldRef(m_midContexts, apkCtx, clazz, field, access, false, objs, refs); found = true; } else { localClassFound = clazz; } } catch (ClassNotFoundException cnfe) { } if (found) { continue; } try { MEClass rClass = m_sctx.getMEClass(className); MEField rField = rClass.getField(fieldName, fieldType); if (rField != null) { MEClassResource rRsc = rClass.getResource(); MEClassContext rCtx = rRsc.getContext(); buildFieldRef(m_refContexts, rCtx, rClass, rField, access, false, objs, refs); found = true; } else { rClassFound = rClass; } } catch (ClassNotFoundException e) { } if (found) { continue; } if (localClassFound != null) { String unknownSuperClassName = localClassFound.getUnknownSuperClassName(); if (unknownSuperClassName != null) { try { MEClass rClass = m_sctx.getMEClass(unknownSuperClassName); MEField rField = rClass.getField(fieldName, fieldType); if (rField != null) { MEClassResource rRsc = rClass.getResource(); MEClassContext rCtx = rRsc.getContext(); buildFieldRef(m_refContexts, rCtx, rClass, rField, access, false, objs, refs); found = true; } else if (rClassFound == null) { rClassFound = rClass; } } catch (ClassNotFoundException e) { } } } if (found) { continue; } if (localClassFound != null) { MEField u = new UnknownField(fieldName, fieldType, localClassFound); buildFieldRef(m_midContexts, apkCtx, localClassFound, u, access, true, objs, refs); } else if (rClassFound != null) { MEField u = new UnknownField(fieldName, fieldType, rClassFound); MEClassResource rRsc = rClassFound.getResource(); MEClassContext rCtx = rRsc.getContext(); buildFieldRef(m_refContexts, rCtx, rClassFound, u, access, true, objs, refs); } else { // Class not found in api classes, make an unknown resource reference if (m_uCtx == null) { m_uCtx = new UnknownContext(); } UnknownClass uClass = null; try { uClass = (UnknownClass) m_uCtx.getMEClass(className); } catch (ClassNotFoundException cnfe) { UnknownResource uRes = new UnknownResource(className, m_uCtx); uClass = new UnknownClass(className, uRes); m_uCtx.defineClass(uClass); } UnknownField uField = null; uField = (UnknownField) uClass.getField(fieldName, fieldType); if (uField == null) { uField = new UnknownField(fieldName, fieldType, uClass); } buildFieldRef(m_refContexts, m_uCtx, uClass, uField, access, true, objs, refs); } // unknown class } if (apkCtx.getXmlParser().getManifest() != null && c.isRunning()) { ///xmls ArrayList<ZipEntry> xmlentries = apkCtx.getXmlParser().getXmlFiles(); for (int iXml = 0; c.isRunning() && iXml < xmlentries.size(); iXml++) { ZipEntry xml = xmlentries.get(iXml); if (xml.getName().equals(XmlParser.MANIFEST)) { continue; } RefContext context = (RefContext) m_midContexts.get(Analyser.getContextName(apkCtx)); if (context == null) { context = new RefContext(apkCtx); m_midContexts.put(Analyser.getContextName(apkCtx), context); } RefFolder refFolder = context.registerSubFolder("xml", RefFolder.XML); RefXml refxml = new RefXml(xml, apkCtx); objs.add(xml); refs.add(refxml); refFolder.registerChild(xml.getName(), refxml); } //android resources Set<ResResSpec> specs = apkCtx.getDexReferenceCache().getSpecs(); Iterator<ResResSpec> iSpec = specs.iterator(); int specCnt = 0; while (c.isRunning() && iSpec != null && iSpec.hasNext()) { ResResSpec spec = iSpec.next(); DexResSpec dexSpec = new DexResSpec(spec); apkCtx.getDexReferenceCache().putDexSpec(spec, dexSpec); buildResSpec(m_midContexts, apkCtx, dexSpec, apkCtx, dexSpec.getType(), true, objs, refs); if (m_listener != null) { m_listener.resolvingResource(apkIndex, apkCount, specCnt, specs.size() * 2, apkCtx, spec); } specCnt++; } iSpec = specs.iterator(); specCnt = 0; while (c.isRunning() && iSpec != null && iSpec.hasNext()) { ResResSpec spec = iSpec.next(); DexResSpec dexSpec = new DexResSpec(spec, apkCtx.getDexReferenceCache().findResInternalRefenence(spec.getId().id), apkCtx.getXmlParser().findXmlInternalRefenence(spec.getId().id), apkCtx.getDexReferenceCache().findCodeInternalRefenence(spec.getId().id)); apkCtx.getDexReferenceCache().putDexSpec(spec, dexSpec); buildResSpecRef(m_midContexts, apkCtx, dexSpec, apkCtx, dexSpec.getType(), true, objs, refs); if (m_listener != null) { m_listener.resolvingResource(apkIndex, apkCount, specCnt + specs.size(), specs.size() * 2, apkCtx, spec); } specCnt++; } HashSet<Integer> externalids = new HashSet<Integer>(); externalids.addAll(apkCtx.getDexReferenceCache().listResExternalReference()); externalids.addAll(apkCtx.getXmlParser().listXmlExternalReference()); externalids.addAll(apkCtx.getDexReferenceCache().listCodeExternalReference()); MEClassContext[] contexts = m_sctx.getContexts(); Iterator<Integer> iExtResId = externalids.iterator(); while (c.isRunning() && iExtResId.hasNext()) { int id = iExtResId.next(); if (id == 0) { continue;//special for @null } HashSet<ResResSpec> specRef = apkCtx.getDexReferenceCache().findResExternalRefenence(id); ArrayList<XmlLine> xmlRef = apkCtx.getXmlParser().findXmlExternalRefenence(id); ArrayList<LoadConstRes> codeRef = apkCtx.getDexReferenceCache().findCodeExternalRefenence(id); String foldername = null; boolean found = false; for (int iContext = 0; c.isRunning() && iContext < contexts.length; iContext++) { MEClassContext context = contexts[iContext]; DexReferenceCache cache = context.getDexReferenceCache(); if (cache != null) { ResResSpec spec = cache.getSpec(id); if (spec != null) { DexResSpec dexSpec = new DexResSpec(spec, specRef, xmlRef, codeRef); apkCtx.getDexReferenceCache().putDexSpec(spec, dexSpec); buildResSpecRef(m_refContexts, context, dexSpec, apkCtx, dexSpec.getType(), true, objs, refs); found = true; break; } else if (cache.isSamePackage(id)) { foldername = Analyser.getContextName(context); } } } if (!found && specRef.size() + xmlRef.size() != 0 //ignore code const ) { UnknownResSpec spec = new UnknownResSpec(id); DexResSpec dexSpec = new DexResSpec(spec, specRef, xmlRef, codeRef); if (m_uResCtx == null) { m_uResCtx = new UnknownResContext(); } buildResSpecRef(m_refContexts, m_uResCtx, dexSpec, apkCtx, foldername == null ? "Unknown Package" : foldername, false, objs, refs); } } } } protected RefResSpec buildResSpec(Map<String, Reference> treeContext, MEClassContext mMEContext, DexResSpec dexSpec, ApkClassContext rContext, String foldername, boolean addRes, ArrayList<Object> objs, ArrayList<ReverseReference> refs) { RefContext midResource = (RefContext) treeContext.get(Analyser.getContextName(mMEContext)); if (midResource == null) { midResource = new RefContext(mMEContext); treeContext.put(Analyser.getContextName(mMEContext), midResource); } RefFolder refFolder; if (addRes) { refFolder = midResource.registerResSubFolder(foldername); } else { refFolder = midResource.registerSubFolder(foldername, foldername.equals("Unknown Package") ? RefFolder.UNKNOWN : RefFolder.RES); } RefResSpec refResSpec = new RefResSpec(dexSpec, rContext); refResSpec = (RefResSpec) refFolder.registerChild(dexSpec.getName(), refResSpec); if (objs != null && refs != null) { objs.add(dexSpec.getResSpec()); refs.add(refResSpec); } return refResSpec; } protected void buildResSpecRef(Map<String, Reference> treeContext, MEClassContext mMEContext, DexResSpec dexSpec, ApkClassContext rContext, String foldername, boolean addRes, ArrayList<Object> objs, ArrayList<ReverseReference> refs) { if (dexSpec.getSumReference() == 0) { return; } RefResSpec refResSpec = buildResSpec(treeContext, mMEContext, dexSpec, rContext, foldername, addRes, null, null); //not record twice Iterator<ResResSpec> iSpec = dexSpec.getResReference().iterator(); while (iSpec.hasNext()) { ResResSpec specRef = iSpec.next(); ReverseReference reverse = refs.get(objs.indexOf(specRef)); RefResReference refResRef = refResSpec.registerResReference(specRef, RefResReference.RESREF, reverse); reverse.addReferredReference(refResRef, treeContext == m_midContexts); } Iterator<XmlParser.XmlLine> iXmlLine = dexSpec.getXmlReference().iterator(); while (iXmlLine.hasNext()) { XmlLine xmlRef = iXmlLine.next(); ReverseReference reverse = refs.get(objs.indexOf(xmlRef.entry)); RefResReference refResRef = refResSpec.registerResReference(xmlRef, RefResReference.XML, reverse); reverse.addReferredReference(refResRef, treeContext == m_midContexts); } Iterator<DexReferenceCache.LoadConstRes> iCode = dexSpec.getCodeReference().iterator(); while (iCode.hasNext()) { DexReferenceCache.LoadConstRes loadConst = iCode.next(); ReverseReference reverse = refs.get(objs.indexOf(loadConst.method)); RefResReference refResRef = refResSpec.registerResReference(loadConst, RefResReference.CODE, reverse); reverse.addReferredReference(refResRef, treeContext == m_midContexts); } } protected RefField buildField(Map<String, Reference> treeContext, MEClassContext mMEContext, MEClass mMEClass, MEField mMEField, boolean fieldNotFound) { int flags = (fieldNotFound && treeContext == m_midContexts) ? Reference.NOTFOUND : 0; RefContext resourceContext = (RefContext) treeContext.get(Analyser.getContextName(mMEContext)); if (resourceContext == null) { resourceContext = new RefContext(mMEContext); treeContext.put(Analyser.getContextName(mMEContext), resourceContext); } resourceContext.setFlags(resourceContext.getFlags() | flags); String midPackName = mMEClass.getResource().getPackage(); RefPackage midPack = resourceContext.registerPackage(midPackName); midPack.setFlags(midPack.getFlags() | flags); RefClass midClass = midPack.registerClass(mMEClass); midClass.setFlags(midClass.getFlags() | flags); RefField refField = midClass.registerField(mMEField); refField.setFlags(refField.getFlags() | flags); return refField; } protected void buildFieldRef(Map<String, Reference> treeContext, MEClassContext mMEContext, MEClass mMEClass, MEField mMEField, DexReferenceCache.FieldAccess access, boolean fieldNotFound, ArrayList<Object> objs, ArrayList<ReverseReference> refs) { access.setMEField(mMEField, mMEClass); int flags = (fieldNotFound && treeContext == m_midContexts) ? Reference.NOTFOUND : 0; RefField refField = buildField(treeContext, mMEContext, mMEClass, mMEField, fieldNotFound); ReverseReference reverse = refs.get(objs.indexOf(access.method)); RefFieldAccess refAccess = new RefFieldAccess(access, (RefMethod) reverse); refAccess.setFlags(flags); reverse.addReferredReference(refAccess, treeContext == m_midContexts); refField.registerAccess(refAccess); } protected void buildEmptyRef(AbstractClassContext mContext, MEClass mClass, MEMethod mMethod, ArrayList<Object> objs, ArrayList<ReverseReference> refs) { RefContext refContext = (RefContext) m_midContexts.get(Analyser.getContextName(mContext)); if (refContext == null) { refContext = new RefContext(mContext); m_midContexts.put(Analyser.getContextName(mContext), refContext); } String refPackName = mClass.getResource().getPackage(); RefPackage refPack = refContext.registerPackage(refPackName); RefClass refClass = refPack.registerClass(mClass); RefMethod refMethod = refClass.registerMethod(mMethod); if (mMethod instanceof DexMethod && objs != null && refs != null && objs.contains(mMethod) == false) { objs.add(mMethod); refs.add(refMethod); } if (mMethod instanceof UnknownMethod) { refMethod.setFlags(refMethod.getFlags() | Reference.NOTFOUND); } } protected void buildRef( AbstractClassContext mMEContext, MEClass mMEClass, MEMethod mMEMethod, boolean methFail, boolean methNotFound, MEClassContext rMEContext, MEClass rMEClass, MEMethod rMEMethod, MEMethod.Invokation invokation, ArrayList<Object> objs, ArrayList<ReverseReference> refs) { invokation.setMethod(rMEMethod, rMEClass); int flags = (methFail ? Reference.FAILED : 0) | (methNotFound ? Reference.NOTFOUND : 0); RefInvokation refInv = null; RefInvokation midInv = null; RefMethod refMethod = null; RefMethod midMethod = null; // Ref side if (rMEContext != null) { String refInvStr = mMEClass.getName() + "." + mMEMethod.getFormattedName() + "(" + mMEMethod.getArgumentsString() + ")"; RefContext refContext = (RefContext) m_refContexts.get(Analyser.getContextName(rMEContext)); if (refContext == null) { refContext = new RefContext(rMEContext); m_refContexts.put(Analyser.getContextName(rMEContext), refContext); } String refPackName = rMEClass.getResource().getPackage(); RefPackage refPack = refContext.registerPackage(refPackName); RefClass refClass = refPack.registerClass(rMEClass); refMethod = refClass.registerMethod(rMEMethod); if (rMEMethod instanceof UnknownMethod) { refMethod.setFlags(refMethod.getFlags() | Reference.NOTFOUND); } refInv = new RefInvokation(refInvStr, refContext, refPack, refClass, refMethod, false, invokation); } // Midlet side if (mMEContext != null) { String midInvStr = rMEClass.getName() + "." + rMEMethod.getFormattedName() + "(" + rMEMethod.getArgumentsString() + ")"; RefContext midResource = (RefContext) m_midContexts.get(Analyser.getContextName(mMEContext)); if (midResource == null) { midResource = new RefContext(mMEContext); m_midContexts.put(Analyser.getContextName(mMEContext), midResource); } midResource.setFlags(midResource.getFlags() | flags); String midPackName = mMEClass.getResource().getPackage(); RefPackage midPack = midResource.registerPackage(midPackName); midPack.setFlags(midPack.getFlags() | flags); RefClass midClass = midPack.registerClass(mMEClass); midClass.setFlags(midClass.getFlags() | flags); midMethod = midClass.registerMethod(mMEMethod); if (mMEMethod instanceof DexMethod && objs != null && refs != null && objs.contains(mMEMethod) == false) { objs.add(mMEMethod); refs.add(midMethod); } midMethod.setFlags(midMethod.getFlags() | flags); midInv = new RefInvokation(midInvStr, midResource, midPack, midClass, midMethod, rMEContext == null, invokation); midInv.setFlags(flags); } // Coupling if (refInv != null && midInv != null) { refInv.setOppositeInvokation(midInv); midInv.setOppositeInvokation(refInv); } if (refMethod != null && refInv != null) { refMethod.registerInvokation(refInv); } if (midMethod != null && midInv != null) { midMethod.registerInvokation(midInv); } } public Collection<Reference> getReferenceResources() { return m_refContexts.values(); } public Collection<Reference> getMidletResources() { return m_midContexts.values(); } }