결제 앱 APK 변조·정산 탈취 막은 다층 무결성 방어
목차
배경
이커머스 앱이 마켓에 풀린 뒤로 이상한 트래픽이 잡히기 시작했음. 정상 클라이언트로는 절대 나올 수 없는 호출 패턴이 보였고, 추적해 보니 APK 디컴파일 후 재서명한 변종이었음. 단순 난독화로는 한계가 명확했고, 결제 플랫폼 특성상 파트너 정산 데이터에 손대는 게 보여서 더 미룰 수 없었음.
1차: 서명 해시 검증
가장 먼저 한 건 런타임 서명 해시 검증임. 앱 부팅 시 패키지매니저로 서명 인증서를 꺼내 SHA-256 해시를 계산하고, 박아둔 정상 해시와 비교했음. 다르면 API 클라이언트 초기화 자체를 차단.
다만 자바 레이어에 박아두면 우회가 너무 쉬웠음. Smali 한 줄 패치로 비교 결과를 뒤집을 수 있어서, 정상 해시 자체를 NDK 영역으로 옮김.
2차: NDK 키 보관
native-keys.cpp 에 정상 해시와 시드 값을 XOR 인코딩으로 저장. CMakeLists.txt 에 strip 옵션과 visibility hidden 을 걸어 심볼 노출을 최소화.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Os")
set_target_properties(nativekeys PROPERTIES LINK_FLAGS "-Wl,--gc-sections")
JNI 진입점만 export 하고 내부 함수는 전부 숨김. IDA 로 까도 문자열이 바로 안 보이게 됨.
3차: 루팅/Frida 탐지
런타임 무결성 체크 항목을 다음과 같이 분리했음.
| 검사 | 신호 | 대응 |
|---|---|---|
| 루팅 | su 바이너리, magisk 흔적, /system 쓰기 가능 | 세션 차단 |
| Frida | gum-js-loop 스레드, frida-agent 매핑 | 즉시 종료 |
| 디버거 | TracerPid 비제로 | API 호출 거부 |
| 에뮬레이터 | 빌드 핑거프린트, 센서 부재 | 서버 플래그 |
특히 Frida 탐지는 /proc/self/maps 와 스레드 이름을 같이 봐야 우회가 어려웠음. 한 군데만 보면 후킹 한 방에 뚫림.
4차: 난독화 룰 정리
proguard-rules.pro 에서 리플렉션 깨질까봐 과하게 keep 해뒀던 항목을 싹 정리했음. 직렬화 모델만 남기고 나머지는 전부 난독화 대상으로 돌림. 빌드 후 mapping.txt 사이즈가 3배로 커진 게 체감됨.
검증하며 깨달은 것
- 한 레이어만 막으면 무조건 뚫림. 자바·NDK·서버 셋이 동시에 검사해야 했음
- 탐지 즉시 앱을 죽이지 않고, 서버에 신호로 먼저 올리는 채널을 따로 둠 → 공격자의 우회 시도 패턴이 로그로 쌓임
- API 클라이언트 초기화 자체를 무결성 통과 후로 미루니, 우회 실패 시 네트워크 호출이 아예 안 나가서 분석 난이도가 한 단계 더 올라감
완벽한 방어는 불가능함. 다만 공격 비용을 충분히 올리면 자동화 변종은 거의 다 걸러지더라.
다음
댓글 0
첫 댓글 달아줘.