2012-02-11 49 views
2

你好,我一直試圖弄清楚這個錯誤很長一段時間了。我有一個空指針newby問題這裏是類:空指針的原因

編輯:該程序是爲了注入代碼到另一個類,以阻止它刪除類時,它被加載然後它反映了類文件(存儲爲字節數組),然後轉儲到一個類文件。

我評論說,對應於堆棧跟蹤

public class Program { 

private HashMap<String, ClassGen> myClass = new HashMap<String, ClassGen>(); 
private int array_index; 

/** 
* Constructor. 
*/ 
public Program() { 
    try { 
     File Jar1 = new File("Jar1.jar"); 
     File nJar1 = new File("nJar1.jar"); 
     File OutPutJar = new File("Out.jar"); 
     BAppletStub stub = new BAppletStub(); 
     injectLoader(); 
     dumpClientFiles(stub); // Line 65 
     JarFile theJar = new JarFile(OutPutJar); 
     Enumeration<?> en = theJar.entries(); 
     while (en.hasMoreElements()) { 
      JarEntry entry = (JarEntry) en.nextElement(); 
      if (entry.getName().endsWith(".class")) { 
       ClassParser cp = new ClassParser(theJar.getInputStream(entry), entry.getName()); 
       JavaClass jc = cp.parse(); 
       ClassGen cg = new ClassGen(jc); 
       myClass.put(cg.getClassName(), cg); 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

private void injectLoader() throws IOException { 
    JarFile theJar = new JarFile("Jar1.jar"); 
    FileOutputStream stream = new FileOutputStream("nJar1.jar"); 
    JarOutputStream out = new JarOutputStream(stream); 
    Enumeration<?> en = theJar.entries(); 
    while (en.hasMoreElements()) { 
     JarEntry entry = (JarEntry) en.nextElement(); 
     if (entry.getName().contains("META-INF")) 
      continue; 
     JarEntry je = new JarEntry(entry.getName()); 
     out.putNextEntry(je); 
     if (entry.getName().endsWith(".class")) { 
      ClassParser cp = new ClassParser(theJar.getInputStream(entry), entry.getName()); 
      JavaClass jc = cp.parse(); 
      ClassGen cg = new ClassGen(jc); 
      fixClass(cg); 
      out.write(cg.getJavaClass().getBytes()); 
     } else { 
      InputStream in = theJar.getInputStream(entry); 
      int read; 
      byte[] buffer = new byte[1024]; 
      while ((read = in.read(buffer)) != -1) { 
       out.write(buffer, 0, read); 
      } 
     } 
    } 
    out.close(); 
    stream.close(); 
} 

@SuppressWarnings({ "deprecation", "unchecked" }) 
private void fixClass(ClassGen cg) { 
    for (Method m : cg.getMethods()) { 
     if (m.getReturnType().equals(Type.CLASS)) { 
      MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool()); 
      InstructionList list = mg.getInstructionList(); 
      String pattern = "aaload checkcast aload invokevirtual"; 
      InstructionFinder finder = new InstructionFinder(list); 
      Iterator<InstructionHandle[]> it = finder.search(pattern); 
      while (it.hasNext()) { 
       InstructionHandle[] handles = it.next(); 
       INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) handles[3].getInstruction(); 
       if (invoke.getMethodName(cg.getConstantPool()).equals("remove") && invoke.getClassName(cg.getConstantPool()).contains("Hashtable")) { 
        InstructionFactory factory = new InstructionFactory(cg); 
        Instruction i = factory.createInvoke("java/util/Hashtable", "get", invoke.getReturnType(cg.getConstantPool()), invoke.getArgumentTypes(cg.getConstantPool()), Constants.INVOKEVIRTUAL); 
        InstructionHandle handle = list.insert(handles[3], i); 
        InstructionHandle h = handles[3]; 
        if (h.hasTargeters()) { 
         for (InstructionTargeter t : h.getTargeters()) { 
          t.updateTarget(h, handle); 
         } 
        } 
        try { 
         list.delete(h); 
        } catch (TargetLostException e) { 
         e.printStackTrace(); 
        } 
        mg.setMaxLocals(); 
        mg.setMaxStack(); 
        cg.replaceMethod(m, mg.getMethod()); 
        return; 
       } 
      } 
     } 
    } 
} 

private void dumpClientFiles(BAppletStub stub) { 
    try { 
     File f = new File("nJar1.jar"); 
     URLClassLoader loader = new URLClassLoader(new URL[] { f.toURI().toURL() }); 
     Class<?> g = loader.loadClass("Rs2Applet"); 
     final Applet a = (Applet) g.newInstance(); 
     a.setStub(stub); 
     a.init(); 
     Object[] objs = getObjects(g, a); // Line 237 
     if (objs == null) 
      System.exit(1); 
     Hashtable<?, ?> tempTable = (Hashtable<?, ?>) objs[array_index]; 
     JarOutputStream out = new JarOutputStream(new FileOutputStream("Out.jar")); 
     Enumeration<?> it = tempTable.keys(); 
     int classes_dumped = 0; 
     while (it.hasMoreElements()) { 
      String s = (String) it.nextElement(); 
      Object o = tempTable.get(s); 
      JarEntry entry = new JarEntry(s.replace(".", "/") + ".class"); 
      out.putNextEntry(entry); 
      out.write((byte[]) o); 
      out.closeEntry(); 
      classes_dumped++; 
     } 
     System.out.println("Dumped " + classes_dumped + " classes to Out.jar"); 
     out.close(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public Object[] getObjects(Class<?> clazz, Object object) throws IllegalArgumentException, IllegalAccessException { 
    Field fd = null; 
    Field arr = null; 
    for (Field field : clazz.getDeclaredFields()) { 
     if ((field.getModifiers() & Modifier.PRIVATE) != 0 && field.getType().getCanonicalName().equals("java.lang.Object[]")) { 
      if (fd == null) { 
       fd = field; 
      } else { 
       arr = field; 
      } 
     } 
    } 
    Object[] objs = null; 
    boolean found = false; 
    Field array_field = null; 
    outer: for (int i = 0; i < 2 && !found; i++) { 
     array_field = (array_field == null || array_field == arr) ? fd : arr; 
     if (!array_field.isAccessible()) { //Line 278 
      array_field.setAccessible(true); 
     } 
     objs = (Object[]) array_field.get(object); 
     for (int j = 0; j < objs.length; j++) { 
      Object o = objs[j]; 
      if (o instanceof Hashtable) { 
       found = true; 
       if (((Hashtable<?, ?>) o).values().iterator().next().getClass().getCanonicalName().equals("byte[]")) { 
        array_index = j; 
        break outer; 
       } 
      } 
     } 
    } 
    if (fd.isAccessible()) 
     fd.setAccessible(false); 
    if (arr.isAccessible()) 
     arr.setAccessible(false); 
    return objs; 
} 

public static void main(String[] args) { 
    new Program(); //Line 304 
} 
} 

這裏行號的堆棧跟蹤:

java.lang.NullPointerException 
at org.nick.program.getObjects(program.java:278) 
at org.nick.program.dumpFiles(program.java:237) 
at org.nick.program.<init>(program.java:65) 
at org.nick.program.main(program.java:304) 

我的問題是什麼原因造成的空指針,我怎麼能改正?

+0

如果您在此處包含堆棧跟蹤,它也會有所幫助。 – 2012-02-11 18:56:57

+0

你可以顯示堆棧跟蹤嗎? – 2012-02-11 18:57:24

+0

如果您發佈完整的異常堆棧跟蹤,您也可以輕鬆進行調試。 – span 2012-02-11 18:57:32

回答

5

如果clazz不包含Object[]類型的任何私有字段(和正是Object[]!類型擦除可能會發揮作用,但繼承並不),既不fd也不arr將被設置。設定爲array_field的行假設如果arr未設置,fd將會 - 但在剛剛提到的情況下,它不會。

至於如何解決它......好吧,這取決於你究竟想要做什麼。這段代碼目前對我來說沒有什麼意義,所以對它應該做什麼的描述將非常有幫助。

+0

感謝您的迅速響應我已更新我的線程,嘗試並提供一些更多信息:) – Nicholas 2012-02-11 19:50:17

+0

@Nicholas:我的意思是,getObjects應該做什麼?顯然不只是獲得物體。 – cHao 2012-02-11 19:52:38

+0

搜索每種返回類型類的方法 – Nicholas 2012-02-11 20:01:25

1

代碼中有很多方法可能會導致此問題NullPointerException

例如,在第5行:

field.getType().getCanonicalName().equals可能導致此問題作爲getCanonicalName可以在這種情況下返回null和最佳的方法是使用: "java.lang.Object[]".equals(field.getType().getCanonicalName())

儘管,這不是問題,你必須:

  1. 使用如上所示的防禦性編程。 (或至少檢查 的nulls
  2. 提供我們的堆棧,以便我們可以幫助你。
+0

該類顯然是按名稱加載的,所以它幾乎必須有一個規範名稱。 – cHao 2012-02-11 19:22:26

+0

我同意你的看法,我只想告訴他他必須防禦他自己的程序(我已經編輯了我的答案) – 2012-02-11 21:06:45