2015-06-02 72 views
0

我正在Findbugs中編寫自定義檢測器。我想知道是否有什麼方法可以跟蹤ASTORE及相應的ALOAD指令?也就是說,如果ASTORE 3在我的字節碼出現,我想先確定它是一個ASTORE指令,然後它指數(在這種情況下:3),並尋找ALOAD具有相同指數的指令(在這種情況下, ALOAD 3指令)。Findbugs:自定義檢測器

例如在字節碼如下所示,我想讀ASTORE 8指令(出現在導線#29),並查看是否有任何ALOAD指令與索引 。 I.e,ALOAD 8(可在#73行上看到)。

29: astore  8 
    31: aload_1  
    32: iconst_0  
    . 
    . 
    . 
    . 
    . 
    . 
    60: ldc   #54     // String number 
    62: aload   11 
    64: invokeinterface #56, 3   // InterfaceMethod javax/servlet/http/HttpSession.setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V 
    69: aload   12 
    71: aload   7 
    73: aload   8 
    75: invokeinterface #62, 3   // InterfaceMethod com/ibm/itim/ws/services/WSSessionService.getNumber:(Ljava/lang/String;Ljava/lang/String;)Lcom/ibm/itim/ws/model/WSSession; 
    80: astore  14 

此外,如果我找到相應的ALOAD指令,那麼我想檢查哪個方法被調用。我知道可以使用sawOpcode()方法進行檢查,如下所示:

if (seen == INVOKEINTERFACE){...} 

總之,我想要做這樣的事情:

僞代碼

public void sawOpcode(int seen) { 
    if (seen == ASTORE){ 
     //code to identify its index i; i.e, ASTORE i 
     if(seen == ALOAD_i){ 
      //if the corresponding ALOAD instruction is found... 
      if(seen == INVOKEINTERFACE){ 

       // Identify the method invoked 

      } 
     } 

不要知道上述方法是否正確。

+0

作爲FindBugs的開發者,我可以幫你,但是現在你的問題有點含糊。我想你不會對每一個ASTORE感興趣,而是尋找一些特定的情況(例如,特定字符串的ASTORE,或者空的ASTORE,或之前GETFIELD或以前方法調用的結果的ASTORE)。你能更準確地描述這一部分:你在尋找哪些價值?請注意,即使您配對了,也並不意味着您加載了與分支目標相同的值(循環開始等)。通常值應該被跟蹤,而不是寄存器。 –

+0

我正在尋找特定字符串的ASTORE。例如。 String name = request.getParameter(「name」)。該語句在字節碼中被翻譯爲「ALOAD 1. LDC」name「。 INVOKEINTERFACE。 ASTORE 7'。現在我想跟蹤這個ASORE 7找到ALOAD 7. @Tagir – Manoj

+0

我編輯了我的答案並提供了更詳細的示例。隨意問你是否仍有問題。 –

回答

2

對於簡單情況,最好延長OpcodeStackDetector。這個抽象類支持跟蹤堆棧值並存儲關於它們的信息。您不應該關心ASTORE,ALOAD等。只需檢查INVOKEINTERFACE。例如,如果你想找到的地方,最後一個方法參數是另一種方法的返回值,你可以做到以下幾點:

public void sawOpcode(int seen) { 
    if(seen == INVOKEINTERFACE && getMethodDescriptorOperand().getSlashedClassName() 
     .equals("com/ibm/itim/ws/services/WSSessionService") && 
     getMethodDescriptorOperand().getName().equals("getNumber')) 
    Item topStackItem = getStack().getStackItem(0); 
    XMethod returnOf = topStackItem.getReturnValueOf(); 
    if(returnOf != null && returnOf.getName().equals("getParameter")) 
     // here we go 
    } 
} 

您可以getStackItem呼籲改變0到其他號碼來獲得其他操作數以及。不幸的是,您可以通過這種方式知道該值是getParameter方法的返回值,但不知道在該方法中使用了哪些參數。

如果您需要跟蹤更復雜的情況,那麼最好使用ValueNumberAnalysis。它簡單而強大的概念:它爲靜態證明是相同的值分配相同的數字。假設你想跟蹤所有的請求參數。讓我們做的方法進入一些製劑(例如visitCode):

private ValueNumberDataflow vna; 
private Map<ValueNumber, String> vnToParameterName; 

@Override 
public void visit(Code code) { 
    try { 
     this.vna = getClassContext().getValueNumberDataflow(getMethod()); 
    } catch (DataflowAnalysisException | CFGBuilderException e) { 
     bugReporter.logError("Unable to get VNA for "+getMethodDescriptor(), e); 
     return; 
    } 
    this.vnToParameterName = new HashMap<>(); 
    super.visit(code); 
} 

Map將被用於存儲值和對應的參數名稱。這可以在sawOpcode

@Override 
public void sawOpcode(int seen) { 
    if(seen == INVOKEINTERFACE) { 
     if(getNameConstantOperand().equals("getParameter") && 
       getSigConstantOperand().equals("(Ljava/lang/String;)Ljava/lang/String;") 
       /* && check the class if necessary */) { 
      Object topValue = getStack().getStackItem(0).getConstant(); 
      if(topValue instanceof String) { // known parameter name like "name" 
       // Iterate over locations corresponding to current PC 
       // (usually only one such location exists) 
       for(Location location : vna.getCFG() 
         .getLocationsContainingInstructionWithOffset(getPC())) { 
        try { 
         // This frame contains value numbers 
         // right after the INVOKEINTERFACE execution 
         ValueNumberFrame frame = vna.getFactAfterLocation(location); 
         // ValueNumber corresponding to the top stack value: 
         // the return value of getParameters() method 
         ValueNumber vn = frame.getTopValue(); 
         vnToParameterName.put(vn, (String) topValue); 
        } catch (DataflowAnalysisException e) { 
         return; 
        } 
       } 
      } 
     } 
    } 
} 

所以,現在你可以使用這張地圖。一些更多的代碼添加到sawOpcode

if(seen == INVOKEINTERFACE && getMethodDescriptorOperand().getSlashedClassName() 
     .equals("com/ibm/itim/ws/services/WSSessionService") && 
     getMethodDescriptorOperand().getName().equals("getNumber")) 
    for(Location location : vna.getCFG() 
      .getLocationsContainingInstructionWithOffset(getPC())) { 
     try { 
      // This frame contains value numbers 
      // right before the INVOKEINTERFACE execution 
      ValueNumberFrame frame = vna.getFactAtLocation(location); 
      // ValueNumber corresponding to the top stack value: 
      // the last parameter for getNumber method 
      ValueNumber vn = frame.getStackValue(0); 
      String parameterName = vnToParameterName.get(vn); 
      if(parameterName != null) { 
       // hurrah: this parameter is in fact 
       // the return value of getParameter(parameterName) 
      } 
     } catch (DataflowAnalysisException e) { 
      return; 
     } 
    } 

我沒有測試此代碼,所以一些小問題是可能的。請注意0​​是相當強大的東西。它不僅能夠跟蹤ASTORE/ALOAD,而且還可以將此值重新保存到另一個變量中,甚至(有一些限制)將其存儲到現場,並隨後加載。當然,如果你根本不使用局部變量,它也可以工作(如getNumber(request.getParameter("name")))。