본문 바로가기
보안 및 개발/MOBILE

[Frida] API 정리

by CH@3M 2021. 11. 30.

1. Frida : Ole에서 개발한 Dynamic Binary Instrumentation (DBI) toolkit

DBI(Dynamic Binary Instrumentation)

DBI는 바이너리 프로그램이 실행되는 동안 명령어를 수정, 삽입하는 것입니다. 이 기술은 프로세스 분석, 추적, 디버깅 등에 사용할 수 있습니다.

 

2. Frida 주요기능

Injection 임의 코드를 메모리나 애플리케이션에 주입합니다.
Interception 특정 함수를 후킹하여 매개 변수나 반환 값을 수정하고, 함수를 재작성합니다.
Stalking 애플리케이션에서 명령어 레벨의 코드를 추적하여 디버깅하거나 메모리 내의 데이터를 검색, 추출합니다.

Frida tools 명령어

frida 앱을 실행하여 frida와 애플리케이션을 연결, 스크립트 로드
frida-ps 프로세스 목록 출력
frida-trace 함수 호출 추적
frida-ls-devices 연결된 기기 목록 출력
frida-kill 동작중인 프로세스 종료

Frida 연결

Attach -F 현재 foreground에서 실행되고 있는 앱을 연결
-n <PACKAGE NAME> 앱의 패키지 이름으로 앱을 연결
-p <PID> 앱의 프로세스 ID로 앱을 연결
Spawn -f <PACKAGE NAME> 앱을 실행하고, 연결
Include/Exclude -I <MODULE> 모듈의 모든 함수를 추적
-X <MODULE> 모듈의 모든 함수를 추적에서 제외
-i <MOUDULE!FUNCTION> 함수를 추적(glob pattern)
-x <MODULE!FUNCTION> 함수를 추적에서 제외(glob pattern)
-a <FUNTION!offset> 함수를 추적(offset)

애뮬레이터에 연결할 경우 : frida -D emulator-5554 -f com.google.android.calendar --no-pause

Logging -d, --decorate 추적할 함수가 속한 모듈이름을 함께 기록
Others -O <TEXT FILE> 명령줄을 텍스트 파일로 입력

 

Process 사용예시

var modules = Process.enumerateModules()[0];
console.log("modules Base: ", modules.base);
console.log("modules Path: ", modules.path);
var modules_info = Process.findRangeByAddress(ptr(modules.base))
console.log("Protection: ", modules_info.protection);

 

Module 예시 : findExportByName

var fopen = Module.findExportByName(null, "fopen");
console.log("fopen: " + fopen);
// iOS
var mName = "libsystem_c.dylib" 
// Android
var mName = "libc.so" 
var fopen_m = Module.findExportByName(mName, "fopen");
console.log("fopen with module: " + fopen_m);

 

  • Int64 / Uint64 : 인자로 전달한 값을 숫자로 변환하는 객체
add(rhs), sub(rhs), and(rhs), or(rhs), xor(rhs) 변환된 10진수 값에 대해 산술 연산을 수행합니다.
shr(n), shl(n) 변환된 10진수 값에 대해 n 비트만큼 쉬프트 연산을 수행할 수 있습니다.
compare(rhs) 인자로 전달된 값과 비교합니다.
toNumber() Int64 또는 Uint64를 사용한 정수 객체를 숫자 타입으로 변경합니다.
toString([radix = 10]) 변환된 10진수의 값을 문자열 형태로 변환합니다. radix는 진수를 나타내며, 기본값은 10입니다.
  • NativePointer: 인자로 전달된 문자열 값을 메모리 포인터로 변환하는 객체
isNull() 포인터가 NULL인지 검사합니다.
add(rhs), sub(rhs), and(rhs), or(rhs), xor(rhs) 포인터 값을 각 함수에 해당하는 산술 연산을 수행합니다.
compare(rhs) 전달된 인자 값과 정수 형태로 비교합니다.
toInt32() NativePointer 타입을 signed 32-bit 정수로 캐스팅합니다.
toString([radix = 16]) 포인터 값을 문자열로 변환합니다. radix는 진수를 나타내며, 기본값은 16입니다.
readPointer(), writePointer(ptr) 포인터 주소에서 NativePointer 형태로 값을 읽거나 씁니다. 이 때 포인터의 크기는 대상 프로세스의 포인터 크기로 가정합니다.
readS8(), readU8(), readS16(), readU16(), readS32(), readU32(), readShort(), readUShort(), readInt(), readUInt(), readFloat(), readDouble(), readS64(), readU64(), readLong(), readULong() 포인터 주소로부터 각 함수의 접미사를 타입으로 하여 값을 읽습니다. 예를 들어 readU16 함수는 포인터 주소로부터 부호 없는 16비트 값을 읽습니다.
writeS8(value), writeU8(value), writeS16(value), writeU16(value), writeS32(value), writeU32(value), writeShort(value), writeUShort(value), writeInt(value), writeUInt(value), writeFloat(value), writeDouble(value), writeS64(value), writeU64(value), writeLong(value), writeULong(value) 포인터 주소에 각 함수의 접미사를 타입으로 하여 값을 씁니다. 예를 들어 writeU16 함수는 포인터 주소에 부호 없는 16비트 값을 씁니다.
readByteArray(length), writeByteArray(bytes) readByteArray 함수는 포인터 주소로부터 length 길이만큼 값을 읽고, writeByteArray 함수는 ArrayBuffer 타입의 배열을 포인터 주소에 씁니다.
readCString([size = -1]), readUtf8String([size = -1]) 인자로 전달한 size 만큼 문자열을 읽어옵니다. 각 함수에 따라 ASCII, Utf-8 문자열 형태로 읽습니다. size 값이 -1일 경우, NULL 값이 나타날 때까지 읽습니다.
writeUtf8String(str), writeAnsiString(str) 인자로 전달한 문자열을 Utf-8, Ansi 문자열 형태로 포인터 주소에 씁니다. writeAnsiString 함수는 Windows 에서만 유효합니다.
  • NativeFunction: 코드에서 지정한 주소를 실제 함수처럼 사용할 수 있는 객체
    • new NativeFunction(address, returnType, argTypes[, abi])
반응형

'보안 및 개발 > MOBILE' 카테고리의 다른 글

[iOS] 세팅 트윅  (0) 2021.11.08
[Android] Android 7.0 이상 버전 인증서  (0) 2021.03.22
[Android] Burpsuite 사용하기  (0) 2021.03.18
URI Scheme 변조  (0) 2021.03.05
자주사용하는 ADB 명령어  (0) 2020.11.03