암호화 또는 난독화된
global-metadata.dat
파일 추출 방법 두번째 포스팅이다.이번 포스팅에서는
global-metadata.dat
파일뿐만 아니라libil2cpp.so
파일도 함께 암호화되어있을 때 복호화 및 덤프하는 방법에 대해 다룰 것이다.참고로 첫번째 포스팅에서 다뤘던 보안 솔루션과는 다른 솔루션이며 프리다 탐지, 메모리 스캔 및 후킹 탐지를 우회해야 가능하다.
먼저 apk
파일의 lib
폴더에 있는 libil2cpp.so
파일을 열어보면 암호화되어있다.
그리고 assets/bin/Data/Managed/Metadata
폴더에 있는 global-metadata.dat
파일도 암호화되어 있다.
복호화 과정이 어떻게 되는지는 능력 부족으로 파악하지 못했으나 게임이 정상 실행되려면 무조건 원본 libil2cpp.so
파일과 global-metadata.dat
파일을 로드하는 과정이 필요하다.
따라서 원본 파일을 얻기 위해 게임이 정상 실행된 이후 덤프한다.
먼저 원본 IL2CPP
파일을 얻기 위해 아래의 스크립트는 Frida CLI
에서 실행시켰다.
var module = Process.findModuleByName('libil2cpp.so');
var il2cpp = module.base;
var offset = module.size;
// Memory.protect(il2cpp, offset, 'rwx');
var file = new File('/sdcard/Download/dec_libil2cpp.so', 'wb');
var buf = il2cpp.readByteArray(offset);
file.write(buf);
file.flush();
file.close();
스크립트 실행 전 hexdump
를 통해 덤프할 파일의 포맷이 ELF
인지 확인하고
Base Address
를 기억해두어야 한다. 내가 덤프한 IL2CPP
파일의 Base Address
는 0x745e601000
이다.
덤프가 성공적으로 될 경우 단말기의 Download
폴더에서 dec_libil2cpp.so
파일을 얻을 수 있고 IDA
로 열면 복호화되어 있는 것을 알 수 있다.
이제 LoadMetaDataFile
함수를 찾아야 한다. 먼저 global-metadata.dat
문자열을 검색한다.
xrefs
를 통해 호출 시점을 따라갈 경우 서브 루틴 하나가 나온다. sub_1992C0
서브 루틴이 LoadMetaDataFile
함수라는 것을 알 수 있다.
빠르게 후킹을 걸자.
Interceptor.attach(Module.findExportByName(null, 'dlopen'), {
onEnter: function(args) {
this.path = args[0].readUtf8String();
},
onLeave: function(retval) {
if(this.path.indexOf('libil2cpp.so') !== -1) {
var il2cpp = Module.findBaseAddress('libil2cpp.so');
console.error('[!] il2cpp : ' + il2cpp);
var LoadMetaDataFile = il2cpp.add(0x1992C0);
Interceptor.attach(LoadMetaDataFile, {
onLeave: function(retval) {
console.error('[!] LoadMetaDataFile retval : ' + retval);
}
});
}
}
});
스크립트를 다시 실행시켜 LoadMetaDataFile
함수의 리턴 값을 확인한다. 0x746f09d000
이 global-metadata.dat
의 시작 주소 값이다.
hexdump
로 해당 주소 값을 확인할 경우 global-metadata.dat
파일의 매직 넘버를 확인할 수 있다.
global-metadata.dat
파일의 주소 값을 확인했으니 현재 메모리에서 덤프할 메모리를 확인해준다.
덤프할 크기는 0x163000
이다.
libil2cpp.so
파일 덤프했을 때와 마찬가지로 global-metadata.dat
파일을 덤프해준다.
var metadata = ptr(0x746f09d000);
var offset = 0x163000;
var file = new File('/sdcard/Download/dec_global-metadata.dat', 'wb');
var buf = metadata.readByteArray(offset);
file.write(buf);
file.flush();
file.close();
덤프가 성공적으로 되면 dec_global-metadata.dat
파일의 이름을 global-metadata.dat
파일로 변경시킨 뒤 IL2CPPDumper
를 실행한다.
원래라면 덤프가 되어야 하지만 Input il2cpp dump address or input 0 to force continue:
라는 메시지가 뜬다. 이때 IL2CPP
덤프할 때 기록한 Base Address
를 입력해준다.
0x745e601000
입력 시 덤프가 성공적으로 된다!
IDA
에서 스크립트 로드하면 꺼-억