/**
* 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.common;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
import org.apache.bcel.generic.*;
public class ByteCode {
public static void printOpCode(InstructionHandle insHandle, ConstantPoolGen cpg) {
System.out.print("[" + String.format("%02d", insHandle.getPosition()) + "] ");
printOpCode(insHandle.getInstruction(),cpg);
}
/**
* Print the the detail of the given instruction (class, method, etc.)
*
* @param ins Instruction
* @param cpg Constant Pool
*/
public static void printOpCode(Instruction ins, ConstantPoolGen cpg) {
if (ins instanceof InvokeInstruction) {
InvokeInstruction invokeIns = (InvokeInstruction) ins;
System.out.println(formatName(ins) + " " + invokeIns.getClassName(cpg).replaceAll("\\.", "/") + "." + invokeIns.getMethodName(cpg) + invokeIns.getSignature(cpg));
} else if (ins instanceof LDC) {
LDC i = (LDC) ins;
System.out.println(formatName(ins) + " \""+i.getValue(cpg).toString()+"\"");
} else if (ins instanceof NEW) {
NEW i = (NEW) ins;
ObjectType type = i.getLoadClassType(cpg);
System.out.println(formatName(ins) + " " + type.toString());
} else if (ins instanceof LoadInstruction) {
LoadInstruction i = (LoadInstruction) ins;
System.out.println(formatName(ins) +" "+i.getIndex() + " => [stack]");
} else if (ins instanceof StoreInstruction) {
StoreInstruction i = (StoreInstruction) ins;
System.out.println(formatName(ins) +" (objectref) => "+i.getIndex() + "");
} else if (ins instanceof FieldInstruction) {
FieldInstruction i = (FieldInstruction) ins;
System.out.println(formatName(ins) +" "+i.getFieldName(cpg) + "");
} else if (ins instanceof IfInstruction) {
IfInstruction i = (IfInstruction) ins;
System.out.println(formatName(ins) +" target => "+i.getTarget().toString()+ "");
} else if (ins instanceof ICONST) {
ICONST i = (ICONST) ins;
System.out.println(formatName(ins) +" "+i.getValue()+" ("+i.getType(cpg)+")");
} else if (ins instanceof GOTO) {
GOTO i = (GOTO) ins;
System.out.println(formatName(ins) +" target => "+i.getTarget().toString());
} else {
System.out.println(formatName(ins));
}
}
/**
* Align the instruction to make the output more readable.
* @param ins Instruction to print
* @return Output the name with 15 pad characters (always 15 chars output)
*/
private static String formatName(Instruction ins) {
return String.format("%-15s",ins.getName());
}
/**
* Get the constant value of the given instruction.
* (The instruction must refer to the Constant Pool otherwise null is return)
*
* <T> is the Type of the constant value return
*
*
* This utility method should be used only when the taint analysis is not needed.
* For example, to detect api where the value will typically be hardcoded.
* (Call such as setConfig("valueHardcoded"), setActivateStuff(true) )
*
* @param h Instruction Handle
* @param cpg Constant Pool
* @param clazz Type of the constant being read
* @return The constant value if any is found
*/
public static <T> T getConstantLDC(InstructionHandle h, ConstantPoolGen cpg, Class<T> clazz) {
Instruction prevIns = h.getInstruction();
if (prevIns instanceof LDC) {
LDC ldcInst = (LDC) prevIns;
Object val = ldcInst.getValue(cpg);
if (val.getClass().equals(clazz)) {
return clazz.cast(val);
}
}
else if(clazz.equals(String.class) && prevIns instanceof INVOKESPECIAL) {
//This additionnal call allow the support of hardcoded value passed to String constructor
//new String("HARDCODE")
INVOKESPECIAL invoke = (INVOKESPECIAL) prevIns;
if(invoke.getMethodName(cpg).equals("<init>") && invoke.getClassName(cpg).equals("java.lang.String") &&
invoke.getSignature(cpg).equals("(Ljava/lang/String;)V")) {
return getConstantLDC(h.getPrev(), cpg, clazz);
}
}
return null;
}
public static Integer getConstantInt(InstructionHandle h) {
Instruction prevIns = h.getInstruction();
if (prevIns instanceof ICONST) {
ICONST ldcCipher = (ICONST) prevIns;
Number num = ldcCipher.getValue();
return num.intValue();
}
return null;
}
/**
* Extract the number from a push operation (BIPUSH/SIPUSH).
*
* @param h Instruction Handle
* @return The constant number if any is found
*/
public static Number getPushNumber(InstructionHandle h) {
Instruction prevIns = h.getInstruction();
if (prevIns instanceof BIPUSH) {
BIPUSH ldcCipher = (BIPUSH) prevIns;
return ldcCipher.getValue();
} else if (prevIns instanceof SIPUSH) {
SIPUSH ldcCipher = (SIPUSH) prevIns;
return ldcCipher.getValue();
}
return null;
}
/**
* Get the previous instruction matching the given type of instruction (second parameter)
*
* @param startHandle Location to start from
* @param clazz Type of instruction to look for
* @return The instruction found (null if not found)
*/
public static <T> T getPrevInstruction(InstructionHandle startHandle, Class<T> clazz) {
InstructionHandle curHandle = startHandle;
while (curHandle != null) {
curHandle = curHandle.getPrev();
if (curHandle != null && clazz.isInstance(curHandle.getInstruction())) {
return clazz.cast(curHandle.getInstruction());
}
}
return null;
}
}