czwartek, wrzesień 25, 2008

Sztuczki tropiciela błędów, part 3 - hackujemy klasy finalne ;-)

Dziś próbowałem się w pracy "włamać" do biblioteki odpowiedzialnej za pooling połączeń do bazy danych. Chodzi po prostu o to, że chcę ustalić czy pooling nie robi nieładnych rzeczy zaraz po starcie ;-)Niestety autor klas poolingu był podejrzliwy i uczynił większość klas klasami finalnymi, przez to nie mogłem użyć mojej ulubionej techniki polegającej na nadpisaniu klasy i założenia breakpointów w metodach które chciałem obserwować...I wtedy przyszło olśnienie ;-) A co gdyby "wstrzyknąć" swój kod do środka klasy "wroga" i zmusić ją do pracy na moją korzyść? ;-)Na klasach poolingu tego jeszcze nie zrobiłem, ale idea wydaje się być słuszna. Szczególnie skuteczna powinna być w przypadku klas, które agregują lub są wrapperami dla klas które dziedziczą po czymś dostępnym, lub rozszerzają coś dostępnego.Wyobraźmy sobie, że mamy kod interfejsu:
package org.przemelek.hack.secure;
public interface Form {
 public void login(String user,String password);
}
Oraz finalną klasę SecureForm, która jest "tajna" i finalną klasę opakowującą SecureForm o nazwie SpecialForm, która to klasa używa naszej tajnej klasy.
package org.przemelek.hack.secure;
final class SecureForm implements Form {
 protected SecureForm() {
  System.out.println("Secure object created");
 }
 public void login(String user, String password) {
  System.out.println("Secure login");
 }
}
package org.przemelek.hack.secure;
public final class SpecialForm implements Form { 
    private Form form; 
    public SpecialForm() {
     form = new SecureForm(); 
    } 
    public void login(String user, String password) {
     form.login(user, password); 
    }
}
Chcielibyśmy móc coś zrobić w momencie gdy wywołana zostanie metoda login(String,String), z tym że chodzi także o wywołania wewnątrz kodu klasy SpecialForm [tutaj akurat takich nie mamy].I w tym momencie z pomocą przychodzą nam odbicia ;-)
package org.przemelek.hack;
import java.lang.reflect.Field;
import org.przemelek.hack.secure.Form;
import org.przemelek.hack.secure.SpecialForm;

public class Hack {
 public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
  Form form = new SpecialForm();
  Field formField = SpecialForm.class.getDeclaredField("form");
  formField.setAccessible(true);
  final Form oldForm = (Form)formField.get(form);
  formField.set(form, new Form() {
    public void login(String user, String password) {
     System.out.println("Hacked login :-)");
     System.out.println("user:"+user+" password:"+password);
     oldForm.login(user, password);
    }
  });
  form.login("test", "tost");
 }
}
Przez odbicia prosimy o zadeklarowane pole form, zapamiętujemy jego wartość, następnie tworzymy klasę anonimową na podstawie znanego nam interfejsu Form, i podmieniamy jej instancją wartość pola form. I już działa ;-)Gdy gdziekolwiek w naszym kodzie, czy kodzie biblioteki którą hackujemy nastąpi wywołanie metody login(String,String) z klasy SpecialForm wywołany zostanie także nasz kod :-)Sztuczki tropiciela błędów, part 2Sztuczki tropiciela błędów, part 1


Podobne postybeta
Sztuczki tropiciela błędów, part 4
Sztuczki tropiciela błędów, part 2 ;-)
Sztuczki tropiciela błędów ;-)
Ile to jest 1+1 w Java'ie?
Wymiana obiektów między PC a Androidem... - użyj serializacji Luke ;-)

0 comments:

Prześlij komentarz