강의 : 프리다(Frida)를 이용한 안드로이드 앱 모의해킹
5주차 활동 : 섹션6(파이썬 바인딩 이해) 섹션7(프리다 챌린지로 연습, 1-6)
파이썬 바인딩 이해
1. 파이썬 바인딩 구조
- 프리다로 작업을 자동화 하기
ℹ️ 파이썬 코드 실행으로 아래와 같은 기능이 가능함
1. 프로세스 식별하고 연결
2. 연결된 디바이스에서 구현하려는 프로세스와 세션 연결
3. 자바스크립트로 작성된 페이로드 자동 삽입
import frida, sys
jscode = """ payload_code """
session = frida.get_usb_device().attach("com.yourpackage.name")
script = session.create_script(jscode)
script.load()
sys.stdin.read()
- 파이썬 바인딩 기본 구조
#frida, sys 모듈 가져오기
import frida, sys
#삽입할 자바스크립트 코드 넣기
jscode = """ payload_code """
#frida를 시작하고 USB 장치에서 com.your.package.name 프로세스 연결
session = frida.get_usb_device().attach("com.yourpackage.name")
#jscode에 있는 스크립트 코드를 frida에서 사용할 수 있도록 생성
script = session.create_script(jscode)
#생성한 script를 로드
script.load()
#script가 동작하기 전에 종료되는 문제 예방
sys.stdin.read()
- 파이썬 바인딩 기본 구조 - Spawn
#frida를 시작하고 USB 장치에 연결
device = frida.get_usb_device()
#연결된 USB 장치에서 com.your.package.name 프로세스 생성
pid = device.spawn(["com.yourpackage.name"])
#com.your.package.name 프로세스 연결
session = device.attach(pid)
#jscode에 있는 스크립트 코드를 frida에서 사용할 수 있도록 생성
script = session.create_script(jscode)
#생성한 script를 로드
script.load()
#com.your.package.name 프로세스 메인 스레드 실행
device.resume(pid)
#script가 동작하기 전에 종료되는 문제 예방
sys.stdin.read()
- 파이썬 바인딩 파일 만들기
- android.app.Activity 클래스의 onResume 함수 덮어쓰기
import frida, sys
jscode = """
console.log("[*] Starting onResume script");
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activiy.onResume.implementation = function () {
console.log("[*] onResume() got called!");
this.onResume();
};
});
"""
session = frida.get_usb_device().attach("com.android.chrome")
script = session.create_script(jscode)
script.load()
sys.stdin.read()
@onresume.py
import frida, sys
jscode = """
setImmediate(function() {
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activiy.onResume.implementation = function () {
console.log("[*] onResume() got called!");
this.onResume();
}
})
});
"""
process = frida.get_usb_device().attach("com.android.chrome")
script = process.create_script(jscode)
script.load()
sys.stdin.read()
$ python onresume.py
[*] onResume() got called!
...
2. 파이썬 바인딩 메시지 처리
- 메시지 처리하기
- send(message [,data])
- 프리다 기반 애플리케이션에 자바스크립트 객체 message 전송
- script.on(’message’, on_message)
- 프리다 스크립트에서 보낸 메시지를 처리할 콜백 함수를 설정
- 호출할 핸들러를 등록하는 과정
- on_message(message, data)
- script.on(’message’, on_message)에서 등록한 핸들러에 대한 정의를 하는 부분
- 단순히 message 매개변수를 콘솔에 출력하는 역할
- send(message [,data])
@onmessage1.py
import frida, sys
def on_message(message, data):
print(message)
jscode = """
setImmediate(function() {
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activiy.onResume.implementation = function () {
send("[*] onResume() got called!");
this.onResume();
}
})
});
"""
process = frida.get_usb_device().attach("com.android.chrome")
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
$ python onmessage1.py
{'type': 'send', 'payload': '[*] onResume() got called!'}
@onmessage2.py
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print(message['payload'])
else:
print(message)
jscode = """
setImmediate(function() {
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activiy.onResume.implementation = function () {
send("[*] onResume() got called!");
this.onResume();
}
})
});
"""
process = frida.get_usb_device().attach("com.android.chrome")
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
$ python onmessage2.py
[*] onResume() got called!
프리다 챌린지로 연습해보기
0. 챌린지 문제 이해
ℹ️ Frida Lab: Ross Marks가 만든 프리다를 쉽게 연습할 수 있는 놀이터
http://rossmarks.uk/blog/fridalab/
✅ 8개의 문제로 구성
1. Change class challenge_01’s variable ‘chall01’ to 1 : 클래스 challenge_01의 변수 chall01을 1로 변경하기
2. Run chall02() : Chall02() 메소드 실행하기
3. Make chall03() return true : chall03() 메소드가 true 반환하게 만들기
4. Send “frida” to chall04() : chall04() 메소드에 frida 문자열 전송하기
5. Always send “frida” to chall05() : chall05() 메소드에 frida 문자열 항상 전송하기
6. Run chall06() after 10 seconds with correct value : 올바른 값으로 10초 후 chall06() 메소드 실행하기
7. Bruteforce check07Pin() then confirm with chall07() : check07Pin() 메소드를 브로트포스해서 chall07() 메소드로 확인하기
8. Change ‘check’ button’s text value to ‘Confirm’ : check 버튼의 텍스트를 Confirm으로 변경하기
$ nox_adb install C:\...\FridaLab.apk
root@shamu:/ # ./data/local/tmp/frida-server-16.2.1-android-x86
$ frida-ps -Ua
PID Name Identifier
---- --------------- ----------------------
3772 FridaLab uk.rossmarks.fridalab
- jadx-gui : APK 파일에서 Java 소스 코드를 생성해서 보여주는 도구
IF 초기 상태로 복구하고 싶은 경우
$ frida-ps -U
PID Name
---- -------------------------------
3090 FridaLab
$ frida-kill -U 3090
1. 챌린지 풀어보기, 첫번째
1. Change class challenge_01’s variable ‘chall01’ to 1
@uk.rossmarks.fridalab.challenge_01
package uk.rossmarks.fridalab;
/* loaded from: classes.dex */
public class challenge_01 {
static int chall01;
public static int getChall01Int() {
return chall01;
}
}
@fridalab.js
setImmediate(function() {
Java.perform(function() {
var chall_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
//uk.rossmarks.fridalab.challenge_01 내 chall01 변수에 대해 값을 지정해야함
//해당 클래스에 대한 객체를 받아오기 위해, Java.use를 사용
chall_01.chall01.value = 1; //chall_01 클래스 내부에 있는 chall01 변수 사용
//value란, 자바스크립트에서 객체 내부의 속성을 뜻함
console.log("Sovled Challenge 01");
})
})
⚠️ 프로세스 지정 명령어 오류
프리다 15 버전 부터는 패키지 이름이 아닌 앱 이름을 지정해야 한다.
이때, 앱 이름을 확인하는 방법은 frida-ps -Ua 명령어로 Name 부분에 해당한다.
frida -U -l fridalab.js FridaLab
참고로, 패키지 이름으로 지정할 경우 spawn으로 하면 가능하다.
frida -U -l fridalab.js -f uk.rossmarks.fridalab --no-pause
$ frida -U -l C:\...\fridalab.js uk.rossmarks.fridalab
2. 챌린지 풀어보기, 두번째
2. Run chall02()
- chall02 탐색: 해당 메소드는 메인 액티비티 클래스 내부에 있는 메소드임을 확인 가능
@uk.rossmarks.fridalab.MainActivity
{
...
private void chall02() {
this.completeArr[1] = 1; //해당 배열의 두 번째 값이 1로 세팅이 되면 해결됨.
}
...
}
@fridalab.js
setImmediate(function() {
Java.perform(function() {
//Challenge 01
var chall_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
chall_01.chall01.value = 1;
console.log("\nSolved Challenge 01");
//Challenge 02
Java.choose("uk.rossmarks.fridalab.MainActivity"),{
onMatch : function(chall_02) {
chall_02.chall02();
},
onComplete : function() {
console.log("\nSolved Challenge 02");
}
})
//test.chall02()의 경우, instance가 없기 때문에 메소드를 불러올 수 없다.
})
})
3. 챌린지 풀어보기, 세번째
3. Make chall03() return true
@uk.rossmarks.fridalab.MainActivity
public class MainActivity extends AppCompatActivity {
public int[] completeArr = {0, 0, 0, 0, 0, 0, 0, 0};
public boolean chall03() {
return false;
}
/* JADX INFO: Access modifiers changed from: protected */
@Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.SupportActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
((Button) findViewById(R.id.check)).setOnClickListener(new View.OnClickListener() { // from class: uk.rossmarks.fridalab.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
if (challenge_01.getChall01Int() == 1) {
MainActivity.this.completeArr[0] = 1;
}
if (MainActivity.this.chall03()) {
MainActivity.this.completeArr[2] = 1;
}
MainActivity.this.chall05("notfrida!");
if (MainActivity.this.chall08()) {
MainActivity.this.completeArr[7] = 1;
}
MainActivity.this.changeColors();
}
});
...
}
@fridalab.js
setImmediate(function() {
Java.perform(function() {
(중략)
//Challenge 03
var chall_03 = Java.use("uk.rossmarks.fridalab.MainActivity");
chall_03.chall03.implementation = function() {
return true;
}
console.log("\nSolved Challenge 03");
})
})
4. 챌린지 풀어보기, 네번째
4. Send “frida” to chall04()
@uk.rossmarks.fridalab.MainActivity
{
...
public void chall04(String str) {
if (str.equals("frida")) {
this.completeArr[3] = 1;
}
} //주어진 str 인자값을 받아와 인자값과 frida라는 문자열이 일치하면 성공
...
}
@fridalab.js
setImmediate(function() {
Java.perform(function() {
(중략)
//Challenge 04
Java.choose("uk.rossmarks.fridalab.MainActivity", {
//static이 없기 때문에 java.choose를 사용한다.
onMatch : function(chall_04) {
console.log("\nfrida string send");
chall_04.chall04("frida");
},
onComplete : function() {
console.log("\nSolved Challenge 04");
}
})
})
})
5. 챌린지 풀어보기, 다섯번째
5. Always send “frida” to chall05()
@uk.rossmarks.fridalab.MainActivity
{
...
public void chall05(String str) {
if (str.equals("frida")) {
this.completeArr[4] = 1;
} else {
this.completeArr[4] = 0;
}
}
...
}
@fridalab.js
setImmediate(function() {
Java.perform(function() {
(중략)
//Challenge 05
var chall_05 = Java.use("uk.rossmarks.fridalab.MainActivity");
chall_05.chall05.overload("java.lang.String").implementation =
function(arg) {
this.chall05("frida");
console.log("\nSolved Challenge 05");
}
})
})
6. 챌린지 풀어보기, 여섯번째
6. Run chall06() after 10 seconds with correct value
@uk.rossmarks.fridalab.MainActivity
{
...
public void chall06(int i) {
if (challenge_06.confirmChall06(i)) {
this.completeArr[5] = 1;
}
}
...
}
- 이후 addChall06 함수로 이동
@uk.rossmarks.fridalab.challenge_06
package uk.rossmarks.fridalab;
/* loaded from: classes.dex */
public class challenge_06 {
static int chall06;
static long timeStart;
public static void startTime() {
timeStart = System.currentTimeMillis();
}
public static boolean confirmChall06(int i) {
return i == chall06 && System.currentTimeMillis() > timeStart + 10000;
}
public static void addChall06(int i) {
chall06 += i;
if (chall06 > 9000) {
chall06 = i;
}
}
}
True가 되는 조건
1. i == chall06
@uk.rossmarks.fridalab.MainActivity
{
...
challenge_06.addChall06(new Random().nextInt(50) + 1);
new Timer().scheduleAtFixedRate(new TimerTask() { // from class: uk.rossmarks.fridalab.MainActivity.2
@Override // java.util.TimerTask, java.lang.Runnable
public void run() {
int nextInt = new Random().nextInt(50) + 1;
challenge_06.addChall06(nextInt);
Integer.toString(nextInt);
}
}, 0L, 1000L);
challenge_07.setChall07();
...
}
@uk.rossmarks.fridalab.challenge_06
{
...
public static void addChall06(int i) {
chall06 += i;
if (chall06 > 9000) {
chall06 = i;
}
}
}
}
⇒ addchall06 함수를 탐색한다.
2. System.currentTimeMillis() > timeStart + 10000로 인해 10sec가 지나가야만 한다.
⇒ setTimeout(fn, delay)를 사용한다.
@fridalab.js
setImmediate(function() {
Java.perform(function() {
(중략)
//Challenge 05
var chall_05 = Java.use("uk.rossmarks.fridalab.MainActivity");
chall_05.chall05.overload("java.lang.String").implementation =
function(arg) {
this.chall05("frida");
console.log("\nSolved Challenge 05");
}
})
})
//Challenge 06
setTimeout(function() {
console.log("\n10sec Challenge Solved!");
setImmediate(function(){
Java.perform(function(){
var chall_06 = Java.use("uk.rossmarks.fridalab.challenge_06");
chall_06.addChall06.overload("int").implementation = function(arg) {
Java.choose("uk.rossmarks.fridalab.MainActivity", {
onMatch : function(instance) {
instance.chall06(chall_06.chall06.value);
},
onComplete : function() {
console.log("\nSolved Challenge 06");
}
})
}
})
})
}, 10000);
'4-2. 2024-1 심화 스터디 > 안드로이드 모의해킹' 카테고리의 다른 글
[7주차] 블레이드러너 - 안드로이드 모의해킹 (0) | 2024.06.01 |
---|---|
[5주차] 블레이드러너 - 안드로이드 모의 해킹 (0) | 2024.05.14 |
[3주차] 블레이드러너- 안드로이드 모의해킹 (0) | 2024.04.04 |
[2주차] 블레이드러너 - 안드로이드 모의해킹 (1) | 2024.03.24 |
[1주차] 블레이드러너 - 안드로이드 모의해킹 (0) | 2024.03.22 |