iOS Frida 구성
Reading time: 9 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Frida 설치
탈옥된 장치에 Frida를 설치하는 단계:
- Cydia/Sileo 앱을 엽니다.
- 관리 -> 소스 -> 편집 -> 추가로 이동합니다.
- URL로 "https://build.frida.re"를 입력합니다.
- 새로 추가된 Frida 소스로 이동합니다.
- Frida 패키지를 설치합니다.
Corellium을 사용하는 경우 https://github.com/frida/frida/releases에서 Frida 릴리스를 다운로드해야 합니다 (frida-gadget-[yourversion]-ios-universal.dylib.gz
) 그리고 압축을 풀고 Frida가 요청하는 dylib 위치에 복사합니다, 예: /Users/[youruser]/.cache/frida/gadget-ios.dylib
설치 후, PC에서 frida-ls-devices
명령을 사용하여 장치가 나타나는지 확인합니다 (PC가 장치에 접근할 수 있어야 합니다).
또한 **frida-ps -Uia
**를 실행하여 전화기의 실행 중인 프로세스를 확인합니다.
탈옥되지 않은 장치에서 Frida 사용 및 앱 패치 없이
앱을 패치하지 않고 탈옥되지 않은 장치에서 Frida를 사용하는 방법에 대한 블로그 게시물을 확인하세요: https://mrbypass.medium.com/unlocking-potential-exploring-frida-objection-on-non-jailbroken-devices-without-application-ed0367a84f07
Frida 클라이언트 설치
frida tools를 설치합니다:
pip install frida-tools
pip install frida
Frida 서버가 설치되고 장치가 실행 중이며 연결된 상태에서 클라이언트가 작동하는지 확인하십시오:
frida-ls-devices # List devices
frida-ps -Uia # Get running processes
프리다 트레이스
# Functions
## Trace all functions with the word "log" in their name
frida-trace -U <program> -i "*log*"
frida-trace -U <program> -i "*log*" | swift demangle # Demangle names
# Objective-C
## Trace all methods of all classes
frida-trace -U <program> -m "*[* *]"
## Trace all methods with the word "authentication" from classes that start with "NE"
frida-trace -U <program> -m "*[NE* *authentication*]"
# Plug-In
## To hook a plugin that is momentarely executed prepare Frida indicating the ID of the Plugin binary
frida-trace -U -W <if-plugin-bin> -m '*[* *]'
모든 클래스 및 메서드 가져오기
- 자동 완성:
frida -U <program>
을 실행하세요.
- 모든 사용 가능한 클래스 가져오기 (문자열로 필터링)
// frida -U <program> -l /tmp/script.js
var filterClass = "filterstring"
if (ObjC.available) {
for (var className in ObjC.classes) {
if (ObjC.classes.hasOwnProperty(className)) {
if (!filterClass || className.includes(filterClass)) {
console.log(className)
}
}
}
} else {
console.log("Objective-C runtime is not available.")
}
- 클래스의 모든 메서드 가져오기 (문자열로 필터링)
// frida -U <program> -l /tmp/script.js
var specificClass = "YourClassName"
var filterMethod = "filtermethod"
if (ObjC.available) {
if (ObjC.classes.hasOwnProperty(specificClass)) {
var methods = ObjC.classes[specificClass].$ownMethods
for (var i = 0; i < methods.length; i++) {
if (!filterMethod || methods[i].includes(filterClass)) {
console.log(specificClass + ": " + methods[i])
}
}
} else {
console.log("Class not found.")
}
} else {
console.log("Objective-C runtime is not available.")
}
- 함수 호출
// Find the address of the function to call
const func_addr = Module.findExportByName("<Prog Name>", "<Func Name>")
// Declare the function to call
const func = new NativeFunction(
func_addr,
"void",
["pointer", "pointer", "pointer"],
{}
)
var arg0 = null
// In this case to call this function we need to intercept a call to it to copy arg0
Interceptor.attach(wg_log_addr, {
onEnter: function (args) {
arg0 = new NativePointer(args[0])
},
})
// Wait untill a call to the func occurs
while (!arg0) {
Thread.sleep(1)
console.log("waiting for ptr")
}
var arg1 = Memory.allocUtf8String("arg1")
var txt = Memory.allocUtf8String("Some text for arg2")
wg_log(arg0, arg1, txt)
console.log("loaded")
Frida Fuzzing
Frida Stalker
From the docs: Stalker는 Frida의 코드 추적 엔진입니다. 이는 스레드를 따라가며, 실행되는 모든 함수, 모든 블록, 심지어 모든 명령어를 캡처할 수 있게 해줍니다.
Frida Stalker를 구현한 예시는 https://github.com/poxyran/misc/blob/master/frida-stalker-example.py에서 확인할 수 있습니다.
이것은 함수가 호출될 때마다 Frida Stalker를 연결하는 또 다른 예입니다:
console.log("loading")
const wg_log_addr = Module.findExportByName("<Program>", "<function_name>")
const wg_log = new NativeFunction(
wg_log_addr,
"void",
["pointer", "pointer", "pointer"],
{}
)
Interceptor.attach(wg_log_addr, {
onEnter: function (args) {
console.log(`logging the following message: ${args[2].readCString()}`)
Stalker.follow({
events: {
// only collect coverage for newly encountered blocks
compile: true,
},
onReceive: function (events) {
const bbs = Stalker.parse(events, {
stringify: false,
annotate: false,
})
console.log(
"Stalker trace of write_msg_to_log: \n" +
bbs.flat().map(DebugSymbol.fromAddress).join("\n")
)
},
})
},
onLeave: function (retval) {
Stalker.unfollow()
Stalker.flush() // this is important to get all events
},
})
caution
디버깅 관점에서는 흥미롭지만 퍼징을 위해 .follow()
및 **.unfollow()
**를 지속적으로 사용하는 것은 매우 비효율적입니다.
Fpicker
fpicker는 AFL++ 모드 또는 수동 추적 모드와 같은 프로세스 내 퍼징을 위한 다양한 퍼징 모드를 제공하는 Frida 기반 퍼징 스위트입니다. Frida에서 지원하는 모든 플랫폼에서 실행되어야 합니다.
- fpicker 설치 & radamsa
# Get fpicker
git clone https://github.com/ttdennis/fpicker
cd fpicker
# Get Frida core devkit and prepare fpicker
wget https://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-[yourOS]-[yourarchitecture].tar.xz
# e.g. https://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-macos-arm64.tar.xz
tar -xf ./*tar.xz
cp libfrida-core.a libfrida-core-[yourOS].a #libfrida-core-macos.a
# Install fpicker
make fpicker-[yourOS] # fpicker-macos
# This generates ./fpicker
# Install radamsa (fuzzer generator)
brew install radamsa
- FS 준비:
# From inside fpicker clone
mkdir -p examples/wg-log # Where the fuzzing script will be
mkdir -p examples/wg-log/out # For code coverage and crashes
mkdir -p examples/wg-log/in # For starting inputs
# Create at least 1 input for the fuzzer
echo Hello World > examples/wg-log/in/0
- Fuzzer 스크립트 (
examples/wg-log/myfuzzer.js
):
// Import the fuzzer base class
import { Fuzzer } from "../../harness/fuzzer.js"
class WGLogFuzzer extends Fuzzer {
constructor() {
console.log("WGLogFuzzer constructor called")
// Get and declare the function we are going to fuzz
var wg_log_addr = Module.findExportByName(
"<Program name>",
"<func name to fuzz>"
)
var wg_log_func = new NativeFunction(
wg_log_addr,
"void",
["pointer", "pointer", "pointer"],
{}
)
// Initialize the object
super("<Program nane>", wg_log_addr, wg_log_func)
this.wg_log_addr = wg_log_addr // We cannot use "this" before calling "super"
console.log("WGLogFuzzer in the middle")
// Prepare the second argument to pass to the fuzz function
this.tag = Memory.allocUtf8String("arg2")
// Get the first argument we need to pass from a call to the functino we want to fuzz
var wg_log_global_ptr = null
console.log(this.wg_log_addr)
Interceptor.attach(this.wg_log_addr, {
onEnter: function (args) {
console.log("Entering in the function to get the first argument")
wg_log_global_ptr = new NativePointer(args[0])
},
})
while (!wg_log_global_ptr) {
Thread.sleep(1)
}
this.wg_log_global_ptr = wg_log_global_ptr
console.log("WGLogFuzzer prepare ended")
}
// This function is called by the fuzzer with the first argument being a pointer into memory
// where the payload is stored and the second the length of the input.
fuzz(payload, len) {
// Get a pointer to payload being a valid C string (with a null byte at the end)
var payload_cstring = payload.readCString(len)
this.payload = Memory.allocUtf8String(payload_cstring)
// Debug and fuzz
this.debug_log(this.payload, len)
// Pass the 2 first arguments we know the function needs and finally the payload to fuzz
this.target_function(this.wg_log_global_ptr, this.tag, this.payload)
}
}
const f = new WGLogFuzzer()
rpc.exports.fuzzer = f
- 퍼저를 컴파일합니다:
# From inside fpicker clone
## Compile from "myfuzzer.js" to "harness.js"
frida-compile examples/wg-log/myfuzzer.js -o harness.js
- **
radamsa
**를 사용하여 퍼저fpicker
호출:
# Indicate fpicker to fuzz a program with the harness.js script and which folders to use
fpicker -v --fuzzer-mode active -e attach -p <Program to fuzz> -D usb -o examples/wg-log/out/ -i examples/wg-log/in/ -f harness.js --standalone-mutator cmd --mutator-command "radamsa"
# You can find code coverage and crashes in examples/wg-log/out/
caution
이 경우 우리는 각 페이로드 후에 앱을 재시작하거나 상태를 복원하지 않습니다. 따라서 Frida가 충돌을 발견하면 그 페이로드 이후의 다음 입력도 앱을 충돌시킬 수 있습니다 (앱이 불안정한 상태이기 때문에) 비록 입력이 앱을 충돌시켜서는 안 되더라도.
게다가, Frida는 iOS의 예외 신호에 후킹하므로, Frida가 충돌을 발견하면, 아마도 iOS 충돌 보고서가 생성되지 않을 것입니다.
이를 방지하기 위해, 예를 들어, 우리는 각 Frida 충돌 후에 앱을 재시작할 수 있습니다.
로그 및 충돌
macOS 콘솔 또는 log
cli를 사용하여 macOS 로그를 확인할 수 있습니다.
또한 **idevicesyslog
**를 사용하여 iOS의 로그를 확인할 수 있습니다.
일부 로그는 **<private>
**를 추가하여 정보를 생략합니다. 모든 정보를 표시하려면 https://developer.apple.com/bug-reporting/profiles-and-logs/에서 일부 프로필을 설치하여 해당 개인 정보를 활성화해야 합니다.
무엇을 해야 할지 모른다면:
vim /Library/Preferences/Logging/com.apple.system.logging.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Enable-Private-Data</key>
<true/>
</dict>
</plist>
killall -9 logd
다음에서 충돌을 확인할 수 있습니다:
- iOS
- 설정 → 개인 정보 보호 → 분석 및 개선 → 분석 데이터
/private/var/mobile/Library/Logs/CrashReporter/
- macOS:
/Library/Logs/DiagnosticReports/
~/Library/Logs/DiagnosticReports
warning
iOS는 동일한 앱의 충돌을 25개만 저장하므로 이를 정리해야 하며, 그렇지 않으면 iOS가 충돌을 생성하는 것을 중단합니다.
Frida Android Tutorials
References
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.