/** * Find Security Bugs * Copyright (c) Philippe Arteau, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ package com.h3xstream.findsecbugs.android; import com.h3xstream.findsecbugs.common.ByteCode; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.Detector; import edu.umd.cs.findbugs.Priorities; import edu.umd.cs.findbugs.ba.CFG; import edu.umd.cs.findbugs.ba.CFGBuilderException; import edu.umd.cs.findbugs.ba.ClassContext; import edu.umd.cs.findbugs.ba.Location; import org.apache.bcel.classfile.*; import org.apache.bcel.generic.ALOAD; import org.apache.bcel.generic.ASTORE; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.INVOKESPECIAL; import org.apache.bcel.generic.INVOKEVIRTUAL; import org.apache.bcel.generic.Instruction; import java.util.*; import org.apache.bcel.generic.InstructionHandle; import com.h3xstream.findsecbugs.common.StringCodeAnalysis; /** * Created by blackarbiter on 17/8/2. */ public class LocalDenialOfServiceDetector implements Detector{ private static final String LOCAL_DENIAL_SERVICE_TYPE = "LOCAL_DENIAL_SERVICE"; private BugReporter bugReporter; public LocalDenialOfServiceDetector(BugReporter bugReporter) { this.bugReporter = bugReporter; } @Override public void visitClassContext(ClassContext classContext) { JavaClass javaClass = classContext.getJavaClass(); Method[] methodList = javaClass.getMethods(); for (Method m : methodList) { try { analyzeMethod(javaClass, m, classContext); } catch (CFGBuilderException e) { } } } private void analyzeMethod(JavaClass javaClass, Method m, ClassContext classContext) throws CFGBuilderException { HashMap<String, List<Location>> all_line_location = (HashMap<String, List<Location>>) get_line_location(m, classContext); Code code = m.getCode(); StringCodeAnalysis sca = new StringCodeAnalysis(code); String[] codes = sca.codes_String_Array(); int code_length = sca.get_Code_Length(sca.get_First_Code(codes)); int[] exception_scop = sca.getExceptionScope(); for(int i=1; i<codes.length; i++){ int line_index = sca.get_code_line_index(codes[i]); if (line_index < code_length){ if(codes[i].toLowerCase().contains("invokevirtual") && (codes[i].contains("android.content.Intent.get") || codes[i].contains("android.os.Bundle.get"))){ if(exception_scop.length == 0){ String method_name = get_method_name(codes[i]); if(all_line_location.containsKey(method_name)){ for(Location loc : all_line_location.get(method_name)){ bugReporter.reportBug(new BugInstance(this, LOCAL_DENIAL_SERVICE_TYPE, Priorities.NORMAL_PRIORITY) // .addClass(javaClass) .addMethod(javaClass, m) .addSourceLine(classContext, m, loc)); } }else { bugReporter.reportBug(new BugInstance(this, LOCAL_DENIAL_SERVICE_TYPE, Priorities.NORMAL_PRIORITY) // .addClass(javaClass) .addMethod(javaClass, m)); // .addSourceLine(classContext, m, )); } }else{ boolean is_scope = false; for(int j=0; j<exception_scop.length; j+=2){ int start = exception_scop[j]; int end = exception_scop[j+1]; if(line_index >= start && line_index <= end){ is_scope = true; } if(is_scope){ break; } } if(!is_scope){ String method_name = get_method_name(codes[i]); if(all_line_location.containsKey(method_name)){ for(Location loc : all_line_location.get(method_name)){ bugReporter.reportBug(new BugInstance(this, LOCAL_DENIAL_SERVICE_TYPE, Priorities.NORMAL_PRIORITY) // .addClass(javaClass) .addMethod(javaClass, m) .addSourceLine(classContext, m, loc)); } }else { bugReporter.reportBug(new BugInstance(this, LOCAL_DENIAL_SERVICE_TYPE, Priorities.NORMAL_PRIORITY) // .addClass(javaClass) .addMethod(javaClass, m)); // .addSourceLine(classContext, m, )); } } } } } } } private Map<String, List<Location>> get_line_location(Method m, ClassContext classContext){ HashMap<String, List<Location>> all_line_location = new HashMap<>(); ConstantPoolGen cpg = classContext.getConstantPoolGen(); CFG cfg = null; try { cfg = classContext.getCFG(m); } catch (CFGBuilderException e) { e.printStackTrace(); return all_line_location; } for (Iterator<Location> i = cfg.locationIterator(); i.hasNext(); ) { Location loc = i.next(); Instruction inst = loc.getHandle().getInstruction(); if(inst instanceof INVOKEVIRTUAL) { INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) inst; // if (classname.equals(invoke.getClassName(cpg)) && // methodName.equals(invoke.getMethodName(cpg))) { if(all_line_location.containsKey(invoke.getMethodName(cpg))){ all_line_location.get(invoke.getMethodName(cpg)).add(loc); }else { LinkedList<Location> loc_list = new LinkedList<>(); loc_list.add(loc); all_line_location.put(invoke.getMethodName(cpg), loc_list); } // } } } return all_line_location; } private String get_class_name(String code_line){ if(code_line.contains("android.content.Intent")){ return "android.content.Intent"; } return "android.os.Bundle"; } private String get_method_name(String code_line){ try { String class_name = get_class_name(code_line); String[] split1 = code_line.split(class_name + "."); String method_name = split1[1].split(" ")[0].trim(); return method_name; }catch (Exception e){ // e.printStackTrace(); } return "error_get_method_name"; } @Override public void report() { } }