우선 apk 내 chall02() 함수를 찾아보니 MainActivity 내에 존재했고, xrefs 를 찍어 보니 없었음. 따라서 MainActivity에서 호출해주는 코드를 직접 만들어야 함
Challenge 1 때와 같이 Java.use(MainActivity) 후 onCreate 메소드 내에서 직접 호출을 해주면 되지 않을까 싶었는데 안 됨
import frida, sys
def on_message(message, data):
if message["type"] == "send":
print(f"[+] {message['payload']}")
else:
print(message)
def hook():
jscode = """
Java.perform(function() {
// 1
var challenge_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
challenge_01.getChall01Int.implementation = function() {
send("challenge_01::getChall01Int called");
var result = this.getChall01Int();
send("myMethod returned: " + result);
send("modified result: 1");
return 1;
};
// 2
var MainActivity = Java.use("uk.rossmarks.fridalab.MainActivity");
MainActivity.onCreate.implement = function(v) {
send("MainActivity::onCreate called");
this.onCreate();
}
});
"""
process = frida.get_usb_device().attach("FridaLab")
script = process.create_script(jscode)
script.on("message", on_message)
script.load()
sys.stdin.read()
if __name__ == "__main__":
hook()
찾아 보니 런타임에 올라가 있는 클래스 인스턴스를 후킹할 때는 Java.use가 아닌 Javs.choose를 사용해야 한다고 함 (https://velog.io/@resur/Java.use-Java.choose-차이)
static 메소드가 아닌 경우 instance 메소드에 해당되고, 이 경우 런타임에 로드 된 인스턴스 자체를 후킹 하는 방식으로만 동작함. Java.use와 Java.choose를 사용할 수 있는 경우를 정리하면 아래와 같음
Java.use
를 사용하면 클래스의 메소드에 직접 접근하여 후킹할 수 있습니다. Frida는 내부적으로 래퍼 객체를 생성하여 메소드 호출을 가로채고 수정할 수 있도록 해줍니다.하지만 주의해야 할 점은
Java.use
를 사용하여 후킹한 메소드는 해당 클래스의 모든 인스턴스에 영향을 줍니다. 즉, 후킹된 메소드는 해당 클래스의 모든 객체에서 동일하게 동작하게 됩니다. 따라서 특정 인스턴스에 대해서만 메소드를 후킹하고 싶다면Java.choose
를 사용하여 해당 인스턴스를 찾아 후킹해야 합니다.
Java.use
를 사용한 메소드 후킹은 간단하고 편리하지만, 클래스의 모든 인스턴스에 영향을 줄 수 있다는 점을 고려해야 합니다.
Java.choose 인자는 후킹할 클래스명, 콜백 함수이며 콜백 함수는 onMatch와 onComplete로 구성됨. 여기서 유의해야 할 점은 onMatch, onComplete 모두 정의해 줘야 한다는 것 (onComplete 누락시 에러 발생)
아래 코드를 통해 MainActivity 인스턴스를 후킹하고 chall02() 함수를 직접 호출
import frida, sys
def on_message(message, data):
if message["type"] == "send":
print(f"[+] {message['payload']}")
else:
print(message)
def hook():
jscode = """
Java.perform(function() {
// 1
var challenge_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
challenge_01.getChall01Int.implementation = function() {
send("challenge_01::getChall01Int called");
var result = this.getChall01Int();
send("myMethod returned: " + result);
send("modified result: 1");
return 1;
};
// 2
Java.choose("uk.rossmarks.fridalab.MainActivity", {
onMatch: function(instance) {
send("Found instance: " + instance);
send("call MainActivity::chall02");
instance.chall02();
},
onComplete: function() {}
});
});
"""
process = frida.get_usb_device().attach("FridaLab")
script = process.create_script(jscode)
script.on("message", on_message)
script.load()
sys.stdin.read()
if __name__ == "__main__":
hook()
아래 코드를 이용해 로드된 모든 클래스를 열거할 수 있음
Java.enumerateLoadedClasses({
"onMatch" : function(className) {
console.log(className)
},
"onComplete" : function() {}
});