Analysis
LD player, Nox와 같은 애뮬레이터에서 앱을 실행 중인지 확인하는 기능이다.
애플리케이션을 실행하는 환경이 애뮬레이터인지 아닌지에 따라 출력되는 메시지가 다르다.
Code
EmulatorDetectionActivity$onCreate$1
final class EmulatorDetectionActivity$onCreate$1 implements View.OnClickListener {
final /* synthetic */ EmulatorDetectionActivity this$0;
EmulatorDetectionActivity$onCreate$1(EmulatorDetectionActivity emulatorDetectionActivity) {
this.this$0 = emulatorDetectionActivity;
}
public final void onClick(View it) {
if (this.this$0.isEmulator()) {
Toast.makeText(this.this$0.getApplicationContext(), "This is Emulator", 1).show();
} else {
Toast.makeText(this.this$0.getApplicationContext(), "This is not Emulator", 1).show();
}
}
}
버튼을 눌렀을 때 호출되는 함수로 isEmulator() 함수 결괏값에 따라 애뮬레이터인지 판단하여 "This is Emulator" 혹은 "This is not Emulator" 문자열을 출력한다.
isEmulator
public final boolean isEmulator() {
String str = Build.FINGERPRINT + Build.DEVICE + Build.MODEL + Build.BRAND + Build.PRODUCT + Build.MANUFACTURER + Build.HARDWARE;
if (str != null) {
String builddtls = str.toLowerCase();
Intrinsics.checkExpressionValueIsNotNull(builddtls, "(this as java.lang.String).toLowerCase()");
if (StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "generic", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) EnvironmentCompat.MEDIA_UNKNOWN, false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "emulator", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "sdk", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "vbox", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "genymotion", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "x86", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "goldfish", false, 2, (Object) null) || StringsKt.contains$default((CharSequence) builddtls, (CharSequence) "test-keys", false, 2, (Object) null)) {
return true;
}
return false;
}
throw new TypeCastException("null cannot be cast to non-null type java.lang.String");
}
isEmulator() 함수에서는 Fingerprint, Device, Model 등과 같은 기기 고유 값을 이용하여 애뮬레이터인지 아닌지 판단한다. 만약 애뮬레이터가 맞다면 true를 반환하고 아니라면 false를 반환한다.
여기서 Fingerprint, Device, Model이 각각 어떤 의미인지 확인할 수 있다.
Exploit
smali
애뮬레이터 우회를 위한 첫 번째는 smali 코드 변조다. (이전 Root Detection과 거의 동일하다)
먼저 변조할 코드를 찾기 위해 APK Easy Tool을 이용하여 디컴파일을 진행한다.
이후 smali → owasp → sat → goat 경로를 따라가면 EmulatorDetectionActivity.smali 코드를 확인할 수 있다.
isEmulator() 함수 마지막 부분을 확인해보면 다음과 같은 부분을 확인할 수 있다.
이전 코드 중 애뮬레이터가 맞다면 cond_0으로 이동하여 v3 값을 0x1로 설정해준 후 이를 반환해주는 것을 확인할 수 있다.
그렇다면 우회는 간단하게 그냥 v3로 넣어주는 값을 0x1에서 0x0으로 변경해주면 끝이다.
이후 컴파일 및 설치를 진행한 다음 확인해보면 다음과 같이 "This is not Emulator" 메시지가 출력되는 것을 확인할 수 있다.
Frida
두 번째는 frida를 이용한 우회이다.
frida를 이용한 우회도 이전 Root Detection과 거의 유사하다.
코드는 다음과 같이 isEmulator() 함수를 후킹한 후 반환 값을 false로 주면 우회할 수 있다.
console.log("Script loaded successfully");
Java.perform(function x() {
console.log("java perform function");
var my_class = Java.use("owasp.sat.agoat.EmulatorDetectionActivity");
my_class.isEmulator.implementation = function (args) {
console.log("\n----0----");
return false;
};
});
스크립트 실행 후 CHECK EMULATOR 버튼을 눌러주면 다음과 같은 로그와 이전 smali변조와 같이 "This is not Emulator"라는 메시지를 애플리케이션에서 확인할 수 있다.
Reference
'Android > Androgoat' 카테고리의 다른 글
Network Intercepting (0) | 2021.09.20 |
---|---|
Binary Patching (0) | 2021.09.20 |
Root Detection (0) | 2021.09.20 |