Information Security/Android
frida-gum Integration Android
hackcatml
2022. 8. 6. 14:30
반응형
모의해커라면 frida를 이용하여 모바일 앱 동적 분석을 자주 합니다.
예전 같으면 꿈도 못꿨을 모바일 앱 리버싱이 정말 많이 편해졌죠. 신입 모의해커도 프리다는 기본으로 다룰 줄 아는 시대입니다.
그러나, frida JavaScript API 라는 무기를 하나 가졌을 뿐입니다.
전쟁터에 무기 딱 하나 들고 참전했는데, 여러가지 이유로 해당 무기를 사용 못하게 되면 참 난감해지겠죠. 그래서, frida는 코어 모듈을 떼어다가 다른 무기를 만들 수 있게끔 제공하고 있습니다.
무기를 하나 더 들고 참전하는 만큼 다양한 상황에 좀 더 유연하게 대처가 가능합니다.
frida-gum은 c언어로 작성되었으며, 이를 static library로 제공하고 있어서 프로그램에 포함하여 코드 작성이 가능합니다.
예를 들어, 악성 앱이 실행되면서 랜덤한 이름의 so파일을 생성해서 사용하고 삭제하는 로직이라면 lsposed와 frida-gum의 gum_process_enumerate_modules 함수를 이용해서 덤프를 뜰 수 있습니다.
#include "frida-gum.h"
#include "com_hackcatml_test_MainModule.h"
#include <sstream>
#include <regex>
#include <sys/mman.h>
#include <thread>
static bool isModuleFound = false;
static std::regex modulePattern("so파일 정규식 패턴");
static std::string sofile_dir = "/data/data/com.hackcatml.test/files/";
void dump_so(uintptr_t module_base, unsigned long sofile_size) {
std::stringstream module_base_hexstr;
module_base_hexstr << "0x" << std::hex << module_base;
LOGD("module base: %p", module_base);
LOGD("module base hex string: %s", module_base_hexstr.str().c_str());
LOGD("module size: %lu", sofile_size);
std::string sofile_path = sofile_dir + "dump[" + module_base_hexstr.str() +"].so";
int dfd = open(sofile_path.c_str(), O_RDWR | O_CREAT, 0777);
if(dfd >= -1){
LOGD("gonna write file");
ftruncate(dfd, sofile_size);
// file memory mapping
void *dest = mmap(nullptr, sofile_size, PROT_WRITE | PROT_READ, MAP_SHARED, dfd, 0);
// 모듈 base 주소의 메모리 프로텍트를 'rwx'로 설정하여 access violation 방지
mprotect((void *)module_base, sofile_size, PROT_READ | PROT_WRITE | PROT_EXEC);
// memory copy
memmove(dest, reinterpret_cast<const void *>(module_base), sofile_size);
// memory unmapping
munmap(dest, sofile_size);
close(dfd);
} else {
LOGD("failed to open file");
}
}
static gboolean
moduleFound(const GumModuleDetails * details, gpointer user_data)
{
const char* path = details->path;
if(std::regex_match(path, modulePattern)){
LOGD("found! %s", path);
isModuleFound = true;
std::thread t(dump_so, details->range->base_address, details->range->size);
t.detach();
return false;
}
return true;
}
void on_library_loaded(const char *name, void *handle){
if(!isModuleFound){
gum_process_enumerate_modules(moduleFound, NULL);
}
}
__attribute__((constructor))
void before_main(void)
{
gum_init_embedded ();
LOGD("frida-gum init!");
}
extern "C" __attribute__((visibility("default")))
NativeOnModuleLoaded native_init(const NativeAPIEntries *entries)
{
LOGD("native init!");
return on_library_loaded;
}
반응형