Android 장치 DeviceId 와 반 Xposed Hook 가 져 오기

앱 개발 에 있어 서 기기 의 DeviceId 를 가 져 와 야 합 니 다.브러시 에 대응 해 야 합 니 다.현재 자주 사용 되 는 몇 개의 기기 식별 코드 는 주로 IMEI(국제 모 바 일 기기 신분 코드 International Mobile Equipment Identity)나 MEID(Mobile Equipment IDentifier)가 있 습 니 다.이 두 가지 도 흔히 말 하 는 DeviceId 입 니 다.그러나 Android 6.0 이후 에 권한 이 있어 야 얻 을 수 있 습 니 다.그리고...자바 층 에서 이 ID 는 Hook 에 쉽게 걸 릴 수 있 습 니 다.믿 을 수 없 을 수도 있 습 니 다.또한 MAC 주소 나 블 루 투 스 주소,시리 얼 번호 등 을 통 해 다음 과 같이 잠 정적 으로 열거 할 수 있 습 니 다.
IMEI:(International Mobile Equipment Identity)또는 MEID:(Mobile Equipment IDentifier)MAC 또는 블 루 투 스 주소(플래시 를 다시 닦 아야 업데이트 가능)
  • Serial Number
  • AndroidId ANDROID_ID 는 장치 가 처음 시 작 될 때 생 성 되 고 저 장 된 64bit 의 하나 로 핸드폰 이 업그레이드 되 거나 와 이 프 된 후 이 숫자 가 초기 화 됩 니 다
  • 상기 네 가 지 는 자주 사용 하 는 안 드 로 이 드 식별 코드 이 고 시스템 도 상세 한 인 터 페 이 스 를 제공 하여 개발 자 에 게 가 져 다 주 었 습 니 다.그러나 모두 자바 층 의 방법 이기 때문에 Hook 에 쉽게 걸 릴 수 있 습 니 다.특히 일부 전문 적 인 브러시 는 핸드폰 Root 이후 Xposed 프레임 워 크 의 일부 플러그 인 을 이용 하여 얻 은 데 이 터 를 변경 하기 쉽 습 니 다.가장 간단 한 IMEI 를 가 져 옵 니 다.자주 사용 하 는 가 져 오 는 방법 은 다음 과 같 습 니 다.
    TelephonyManager telephonyManager = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
    return telephonyManager.getDeviceId()
    

    루트 사용자 가 Xposed Hook 을 이용 하여 Telephony Manager 류 의 getDeviceId()방법 을 사용 했다 면 다음 과 같 습 니 다.after Hooked Method 방법 에서 DeviceId 를 난수 로 설정 하면 매번 가 져 오 는 DeviceId 가 다 릅 니 다.
    public class XposedModule implements IXposedHookLoadPackage {
    
            try {
                findAndHookMethod(TelephonyManager.class.getName(), lpparam.classLoader, "getDeviceId", new XC_MethodHook() {
                                @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                super.afterHookedMethod(param);
                                    param.setResult("" + System.currentTimeMillis());
                            }
                        });
            } catch (Exception e1) {
            }catch (Error e) {
            } }
    

    그래서 상대 적 으로 정확 한 설비 정 보 를 얻 기 위해 우 리 는 해당 하 는 대응 조 치 를 취해 야 한다.예 를 들 어:
    4.567917.일부 시스템 에 숨겨 진 인 터 페 이 스 를 사용 하여 장치 정 보 를 얻 을 수 있 습 니 다.숨겨 진 인 터 페 이 스 는 변경 되 기 쉽 지 않 습 니 다.전체 시스템 이 정상적으로 작 동 하지 않 을 수도 있 기 때 문 입 니 다
  • 자신 이 Binder 통신 방식 으로 서비스 에 정 보 를 요청 할 수 있다.예 를 들 어 IMEI 호 는 Phone 서비스 에 요청 을 보 내 서 얻 으 려 는 것 이다.물론 Phone 서비스 중의 자바 류 가 Hook 에 의 해 이 루어 진다 면 이런 방식 도 정확 한 정 보 를 얻 지 못 할 것 이다
  • Native 방식 으로 설비 정 보 를 얻 을 수 있 습 니 다.이런 방식 은 Xposed Hook 에 의 해 효과적으로 피 할 수 있 지만 adbi 가 이 지층 Hook 에 있 을 수 있 습 니 다

  • 먼저 getDeviceId 를 어떻게 얻 는 지 살 펴 보 겠 습 니 다.소스 코드 는 다음 과 같 습 니 다.
    public String getDeviceId() {
        try {
            return getITelephony().getDeviceId();
        } catch (RemoteException ex) {
            return null;
        } catch (NullPointerException ex) {
            return null;
        }
    }
    
    private ITelephony getITelephony() {
        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
    }
    

    getDeviceId 가 Hook 에 걸 렸 지만 getITelephony 가 Hook 에 걸 리 지 않 았 다 면 저 희 는 Telephony Manager 의 getITelephony 방법 을 반사 적 으로 얻 을 수 있 습 니 다.ITelephony 의 getDeviceId 를 통 해 DeviceId 를 얻 을 수 있 습 니 다.그러나 이 방법 은 ROM 버 전과 관계 가 있 습 니 다.비교적 빠 른 버 전 은 getITelephony 방법 이 없 었 습 니 다.초기 에는 IPhone SubInfo 의 getDeviceId 를 통 해 얻 을 수 있 었 습 니 다.그러나 상기 두 가지 방식 은 모두 Hook 에 수용 된다.Hook getDeviceId 방법 이 가능 한 만큼 마찬가지 로 Hook getITEphony 방법 도 가능 하 다.이 차원 의 반 Hook 은 큰 의미 가 없다.그래서 조금 더 깊이 들 어 갈 수 있다.ITelephony.Stub.as Interface 는 매우 뚜렷 한 Binder 통신 방식 입 니 다.그러면 저 희 는 Binder 대 리 를 얻 고 Binder 통신 방식 으로 Phone 서비스 에 요청 을 보 내 고 장치 DeviceId 를 얻 습 니 다.Phone 서 비 스 는 adl 파일 로 생 성 된 Proxy 와 Stub 입 니 다.이 를 바탕 으로 저희 의 코드 를 실현 할 수 있 습 니 다.Binder 통신 의 중요 한 몇 가지 점:InterfaceDescriptor+TransactionId+매개 변 수 는 DeviceId 를 가 져 오 는 데 거의 필요 한 매개 변수 가 없습니다(낮은 버 전이 필요 할 수 있 습 니 다).구체 적 인 방법 은:
  • ServiceManager 의 getService 방법 을 통 해 우리 가 필요 로 하 는 Binder 서비스 대 리 를 직접 얻 을 수 있 습 니 다.여 기 는 바로 phone 서비스 입 니 다
  • com.android.internal.telephony.ITelephony$Stub 의 asInterface 방법 으로 프 록 시 대상 을 획득 합 니 다
  • 반 사 를 이용 하여 getDeviceId 의 Transaction id 를 획득 합 니 다
  • 프 록 시 를 이용 하여 Phone 서비스 에 요청 을 보 내 고 DeviceId 를 가 져 옵 니 다

  • 구체 적 으로 다음 과 같이 실현 하면 대리 측의 훅 에 대응 할 수 있다.
     public static int getTransactionId(Object proxy,
                                            String name) throws RemoteException, NoSuchFieldException, IllegalAccessException {
            int transactionId = 0;
            Class outclass = proxy.getClass().getEnclosingClass();
            Field idField = outclass.getDeclaredField(name);
            idField.setAccessible(true);
            transactionId = (int) idField.get(proxy);
            return transactionId;
        }
    
    //     ,      transactionId
    public static String getInterfaceDescriptor(Object proxy) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method getInterfaceDescriptor = proxy.getClass().getDeclaredMethod("getInterfaceDescriptor");
        return (String) getInterfaceDescriptor.invoke(proxy);
    }
    
    
     static String getDeviceIdLevel2(Context context) {
    
            String deviceId = "";
            try {
                Class ServiceManager = Class.forName("android.os.ServiceManager");
                Method getService = ServiceManager.getDeclaredMethod("getService", String.class);
                getService.setAccessible(true);
                IBinder binder = (IBinder) getService.invoke(null, Context.TELEPHONY_SERVICE);
                Class Stub = Class.forName("com.android.internal.telephony.ITelephony$Stub");
                Method asInterface = Stub.getDeclaredMethod("asInterface", IBinder.class);
                asInterface.setAccessible(true);
                Object binderProxy = asInterface.invoke(null, binder);
                try {
                    Method getDeviceId = binderProxy.getClass().getDeclaredMethod("getDeviceId", String.class);
                    if (getDeviceId != null) {
                        deviceId = binderGetHardwareInfo(context.getPackageName(),
                                binder, getInterfaceDescriptor(binderProxy),
                                getTransactionId(binderProxy, "TRANSACTION_getDeviceId"));
                    }
                } catch (Exception e) {
                }
                Method getDeviceId = binderProxy.getClass().getDeclaredMethod("getDeviceId");
                if (getDeviceId != null) {
                    deviceId = binderGetHardwareInfo("",
                            binder, BinderUtil.getInterfaceDescriptor(binderProxy),
                            BinderUtil.getTransactionId(binderProxy, "TRANSACTION_getDeviceId"));
                }
            } catch (Exception e) {
            }
            return deviceId;
        }
    
        private static String binderGetHardwareInfo(String callingPackage,
                                                    IBinder remote,
                                                    String DESCRIPTOR,
                                                    int tid) throws RemoteException {
    
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            String _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                if (!TextUtils.isEmpty(callingPackage)) {
                    _data.writeString(callingPackage);
                }
                remote.transact(tid, _data, _reply, 0);
                _reply.readException();
                _result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    

    Native 방법 을 이용 하여 Xposed Hook 을 반대 합 니 다.
    많은 시스템 매개 변 수 는 우리 가 Build 를 통 해 얻 은 것 이다.예 를 들 어 시리 얼 번호,핸드폰 하드웨어 정보 등 이다.예 를 들 어 시리 얼 번 호 를 얻 고 자바 층 에서 Build 의 feild 를 직접 이용 하여 얻 으 면 된다.
    public static final String SERIAL = getString("ro.serialno");
    
    private static String getString(String property) {
        return SystemProperties.get(property, UNKNOWN);
    }
    

    그러나 SystemProperties 의 get 방법 은 Hook 에 의 해 수용 되 고 Hook 에 의 해 서열 번 호 를 마음대로 변경 할 수 있 습 니 다.그러나 SystemProperties 류 는 native 방법 으로 하드웨어 정 보 를 얻 을 수 있 습 니 다.우 리 는 native 코드 를 작성 하여 하드웨어 인 자 를 얻 을 수 있 습 니 다.그러면 자바 Hook 에 의 해...
    public static String get(String key) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get(key);
    }
    

    네 이 티 브 소스 한번 볼 게 요.
    static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
                                          jstring keyJ, jstring defJ)
    {
        int len;
        const char* key;
        char buf[PROPERTY_VALUE_MAX];
        jstring rvJ = NULL;
    
        if (keyJ == NULL) {
            jniThrowNullPointerException(env, "key must not be null.");
            goto error;
        }
        key = env->GetStringUTFChars(keyJ, NULL);
        len = property_get(key, buf, "");
        if ((len <= 0) && (defJ != NULL)) {
            rvJ = defJ;
        } else if (len >= 0) {
            rvJ = env->NewStringUTF(buf);
        } else {
            rvJ = env->NewStringUTF("");
        }
    
        env->ReleaseStringUTFChars(keyJ, key);
    
    error:
        return rvJ;
    }
    

    이 부분의 소스 코드 를 참고 하여 스스로.so 라 이브 러 리 를 실현 하면 자바 층 Hook 을 피 할 수 있 습 니 다.
    Github 연결 CacheEmulatorChecker
    저자:책 을 읽 는 작은 달팽이 원문 링크 Android 장치 DeviceId 와 반 Xposed Hook 가 져 오기

    좋은 웹페이지 즐겨찾기