Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

Android에서 기기가 루팅되었는지 확인하는 방법

루팅된 기기 감지가 필요한 이유

결제 게이트웨이를 연동하는 애플리케이션처럼 보안이 중요한 앱의 경우, 루팅된 기기에서는 앱이 실행되지 않도록 차단해야 할 때가 있습니다. 루팅된 기기는 시스템 권한이 임의로 변경될 수 있어 결제 정보 유출 등 보안 위협에 노출되기 쉽기 때문입니다.

이 글에서는 su 명령어 실행 여부를 통해 현재 기기가 루팅되었는지 판별하는 방법을 Android Studio 프로젝트 예제와 함께 단계별로 살펴보겠습니다.

1단계: 새 프로젝트 생성

Android Studio에서 File → New Project를 선택하고, 새 프로젝트 생성에 필요한 모든 세부 정보를 입력하여 새 프로젝트를 만듭니다.

2단계: 레이아웃 파일 작성

res/layout/activity_main.xml 파일에 아래 코드를 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout xmlns:android = "https://schemas.android.com/apk/res/android"
   android:id = "@+id/parent"
   xmlns:tools = "https://schemas.android.com/tools"
   android:layout_width = "match_parent"
   android:layout_height = "match_parent"
   tools:context = ".MainActivity"
   android:gravity = "center"
   android:orientation = "vertical">
   <TextView
      android:id = "@+id/rootFinder"
      android:layout_margin = "20dp"
      android:textAlignment = "center"
      android:layout_width = "match_parent"
      android:layout_height = "wrap_content" />
</LinearLayout>

위 코드에서는 TextView 하나를 배치했습니다. 이 TextView에는 루팅 여부에 대한 결과 정보가 표시됩니다.

3단계: MainActivity 작성

src/MainActivity.java 파일에 아래 코드를 추가합니다.

package com.example.andy.myapplication;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
   int view = R.layout.activity_main;
   TextView rootFinder;
   @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(view);
      rootFinder = findViewById(R.id.rootFinder);
      executeShellCommand("su");
   }
   private void executeShellCommand(String su) {
      Process process = null;
      try {
         process = Runtime.getRuntime().exec(su);
         rootFinder.setText("It is rooted device");
         Toast.makeText(MainActivity.this, "It is rooted device", Toast.LENGTH_LONG).show();
      } catch (Exception e) {
         rootFinder.setText("It is not rooted device");
      } finally {
         if (process != null) {
            try {
               process.destroy();
            } catch (Exception e) { }
         }
      }
   }
}

위 코드의 핵심 로직은 다음과 같습니다. Runtime.getRuntime().exec("su")를 호출해 슈퍼유저 명령어 실행을 시도하고, 그 성공 여부에 따라 기기의 루팅 상태를 판별한 뒤 결과를 TextView에 표시합니다.

executeShellCommand("su");

private void executeShellCommand(String su) {
   Process process = null;
   try {
      process = Runtime.getRuntime().exec(su);
      rootFinder.setText("It is rooted device");
      Toast.makeText(MainActivity.this, "It is rooted device", Toast.LENGTH_LONG).show();
   } catch (Exception e) {
      rootFinder.setText("It is not rooted device");
   } finally {
      if (process != null) {
         try {
            process.destroy();
         } catch (Exception e) { }
      }
   }
}

동작 원리를 정리하면 다음과 같습니다.

  • 루팅된 기기: su 바이너리가 존재하므로 명령어 실행이 성공하고, "It is rooted device"(루팅된 기기입니다)라는 메시지가 표시됩니다.
  • 루팅되지 않은 기기: su 명령어 실행 시 예외가 발생하며, catch 블록에서 "It is not rooted device"(루팅되지 않은 기기입니다)라는 메시지가 표시됩니다.

마지막으로 finally 블록에서는 생성된 프로세스를 안전하게 종료(destroy)하여 리소스 누수를 방지합니다.

앱 실행 및 결과 확인

이제 애플리케이션을 실행해 보겠습니다. 실제 Android 휴대폰이 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 Run 아이콘을 클릭하고, 옵션 목록에서 자신의 모바일 기기를 선택하세요.

앱이 실행되면 모바일 기기 화면에 아래와 같은 기본 화면이 표시됩니다.

Android에서 기기가 루팅되었는지 확인하는 방법

위 실행 결과에서 볼 수 있듯이, 테스트에 사용된 기기는 아직 루팅되지 않은 상태이므로 "루팅되지 않은 기기"라는 메시지가 출력되었습니다.

참고 사항

su 명령어 실행 방식은 간단하지만, 일부 루팅 숨김 도구(SuperSU의 Stealth 모드 등)나 특정 제조사 환경에서는 감지가 실패할 수 있습니다. 따라서 실제 서비스에서는 이 방법과 함께 /system/bin/su, /system/xbin/su 같은 경로 존재 여부 확인, SafetyNet/Play Integrity API 검증 등을 함께 적용하는 것이 좋습니다.