- 원글: 2021. 1. 14. 13:01
- 수정: 오타 수정 및 이미지 링크 수정
IDA를 이용한 JNI(Java Native Interface) 정적 분석
JNI
JNI란 JVM이 native code(C/C++)로 만들어진 코드와 상호작용할 수 있도록 도와주는 인터페이스다.
정확히는 Android가 JAVA 또는 Kotlin으로 작성된 byte code와 native code(C/C++)의 상호작용 방법을 정의한 것이다.
개념과 예제는 아래 링크에서 확인할 수 있다.
https://developer.android.com/training/articles/perf-jni?hl=en
오라클에서 자세한 정보를 제공하기도 한다.
https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
JNI example
JEB로 APK
파일을 분석 중이었는데, 아래와 같이 native code
를 참조한다고 나와있고 함수가 어떻게 정의되어있는지 알 수 없었다.
package com.tencent.mm.jniinterface;
public class AesEcb {
public static native byte[] aesCryptEcb(byte[] _arg0, byte[] _arg1, boolean _arg2, boolean _arg3) {
}
public static native void test() {
}
}
native code를 분석하기 위해 .so
파일을 분석해야 했다.
어플리케이션이 사용하는 so 파일이 약 80개였는데 어떤 파일에 정의되어있는지 알 수 없었다.
따라서 아래와 같은 명령어로 적절히 찾아주었다.
# Windows
findstr /S "aesCryptEcb" *.so
# OS X or Linux
grep -r "aesCryptEcb" ./
libwechatcommon.so
에 있다는 것을 확인했고, 다행히 클래스명으로 검색할 수 있었다.
native code에서는 함수명이 Java_[패키지]_[클래스]_[메소드]
으로 정의된다.
Java_com_tencent_mm_jniinterface_AesEcb_aesCryptEcb()
그리고 인자는 두 개가 추가된다. 첫 번째 인자는 JNIEnv*
, 두 번째 인자는 jobject
다.
그 뒤에 실제로 전달하는 인자들이 위치한다.
이때 인자는 자바 타입에 맞게 변한다.
타입은 아래 링크에서 확인할 수 있다.
https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
즉 다음과 같이 표현될 수 있다.
- Java code -
aesCryptEcb()
public static native byte[] aesCryptEcb(
byte[] _arg0, byte[] _arg1, boolean _arg2, boolean _arg3
)
- nativa code -
Java_com_tencent_mm_jniinterface_AesEcb_aesCryptEcb()
void __fastcall Java_com_tencent_mm_jniinterface_AesEcb_aesCryptEcb(
JNIEnv* env, jobject jobj,
jbyteArray _param1, jbyteArray _param2, jboolean _param3, jboolean _param4
)
그런데 디컴파일을 하면 인자의 개수나 타입을 제대로 파싱하지 못하는 모양이다.
인자는 다음과 같았다.
(__int64 a1, __int64 a2, __int64 a3, __int64 a4, unsigned __int8 a5, char a6)
무엇보다 JNIEnv 관련 함수
를 제대로 파싱하지 못한다.
아래 코드 조각에서 sub_94B14()
함수의 인자인 a1은 JNIEnv*
타입으로 env+offset
형태로 함수를 호출한다. a1 + 1408LL
__int64 __fastcall sub_94B14(__int64 a1, __int64 a2, int a3)
{
// skip..
v5 = *(__int64 (**)(void))(*(_QWORD *)a1 + 1408LL);
// skip..
}
실제 offet 1408의 함수는 NewByteArray()
이므로 아래와 같이 디컴파일 되어야 한다.
__int64 __fastcall sub_94B14(JNIEnv *a1, __int64 a2, int a3)
{
// skip..
v5 = (__int64 (*)(void))(*a1)->NewByteArray;
// skip..
}
IDA
에서 JNI
를 분석할 수 있는 몇가지 방법이 있어서 정리한다.
Method 1 - JNIEnv structure table
먼저 수동으로 분석하는 방법이다.
아래 사이트를 보면 env의 특정 offset에 어떤 함수가 있는지 알 수 있다.
https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
https://gist.github.com/zhangyoufu/5814814
이런 정보를 구글시트에 정리한 자료도 있다.
https://docs.google.com/spreadsheets/d/14GgLwizg6qZzCBVxYc3HfegBGBh5Zff5XpyO3cZP64o/edit?usp=sharing
하지만 수동으로 분석하는 것은 매우 귀찮은 일이다.
다른 방법이 적용되지 않는 경우에만 사용하자.
Method 2 - Set Type JNIEnv*
단순히 타입을 JNIEnv*
로 바꾸는 방법이다.
바꾸려는 타입을 우클릭한 뒤 Set lvar type(Y)
를 클릭한다.
그리고 타입을 JNIEnv*
로 바꿔준다.
많은 사람들이 이 방법을 사용하는 것 같은데 본인은 아래와 같은 오류
가 발생한다.
IDA 버전이나 바이너리에 따라 적용이 안되는 경우도 있는 것 같다.
그래서 다른 방법을 더 찾아보았다.
Method 3 - Parsing jni.h
JNI type을 미리 정의한 헤더파일을 적용하는 방법이다.
이 방법은 IDA 버전에 상관없이 적용 가능
하다.
JNIEnv를 파싱하도록 도와주는 jni_all.h
파일이 아래 github에 공개되어있다.
https://gist.github.com/Jinmo/048776db75067dcd6c57f1154e65b868
파일을 다운받고 IDA에서 적용할 수 있다.
File
→ Load file
→ Parse C header file
→ jni_all.h
선택
이후 Method 2
를 적용하면 에러 없이 잘 적용된다.
Method 4 - Add standard stuctures
JNIEnv관련 타입을 standard stuctures에 추가하는 방법이다.
이 방법은 IDA 7.0 이상
에서 적용가능하다고 확인되었다. (이전 버전에서 테스트해본 사람은 못봤다.)
게다가 추가적인 파일이 필요없고, IDA 기능만으로 적용할 수 있다.
먼저 View → Open subviews → Type libraries
탭으로 이동한다.
추가를 위해 우클릭 후 Load type library
클릭
android_arm
추가
이제 standard structure에 추가해줘야 한다.
Edit → Add struct type
(tool bar 이용 시 Define a new structure/union type
)
Add standard structure
_JNIEnv
추가
그러면 아래처럼 standard type에 _JNIEnv
구조체를 확인할 수 있다.
이제 분석이 필요한 함수로 이동한다.
첫 번째 인자의 타입 우클릭 후 Convert to struct *
그러면 아까 추가한 _JNIEnv
타입으로 바꾸어 줄 수 있다.
그러면 IDA가 제대로 디컴파일 해준다.
참고
JNI tips: https://developer.android.com/training/articles/perf-jni?hl=en
JNI 예제: https://realapril.tistory.com/35
JNIEnv Structure Table:
https://docs.google.com/spreadsheets/d/14GgLwizg6qZzCBVxYc3HfegBGBh5Zff5XpyO3cZP64o/edit?usp=sharing
IDA decompiles so files into Jni: https://www.programmersought.com/article/19415131063/
IDA JNI Function 적용하기: https://chp747.tistory.com/330
Ida Restore Jni Function method name: https://topic.alibabacloud.com/a/ida-restore-jni-function-method-name_8_8_31390896.html
Uploaded by Notion2Tistory v1.1.0