반응형
프로가드(Proguard) 설정하기
회사에서 보안점검으로 인하여 수정사항이 나왔다 그래서 수정진행하기전 몇 개의 게시글을 읽어보았다
proguard 경우는 외부 라이브러리를 사용할 때 어떤걸 사용하느냐에 따라서 하나씩 적용하고 확인해야하는것 같아 우선 해보는걸루!!
//rooting 검사
private fun isDeviceRooted(): Boolean {
val buildTags = Build.TAGS
if (buildTags != null && buildTags.contains("test-keys")) {
return true
}
val paths = arrayOf(
"/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su",
"/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
"/system/bin/failsafe/su", "/data/local/su"
)
for (path in paths) {
if (File(path).exists()) {
return true
}
}
return false
}
//frida detection
private fun isFridaServerRunning(): Boolean {
val activityManager = getSystemService(Activity.ACTIVITY_SERVICE) as ActivityManager
val runningAppProcess = activityManager.runningAppProcesses ?: return false
return runningAppProcess.any { processInfo ->
processInfo.processName.contains("frida-server", ignoreCase = true)
}
}
private fun checkFrida(): Boolean {
val pid = android.os.Process.myPid()
return try {
val mapsFileContents: String? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
File("/proc/$pid/maps").readText(Charset.defaultCharset())
} else {
null
}
mapsFileContents?.contains("frida") ?: false
} catch (e: IOException) {
e.printStackTrace()
false
}
}
//adb, shell
private fun isAdbShellRunning(): Boolean {
val activityManager = getSystemService(Activity.ACTIVITY_SERVICE) as ActivityManager
val runningAppProcess = activityManager.runningAppProcesses ?: return false
return runningAppProcess.any { processInfo ->
processInfo.processName.contains("shell", ignoreCase = true) ||
processInfo.processName.contains("adb", ignoreCase = true)
}
}
fun detectSuspiciousLibraries(): Boolean {
val libraries = System.getProperty("java.library.path")
return libraries?.contains("frida") == true ||
libraries.contains("xposed") ||
libraries.contains("substrate")
}
private fun isTracerPidPresent(): Boolean {
val statusFile = File("/proc/self/status")
if (statusFile.exists()) {
statusFile.useLines { lines ->
lines.forEach { line ->
if (line.startsWith("TracerPid")) {
val tracerPid = line.split(":")[1].trim().toInt()
return tracerPid != 0
}
}
}
}
return false
}
proguard
release {
minifyEnabled = true
shrinkResources = true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.release
}
}
debug {
minifyEnabled = true
shrinkResources = true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
proguard-rules.pro
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
-keep @interface com.google.android.gms.common.annotation.KeepName
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@com.google.android.gms.common.annotation.KeepName *;
}
-keep @interface com.google.android.gms.common.util.DynamiteApi
-dontwarn android.security.NetworkSecurityPolicy
#realm
-keep class io.realm.annotations.RealmModule
-keep @io.realm.annotations.RealmModule class *
-keep @interface io.realm.annotations.RealmModule { *; }
-keep class io.realm.annotations.RealmModule { *; }
-keep class io.realm.internal.Keep
-keep @io.realm.internal.Keep class * { *; }
-keep class io.realm.internal.KeepMember
-keep @io.realm.internal.KeepMember class * { @io.realm.internal.KeepMember *; }
-dontwarn javax.**
-dontwarn io.realm.**
-dontwarn io.reactivex.android.**
-keep class io.realm.RealmCollection
-keep class io.realm.OrderedRealmCollection
-keepclasseswithmembernames class io.realm.** {
native <methods>;
}
-dontnote rx.Observable
# Referenced from JNI
-keep class org.bson.types.Decimal128 {
public static org.bson.types.Decimal128 fromIEEE754BIDEncoding(...);
}
-keep class org.bson.types.ObjectId {
<init>(...);
}
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
##---------------End: proguard configuration for Gson ----------
### Glide, Glide Okttp Module, Glide Transformations
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
#========================================
## AWS
# Class names are needed in reflection
-keepnames class com.amazonaws.**
-keepnames class com.amazon.**
# Enums are not obfuscated correctly in combination with Gson
-keepclassmembers enum * { *; }
# Request handlers defined in request.handlers
-keep class com.amazonaws.services.**.*Handler
# The following are referenced but aren't required to run
-dontwarn com.fasterxml.jackson.**
# Android 6.0 release removes support for the Apache HTTP client
-dontwarn org.apache.http.**
# The SDK has several references of Apache HTTP client
-dontwarn com.amazonaws.http.**
-dontwarn com.amazonaws.metrics.**
# AGP 8 enables R8 full-mode optimization, which will remove constructors of classes that are only
# instantiated via reflection. These classes are instantiated via reflection in the SignerFactory.
-keep class com.amazonaws.auth.AWS4Signer { *; }
-keep class com.amazonaws.auth.QueryStringSigner { *; }
-keep class com.amazonaws.auth.NoOpSigner { *; }
#=========================================================
# Retrofit
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod
# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response
#===================================================
# Gson
-keep class com.google.gson.** { *; }
-dontwarn com.google.gson.**
# Gson에서 직렬화/역직렬화되는 데이터 모델 유지
-keep class your.package.name.model.** { *; }
#============================================
# RxBinding
-keep class com.jakewharton.rxbinding2.** { *; }
-dontwarn com.jakewharton.rxbinding2.**
# RxJava
-keep class io.reactivex.** { *; }
-dontwarn io.reactivex.**
# RxAndroid
-keep class io.reactivex.android.** { *; }
-dontwarn io.reactivex.android.**
# RxKotlin
-keep class io.reactivex.kotlin.** { *; }
-dontwarn io.reactivex.kotlin.**
#==============================
#google map
-keepnames class com.google.android.gms.** {*;}
#============================
# Firebase Authentication
-keepattributes *Annotation*
## Google Play Services 4.3.23 specific rules ##
## https://developer.android.com/google/play-services/setup.html#Proguard ##
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@com.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
#=======================
# Firebase Messaging
-keep class com.google.firebase.messaging.** { *; }
# BouncyCastle
-keep class org.bouncycastle.jsse.** { *; }
# Conscrypt
-keep class org.conscrypt.** { *; }
# OpenJSSE
-keep class org.openjsse.** { *; }
gradle.properties
# R8 (optimization)
# AGP 8.0version ??? = true(default) - 최적화되기 때문에 만약 true일 때 실행이 되지 않는다면 false로 변경
android.enableR8.fullMode=false
빌드할 때 빌드가 끝나고 app-build-outputs-mapping에서 missing_rules.txt를 보고 참조하면 빠르게 끝낼 수 있다
# Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin.
-dontwarn com.google.firebase.messaging.TopicOperation$TopicOperations
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
내 경우에는 이런 힌트를 받고 또한 빌드할 떄 로그로 남는걸 하나씩 적용하여 마무리지을 수 있었다
Missing class com.google.firebase.messaging.TopicOperation$TopicOperations (referenced from: void com.google.firebase.messaging.TopicOperation.<init>(java.lang.String, java.lang.String))
Missing class org.bouncycastle.jsse.BCSSLParameters (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 1 other context)
Missing class org.bouncycastle.jsse.BCSSLSocket (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 5 other contexts)
Missing class org.bouncycastle.jsse.provider.BouncyCastleJsseProvider (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.<init>())
Missing class org.conscrypt.Conscrypt$Version (referenced from: boolean okhttp3.internal.platform.ConscryptPlatform$Companion.atLeastVersion(int, int, int))
Missing class org.conscrypt.Conscrypt (referenced from: boolean okhttp3.internal.platform.ConscryptPlatform$Companion.atLeastVersion(int, int, int) and 4 other contexts)
Missing class org.conscrypt.ConscryptHostnameVerifier (referenced from: okhttp3.internal.platform.ConscryptPlatform$DisabledHostnameVerifier)
Missing class org.openjsse.javax.net.ssl.SSLParameters (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List))
Missing class org.openjsse.javax.net.ssl.SSLSocket (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 1 other context)
Missing class org.openjsse.net.ssl.OpenJSSE (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.<init>())
+추가적으로
테스트 환경에서 최적화를 비활성화해 경고의 근본적인 원인을 파악할 수도 있습니다. 예를 들어, 아래와 같이 -dontoptimize를 사용하여 최적화를 중단할 수 있답니다.
-dontoptimize
5.9MB 정도 작아진 어플을 볼 수 있다
반응형