티스토리 뷰

AlertDialog

Dialog(다이얼로그)는 말 그대로 대화 상자의 개념으로 Alert(팝업)를 띄워 앱을 사용하는 사용자들에게 추가 입력을 받거나 다음 행위(Yes, No, Cancel)를 결정시키는 용도로 사용됩니다. 이 메시지 창에 사용자가 응답을 하지 않으면 화면에 사라지지 않고 계속 대기하게 됩니다.

 

AlertDialog에는 사용되는 요소들

  • Title: 대화상자의 제목
  • Message: 대화상자를 이해하기 위한 내용
  • Positive Button: 사용자의 긍정적인 반응을 의미(Yes, 네, 확인)
  • Negative Button: 사용자의 부정적인 반응을 의미(No, Cancel, 취소)
  • Netural Button: 긍정 또는 부정도 아닌 반응을 의미(Cancel, Remind Later

일반적으로 사용자들에게 광고성 동의를 얻기 위해서는 위와 같은 대화 상자를 띄워 Yes 또는 No 같은 응답을 얻은 후 Mainactivity로 넘어가도록 구현하게 됩니다. 만약 Cancel 버튼이 구현되어 있지 않을 경우 회피도 할 수 없기 때문에 개발자가 구현해둔 흐름대로 처리됩니다.

 

Setcancelable 활용

AlertDialog.Builder => setCancelable(boolean cancelable)

별도의 Cancel 버튼이 없는 대화상자를 무력화하기 위해선 "Setcacelable" 메소드를 통해 사용자 화면에 띄워진 AlertDialog 대화 상자를 뒤로 가기(Back) 하여 원하는 흐름대로 조작할 수 있습니다.

setCancelable은 Boolean 방식이기 때문에 True 또는 False 를 가집니다.

  • True: 활성화
  • False: 비활성화(대부분의 대화상자는 False 형식을 가짐)

앱의 취약점을 테스트하기 위해선 최상위 권한인 "root"를 가진 상태에서 진행을 하게 되는데, 루팅 디바이스를 탐지할 경우 AlertDialog를 호출을 통해 exit() 종료시켜 제대로 된 접근이 힘들어지게 됩니다.

 

만약 AlertDialog 창이 호출되는 시점에 Mainactivity가 백그라운드에서 실행이 되고 있는 상황이라면 setCancelable을 조작하여 앱이 종료되지 않도록 할 수 있습니다. 이를 통해 공격자는 디바이스의 권한 검사와 무결성 검사까지 우회할 수 있는 상황을 만들 수 있습니다.

 

Rooting/Integrity check Bypass

루팅된 디바이스에서 앱을 실행하게 될 경우 "루팅 된 단말기에서는 사용하실 수 없습니다." 메시지를 출력하게 됩니다. 여기서 "확인" 버튼을 누르게 될 경우 앱은 강제적으로 종료되게 됩니다.

 

디컴파일된 코드를 분석해보면 루팅을 탐지하기 위해 2가지 포인트를 체크합니다. Smali 소스를 수정해서 루팅체크를 우회할 수 있도록 합니다.

  • 실행된 디바이스에서 "su" 명령어가 실행되는지
  • 실행된 디바이스에 루팅과 관련된 파일들이 존재하는지(6경로)

 

리패키징 후 실행해보면 이번에는 "앱 서비스가 일시적으로 중지되었습니다." 메시지가 나타납니다. 마찬가지로 "확인" 버튼을 누르게 되면 앱이 강제적으로 종료되어 실행할 수 없습니다.

 

앱의 무결성을 체크하는 방법은 해쉬, 인스톨러, 개발자키(샤이닝키) 등 여러 가지 방법이 존재하지만 위처럼 Mainactivitiy가 대화 상자와 상관없이 백그라운드에서 실행되면 간단한 트릭을 통해 쉽게 우회할 수 있습니다.

 

MainActivity 쪽 소스를 확인해보면 총 2곳의 "setPositiveButton"이 존재합니다. 일반적으로 우측에 배치된 PositiveButton은 사용자의 긍정적인 답변을 유도하는 메소드 입니다. 광고성 동의 여부도 승인에 필요하는 버튼은 우측에 배치되고 좌측이 부정적인 응답을 가집니다.

 

setPositiveButton => setNeutralButton(좌측 배치)

사용자의 앱을 종료시키는 Positivebutton이 어떤 부분인지 체크하기 위해 하나씩 코드를 변조해서 리패키징 합니다.

 

NeutralButton 메소드를 통해 우측에 있던 버튼이 좌측으로 넘어간것을 확인하실 수 있습니다. 어느 라인의 버튼이 사용자의 앱을 종료시키는지 확인했으니 두번 째로 False로 부여된 setCancelable 메소드를 찾아야 합니다.

 

사용자의 앱을 종료시키는 setPositiveButton에는 대화 상자를 무력화시키지 못하도록 setCancelable(false); 메소드를 추가해 뒀습니다.

 

if-eqz v0, :cond_2 => if-nez v0, :cond_2

디컴파일 상태의 코드의 위치를 기억해두신 후 smali 코드로 넘어가 분기문 수정후 리패키징 작업을 해주시면 됩니다.

eqz: ==(같다)

nez: !=(다르다)

 

최종적으로

1. Rooting 체크 smali 코드 수정(su, filepath)

2. 앱을 종료시키는 Button 탐색

3. 부여된 setCancelable 메소드 분기문 수정

위의 3가지 방법을 통해 사용자의 앱 강제 종료를 막을 수 있게 됩니다. 이러한 문제를 해결하기 위해선 대화 상자가 호출되었을 때 MainAcitivity 가 백그라운드에서 마음대로 실행되지 않게 해야 됩니다. 호출된 대화 상자의 응답을 거친 후에 앱이 실행되는 구조라면 보다 안전하게 운영할 수 있게 됩니다.

Comment
댓글쓰기 폼