← 목록으로

Frida로 동적 계측/후킹하기

[Rev] 리버싱 · 작성: 2026-07-19 19:34:18 · 수정: 2026-07-21 23:29:11 · 조회 18

Frida를 "후킹 스크립트를 파이썬/JS로 짤 수 있는 도구"로만 알면, 이게 동적 분석 글에서 다룬 ptrace 기반 디버거와 근본적으로 다른 방식으로 동작한다는 걸 놓치게 된다. Frida는 "멈춰서 들여다보는" 디버거가 아니라, 대상 프로세스 안에 자기 자신의 JS 런타임을 통째로 주입해서, 그 프로세스가 계속 실행되는 동안 실시간으로 함수 호출을 가로채는 방식이다.

아키텍처 레벨: Frida는 어떻게 "안에서" 동작하는가

Frida를 대상 프로세스에 attach하면 내부적으로 이런 일이 벌어진다.

  1. 주입(Injection): Frida는 ptrace(리눅스) 또는 플랫폼별 API로 대상 프로세스의 메모리 공간에 자신의 에이전트 라이브러리(공유 라이브러리)를 강제로 로드시킨다 — 대상 프로세스 입장에서는 마치 자기가 dlopen()으로 그 라이브러리를 직접 로드한 것처럼 보이게 만드는 기법이다
  2. 내장 JS 엔진: 이 에이전트 라이브러리 안에는 QuickJS(경량 JS 엔진)가 통째로 내장되어 있다 — 우리가 작성한 JS 후킹 스크립트는 이 엔진이 대상 프로세스의 주소 공간 "안에서" 그대로 실행한다. Frida 서버(파이썬 쪽)는 이 내부 JS 엔진과 통신하며 결과를 주고받는 역할만 한다
  3. Interceptor.attach()의 실제 동작 — 인라인 후킹(Trampoline): 후킹하려는 함수의 시작 주소에서, Frida는 **그 함수의 원래 명령어 몇 바이트를 자신의 트램폴린 코드로 교체(패치)**한다. 함수가 호출되면 원래 코드 대신 이 트램폴린으로 먼저 진입해서 우리가 등록한 onEnter/onLeave 콜백을 실행한 뒤, 백업해둔 원래 명령어를 실행하고 원래 흐름으로 복귀시킨다 — ptrace로 매번 멈추는 게 아니라, 함수 자체의 코드를 실행 중에 살짝 바꿔치기해서 "가로채기 코드"를 심어두는 방식이라는 게 디버거와의 근본적인 차이다

실전 후킹 예시: 인증 함수 결과 조작

// 예: is_valid_license()가 항상 true를 반환하도록 강제
Interceptor.attach(Module.findExportByName(null, "is_valid_license"), {
  onEnter(args) {
    console.log("is_valid_license() 호출됨, 인자:", args[0].readCString());
  },
  onLeave(retval) {
    console.log("원래 반환값:", retval.toInt32());
    retval.replace(1);   // 반환값을 강제로 1(성공)로 조작
  }
});

retval.replace()함수가 반환하기 직전, RAX 레지스터에 담긴 반환값을 그대로 덮어쓰는 동작이다 — 스택 버퍼 오버플로우로 리턴 주소를 덮는 것과 마찬가지로, "CPU가 다음에 참조할 값을 신뢰 없이 그대로 조작한다"는 같은 발상이 여기서는 훨씬 안전하고 통제된 방식으로 재현된다.

왜 안티 디버깅 상당수를 우회하는가

안티 디버깅 글에서 다룬 ptrace(PTRACE_TRACEME) 셀프 트레이스 탐지는 gdb 같은 ptrace 기반 디버거를 겨냥한 것이다. Frida도 주입 시점에는 ptrace를 쓰지만, 이후 함수 후킹은 코드 패치 방식이라 TracerPid 확인 같은 일부 탐지에는 여전히 걸릴 수 있는 반면, int3 소프트웨어 브레이크포인트를 전혀 심지 않으므로 코드 무결성 체크섬 기반 탐지는 그대로 통과하는 경우가 많다 — 안티 디버깅 기법마다 Frida에 대한 효과가 다르다는 점을 이해하고 대상에 맞는 우회를 골라야 한다.

모바일 리버싱에서 특히 강력한 이유

안드로이드 앱 리버싱이나 iOS 앱 리버싱에서는 앱을 재컴파일하거나 서명을 다시 하지 않고도, Frida로 런타임에 SSL Pinning 검증 함수나 루팅/탈옥 탐지 함수를 즉석에서 무력화할 수 있다 — 모바일 플랫폼의 코드 서명 제약 때문에 바이너리를 영구적으로 패치하기 번거로운 환경에서, "실행 중에만 잠깐 바꿔치기하는" Frida의 방식이 특히 실전에서 선호되는 이유다.

여기서 끝나지 않는다

Frida를 "편리한 후킹 도구"가 아니라 **"대상 프로세스 안에 직접 실행 환경을 심어서, 코드 자체를 실행 중에 패치하는 인라인 계측 기법"**으로 이해하면, 왜 이게 ptrace 기반 디버거보다 훨씬 유연하면서도 일부 탐지 기법에는 여전히 걸릴 수 있는지가 같은 논리로 설명된다.

리버싱 카테고리의 글 (6/11)

  1. 리버싱이란 무엇인가: 정적 분석 기초
  2. 어셈블리어 읽기 기초 (x86-64)
  3. 동적 분석: 디버거로 실행 흐름 추적하기
  4. 안티 디버깅 / 안티 리버싱 기법과 우회
  5. 패킹과 언패킹: 실행 파일을 압축/암호화해서 숨기기
  6. Frida로 동적 계측/후킹하기
  7. 안드로이드 앱 리버싱: APK 분석 기초
  8. iOS 앱 리버싱 기초
  9. 크랙미(Crackme) 실습 방법론
  10. PE 포맷 내부 구조: Windows 실행 파일 뜯어보기
  11. 코드 난독화 해제: Control Flow Flattening 분석하기
← 패킹과 언패킹: 실행 파일을 압축/암호화해서 숨기기 안드로이드 앱 리버싱: APK 분석 기초 →