[AOS] How to Find JNI_OnLoad in Library

koo00·2023년 1월 12일
0

I. Intro

라이브러리 분석 시 (.init_array, .init_proc 과 같은 친구들이 있지만) 일반적으로 JNI_OnLoad 함수가 가장 먼저 호출되기 때문에 해당 함수를 먼저 분석해야 한다.
이때 JNI_OnLoad 함수가 숨겨져 있을 경우 찾는 방법에 대한 포스팅이다.


II. Hooking

먼저 JNI_OnLoad 함수 후킹을 통한 방법이다.

라이브러리 로드 시 JNI_OnLoad 후킹을 통해 주소 값을 쉽게 알아낼 수 있다.

Interceptor.attach(Module.findExportByName(null, 'android_dlopen_ext'), {
	onEnter: function(args) {
		this.path = args[0].readUtf8String();
	},
	onLeave: function(retval) {
		if(this.path.indexOf('libname.so') !== -1) {
			var JNI_OnLoad = Module.findExportByName('libname.so', 'JNI_OnLoad');
			console.log('[*] JNI_OnLoad : ' + JNI_OnLoad);
			
			Interceptor.attach(JNI_OnLoad, {
				onEnter: function(args) {
					// hooking ...
				}
			});
		}
	}
});


정적 분석 시 JNI_OnLoad 함수가 암호화 되어있다면 JNI_OnLoad 호출 전에 복호화를 진행하기 때문에 호출 시점에 메모리를 덤프하면 정적 분석이 가능하다.


III. Debugging

다음은 디버깅을 통한 방법이다. 참고로 나는 Android 11, arm64-v8a 환경에서 진행했다.

System.loadLibrary 함수가 실행될 때 라이브러리는 대략 아래와 같은 과정으로 로드된다. (자세한 로드 및 링킹 과정은 Reference 참고)

libart.so!art::JavaVMExt::LoadNativeLibrary (0x397230) > libnativeloader.so!dlopen_ext > libdl.so!android_dlopen_ext > linker64!dlopen_ext > linker64!do_dlopen (0x35280) > libname.so!.init_func

do_dlopen 함수가 실행될 때 X0 레지스터에서 라이브러리명을 확인할 수 있다.

LoadNativeLibrary 함수가 실행되며 라이브러리가 정상적으로 로드되어 .init_func 함수가 호출된 이후 art::SharedLibrary::FindSymbolWithoutNativeBridge (0x26BE94) 함수의 리턴 값으로 JNI_OnLoad 함수의 주소 값을 얻을 수 있다.

이후 JNI_OnLoad 주소로 분기(BR X24)하기 때문에 JNI_OnLoad 주소 값에 BP를 걸어 분석하면 된다.


IV. Outro

2023년의 첫 포스팅이다.

1~2년 전에는 JNI_OnLoad 후킹도 제대로 못했는데, 지금 보니 분석 능력도 과거에 비해 많이 개선된 것 같다. 뭘 했는지 잘 모르겠는데 암튼 발전했구나 하는 걸 느낀다.

역시 기록을 해야 하나 보다.

하지만 아직 갈 길이 멀다... 올해도 열심히 하자!


Reference

https://cloud.tencent.com/developer/article/1736997
https://android.googlesource.com/platform/bionic.git/+/master/linker/linker.cpp
https://android.googlesource.com/platform/art/+/e34fa1d/runtime/java_vm_ext.cc

profile
JFDI !

0개의 댓글