안드로이드 악성코드 분석 시, 원본 dex를 숨기기 위해 dex파일 동적로딩을 하는 경우가 많이 있습니다.
동적으로 Dex파일을 로드하기 위해선 파일 혹은 메모리에서 로드하는데 다음과 같은 함수를 사용하게 됩니다.
From file:
dalvik.system.DexFile.loadDex depreciated after API 26
dalvik.system.DexClassLoader
dalvik.system.PathClassLoader
From memory:
dalvik.system.InMemoryDexClassLoader (not common in malwares)
파일을 통한 동적로딩 중 DexClassLoader함수를 이용하여 동적로딩하는 코드 작성 및 분석 방법을 확인하겠습니다.
android developer를 통해 확인한 dexclassloader 함수 형식입니다.
아래는 dexclassloader를 이용하여 외부 apk의 dex를 로드하는 코드 예제입니다.
dexclassloader.java
public class MainActivity extends AppCompatActivity {
static final int BUF_SIZE = 8 * 1024;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(
new Button.OnClickListener(){
public void onClick(View v){
String text = loadClass2();
Toast.makeText(getApplicationContext(),text,Toast.LENGTH_LONG).show();
}
});
}
private String loadClass2(){
String APPJS = "test.apk"; // 불러올 apk 이름 명시
File dexInternalStoragePath = new File(getDir("cache",Context.MODE_PRIVATE), APPJS);
BufferedInputStream bis = null;
OutputStream dexWriter = null;
try { // asset 폴더 내 저장된 apk파일을 앱 내 read가 가능한 영역으로 복사
// (/data/data/<app>/app_cache/)
bis = new BufferedInputStream(getAssets().open(APPJS));
dexWriter = new BufferedOutputStream(new FileOutputStream(dexInternalStoragePath));
byte[] buf = new byte[BUF_SIZE];
int len;
while ((len = bis.read(buf, 0, BUF_SIZE)) > 0) {
dexWriter.write(buf, 0, len);
}
dexWriter.close();
bis.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final File optimizedDexOutputPath = getDir("cache",Context.MODE_PRIVATE); // 복사한 apk파일 경로 획득
DexClassLoader dexClassLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(), null,getClassLoader()); //dex 파일 로드
try {
Class clazz = dexClassLoader.loadClass("com.example.user.test.test"); // dex 파일 내 class 로드
Object object = clazz.newInstance();
Method method = clazz.getMethod("get_Message"); //class 내 method 로드
String text = (String) method.invoke(object); //method 호출
return text;
}catch (Exception e){
e.printStackTrace();
}
return "Error..!!";
}
}
test.java(test.apk)
package com.example.user.flag;
public class test{
public String get_Message(){
return "Catch Me!";
}
}
test.java의 경우 앱 실행은 되지 않지만 빌드를 통해 apk파일 생성 및 dexclassloader.java가 있는 프로젝트 assets 파일 내 apk파일 복사
이렇게 작성된 앱의 경우, assets파일 내 apk파일이 존재하는 것을 모른다면 test.java의 내용을 알기 어렵습니다.
원본 Dex 추출을 위해 앱 실행 및 단말기 내 /proc/<pid>/maps를 확인하여 불러오는 dex파일의 위치를 확인합니다.
그 후 해당 위치(위 예제 앱의 경우 /data/data/<package_name>/app_cache/)에 복사한 dex파일이 존재합니다.
다만, 복사한 dex파일은 odex파일로 dex형식으로 변환하여 원본소스코드 확인이 가능합니다.
'Mobile' 카테고리의 다른 글
Frida cheat sheet (0) | 2020.10.11 |
---|---|
MultiDex Dynamic Debug(feat. JEB) (0) | 2020.05.18 |
odex to dex (0) | 2020.05.08 |
ro.debuggable 변경을 통한 동적 디버깅 (2) | 2019.09.23 |
IDA DEX,SO 동적디버깅 (0) | 2019.09.23 |