1. 환경 및 설치
2. 시작 전 에러
3. Fridalab Challenge01~03
환경
아나콘다, Firda 17.9.11, LDplayer, Jadx
아나콘다 설치
Advance AI with Open Source | Anaconda
Anaconda is the birthplace of Python data science. We are a movement of data scientists, data-driven enterprises, and open source communities.
www.anaconda.com
Frida 다운로드
https://github.com/frida/frida/releases
Releases · frida/frida
Clone this repo to build Frida. Contribute to frida/frida development by creating an account on GitHub.
github.com

arm, arm64 > 모바일 기기
x86, x86_64 > 에뮬레이터 (Ld player, Nox player)
아나콘다 환경 설정
아나콘다 환경에 Frida를 버전과 일치하게 설치해줍니다.
frida 명령어를 사용하기위해 frida-tools도 같이 설치해줍니다.
pip install frida==17.9.11
pip install frida-tools
frida 서버 실행
adb root
adb push frida-server-17.9.11-android-x86_64 /data/local/tmp
adb shell
su root
cd /data/local/tmp
chmod 755 frida-server-17.9.11-android-x86_64
./frida-server-17.9.11-android-x86_64 &
Java-Bridge 에러
https://simnple.tistory.com/14 해당 블로그를 참고하였습니다.
load_bride 함수를 추가해줍니다.
....생략....
def load_bridge(lang):
try:
# frida_tools 패키지의 실제 설치 경로를 계산합니다.
frida_tools_path = os.path.dirname(importlib.util.find_spec('frida_tools').origin)
# bridges 폴더 안의 java.js 파일 경로를 생성합니다.
bridge_file = os.path.join(frida_tools_path, 'bridges', f'{lang.lower()}.js')
with open(bridge_file, 'r', encoding='utf-8') as f:
bridge_src = f.read()
# 자바스크립트 전역 공간(globalThis)에 Java 객체를 강제로 등록하는 래핑 코드입니다.
return '(function() { ' + bridge_src + '; Object.defineProperty(globalThis, "' + lang + '", { value: bridge }); })();\n'
except Exception as e:
print(f"[-] 브릿지 파일 로드 실패: {e}")
return ""
....생략.....
# 브릿지 코드 결합 //Reference Java 에러
js_code = load_bridge('Java') + get_script(args.script)
Fridalab
Fridalab을 통해 Frida 사용연습을 할 수 있는 앱입니다.
https://rossmarks.uk/blog/fridalab
FridaLab
I was struggling with a recent test using frida, knowing it could do what I want but unsure how. After lots of googling and trial and error I eventually got it working. So I decided
rossmarks.uk
Challenge01

challenge_01에 클래스의 chall01 변수의 값을 1로 변경해주면 됩니다.
//MainActivity
public void onClick(View view) {
if (challenge_01.getChall01Int() == 1) {
MainActivity.this.completeArr[0] = 1;
}
//challenge_01
package uk.rossmarks.fridalab;
/* JADX INFO: loaded from: classes.dex */
public class challenge_01 {
static int chall01;
public static int getChall01Int() {
return chall01;
}
}
버튼 클릭시 getChall01Int 함수를 불러와 chall01의 값이 1과 동일하다면 해결됩니다.
Java.perform(function(){
console.log("[-] chall01 시작");
// [Challenge 01]
const challenge_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
challenge_01.chall01.value = 1;
console.log("[-] chall01 변수가 변경 되었습니다");
});
Java.perform은 안드로이드 내부의 자바 클래스나 메소드에 접근하기 위해서는 반드시 현재 실행 중인 스레드가 런타임에 부착(Attach)되어 있어야 합니다. Java.perform은 내부 래핑 함수(Callback)가 자바 런타임 컨텍스트 내에서 안전하게 실행되도록 환경을 조성하는 필수 관문입니다. 모든 안드로이드 후킹 스크립트는 이 구조 내부에서 시작됩니다.
Java.use는 힙(Heap) 메모리에 생성된 실제 객체 인스턴스를 찾는 것이 아니라, 클래스의 설계도 자체를 메모리에서 가져옵니다. 따라서 이 단계에서는 인스턴스화되지 않은 정적(Static) 멤버나 메소드에만 접근할 수 있습니다. 본 코드에서는 반환된 래퍼 객체를 let challenge_01 변수에 할당하여 참조합니다.
본 스크립트는 인스턴스 탐색(Java.choose) 과정 없이, 클래스 주소만 알면 즉시 접근 가능한 Static 영역의 취약점을 공략하는 전형적인 방법입니다.
Challenge02

chall02함수를 실행시켜주면됩니다.
private void chall02() {
this.completeArr[1] = 1;
}
setTimeout(function(){
Java.perform(function(){
//[Challenge 01]
..생략
//[instance]
Java.choose("uk.rossmarks.fridalab.MainActivity",{
"onMathch":function(instance) {
//[Challenge 02]
instance.chall02();
},
"onComplete" : function() {
console.log("[-] Main 메모리 탐색 완료");
}
});
},1000);
FridaLab 1번 문제가 클래스의 설계도(Static)를 수정하는 작업이었다면, 2번 문제는 현재 메모리에 실제로 살아서 구동 중인 객체(Instance)의 함수를 강제로 호출하는 가로채기 기법을 다룹니다.
static 키워드가 없는 일반 인스턴스 메소드를 후킹할 때 사용하는 기법으로 안드로이드의 Activity 클래스들은 앱 구동 시 시스템에 의해 동적으로 인스턴스화되므로, Java.use로는 제어할 수 없으며 반드시 이처럼 Java.choose를 통해 메모리 상의 실체(Instance)를 직접 낚아채야만 제어가 가능합니다.
하지만 단순히 Java.choose만 사용하여 함수를 실행시킨다면 chall 02가 풀리지 않습니다. Java.choose함수를 통해 스캔하기전에 앱이 메모리상에 완전히 떠있지 않으면 낚아 챌 수 없기 때문입니다.
따라서 setTimeout으로 약 1초간의 딜레이를 부여함으로써, target 객체가 힙(Heap) 메모리에 안전하게 동적 할당될 시간을 보장한 후 탐색을 시작하도록 유도합니다.
Challenge03

chall03() 함수의 리턴값을 true로 만들어줍니다.
public boolean chall03() {
return false;
}
위 메소드는 함수를 따로 호출할 필요가 없이 버튼을 클릭했을때 함수가 호출됩니다.
public void onClick(View view) {
if (challenge_01.getChall01Int() == 1) {
MainActivity.this.completeArr[0] = 1;
}
if (MainActivity.this.chall03()) {
MainActivity.this.completeArr[2] = 1;
}
}
따라서 Java.use를 통해 함수를 불러와 메소드를 재정의하는 방법을 사용합니다.
// Main 호출
const Main = Java.use("uk.rossmarks.fridalab.MainActivity");
// [Challenge 03]
Main.chall03.implementation = function(){
console.log("[-] chall03가 True로 전환되었습니다.")
return true;
};
이로써 chall03 함수가 호출되었을때 본래 MainActivity에 있던 chall03함수가 아닌 재정의한 chall03이 실행되게 됩니다.
'모바일 해킹' 카테고리의 다른 글
| Fridalab 04~08, 전체 코드 (0) | 2026.06.14 |
|---|