직접 주입한 frida-gum 사용하기

서론

출처: Frida-gum을 이용한 Android Hook - 라온

출처의 글이 4~5년 정도 되기도 했고 지금까지는 frida를 이렇게까지 쓴적이 없었지만, 이해도와 숙련도를 높이기 위해 정리해보려고 한다.

frida-gum 라이브러리

일반적인 프리다 사용 방식은 frida 프로젝트를 빌드하면 생성되는 frida-server 를 실행하고 cli와의 통신으로 frida-agent가 라이브러리 형태로 앱에 주입되어 내부의 frida-gum 모듈을 통해 C/C++ 함수의 후킹이 가능하게 된다.

그래서 이런 방법이 있는지도 모르고 사용하고 있었는데, frida-gum을 라이브러리 형태로 빌드하고 이걸 주입해서 후킹코드를 작성하여 클라이언트처럼 사용하는 방식이 있었다.

한번 해보자

예제 테스트

테스트 환경

  • wsl ubuntu 24.04
  • Android 13 (sdk 33) arm64
  • android-ndk-r25c (현재 지원하는 최신버전)
  • frida-gum 16.5.6

libfrida-gum.a 라이브러리 빌드

devkit으로 빌드하면 라이브러리와 예제 파일을 얻을 수 있다.

meson 빌드 시스템을 사용하며, configure -> releng/meson_configure.py -> meson setup 로 연결되고 기본적으로 meson.options 파일에 정의된 기본 옵션들과 인자로 전달한 추가 옵션을 파싱해서 빌드 디렉터리를 생성하게 된다.
이후 make -> Makefile -> releng/meson_make.py -> meson compile 순서로 호출되어 빌드되며 빌드디렉터리 내에 정의된 옵션과 meson.build 에 정의된 규칙에 따라 frida가 빌드되는 구조를 갖고 있다.

git clone --recursive https://github.com/frida/frida-gum.git
git checkout tags/16.5.6
make
mkdir android-arm64
cd android-arm64
../configure --host=android-arm64 --with-devkits=gum
make 
cd ./gum/devkit

73fe36a7-9d20-47d8-9c1a-9ae344b7b9eb
73fe36a7-9d20-47d8-9c1a-9ae344b7b9eb

예제 파일 빌드 및 실행

예제 코드를 보면 맨위에 주석으로 어떻게 빌드하는지도 적혀있다. 하지만 나는 크로스플랫폼 타겟(안드로이드)으로 작성할 것이기 때문에 clang을 ndk에 있는걸로 써야한다.

~/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang -DANDROID -ffunction-sections -fdata-sections frida-gum-example.c -o frida-gum-example -L. -lfrida-gum -llog -ldl -lm -pthread

빌드된 파일을 실행하면 이렇게 보인다.

e7e2f8b9-a0b1-409d-a1b3-3ec019cdffc3
e7e2f8b9-a0b1-409d-a1b3-3ec019cdffc3

구조 분석

example 코드는 간단하다. 그냥 리스너 attch 후 open, close를 후킹하고 호출하고, 리스너 detach 후 호출하기만 한다.

int
main (int argc,
      char * argv[])
{
  // ... 인터셉터를 생성하고 리스너를 opem, close 함수에 attach 한다. 
  interceptor = gum_interceptor_obtain ();
  gum_interceptor_begin_transaction (interceptor);
  gum_interceptor_attach (interceptor,
      GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "open")),
      listener,
      GSIZE_TO_POINTER (EXAMPLE_HOOK_OPEN));
  gum_interceptor_attach (interceptor,
      GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "close")),
      listener,
      GSIZE_TO_POINTER (EXAMPLE_HOOK_CLOSE));
  gum_interceptor_end_transaction (interceptor);

  // 테스트 1. 오픈, 클로즈 테스트 
  close (open ("/etc/hosts", O_RDONLY));
  close (open ("/etc/fstab", O_RDONLY));

  // 리스너를 detach 한다. 
  gum_interceptor_detach (interceptor, listener);

  // 잘 detach 됐는지 확인. 이때는 로그출력이 안된다. 
  close (open ("/etc/hosts", O_RDONLY));
  close (open ("/etc/fstab", O_RDONLY));

  // detach 이후에 리스너가 호출됐는지 확인하는 코드. 
  // 위에서 볼 수 있듯 여전히 4 call 이다.  
  g_print ("[*] listener still has %u calls\n", EXAMPLE_LISTENER (listener)->num_calls);
  // ... 
}

// on_enter 리스너이다. 
static void
example_listener_on_enter (GumInvocationListener * listener,
                           GumInvocationContext * ic)
{
  ExampleListener * self = EXAMPLE_LISTENER (listener);
  ExampleHookId hook_id = GUM_IC_GET_FUNC_DATA (ic, ExampleHookId);

  switch (hook_id)
  {
    case EXAMPLE_HOOK_OPEN:
      g_print ("[*] open(\"%s\")\n", (const gchar *) gum_invocation_context_get_nth_argument (ic, 0));
      break;
    case EXAMPLE_HOOK_CLOSE:
      g_print ("[*] close(%d)\n", GPOINTER_TO_INT (gum_invocation_context_get_nth_argument (ic, 0)));
      break;
  }
  // 호출될 때마다 호출 카운트 증가
  self->num_calls++;
}

직접 인젝트해서 사용

예제코드는 자기 자신을 후킹하는 것이기 때문에 api 테스트는 가능하지만 의미 없는 코드이다.

테스트

공유 라이브러리 형태로 빌드

main 함수를 라이브러리 로드하면서 실행할 수 있도록 .init_array 등록 코드로 변경한다.

- int main(int argc, char * argv[])

+ __attribute__((constructor))
+ int init(void *arg)

빌드할때는 공유 라이브러리 형태로 빌드되도록 -shared 옵션을 추가하면 된다.

~/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang -DANDROID -ffunction-sections -fdata-sections frida-gum-example.c -o frida-gum-example -L. -lfrida-gum -llog -ldl -lm -pthread -shared

60771c71-f492-421d-beae-ef16ebacd4ca
60771c71-f492-421d-beae-ef16ebacd4ca

인젝터 빌드

~ 이 깃허브에서 빌드해서 사용하면 된다.
~ 방식으로 ~ 에러가 발생하기 때문에 이동시켜서 인젝트 한다.

실행

—– so injection 에 대해 공부 후 진행 —–

Comments

ESC
Type to search...