Привет, гость!

Добро пожаловать на CVVBOARD - крупнейший теневой кардинг форум. У нас Вы сможете найти огромное множество статей по теме кардинга и заработка в интернете. Актуальная информация, новости даркнета, сервисы от проверенных продавцов, эксклюзивные, только рабочие схемы заработка, ежедневные раздачи - все это Вы найдете на нашем форуме! Не пренебрегайте услугами Гарант-Сервиса это убережет Вас от мошенников. Обратите внимание, звание модератора не является гарантом в сделках!

Защита андроид приложений

Download_Link

Участник клуба
Регистрация
7 Июл 2020
Сообщения
404
Реакции
58
Депозит
200$
Когда вы думаете о защите приложения от обратной инженерии, в первую очередь приходят на ум такие слова, как обфускация и шифрование. Но это только часть решения проблемы. Вторая половина — это обнаружение и защита от самих обратных инструментов: отладчиков, эмуляторов, Frida и т. Д. В этой статье мы рассмотрим методы, используемые мобильным программным обеспечением и вредоносными программами, чтобы скрыться от этих инструментов.


Не воспринимайте информацию, изложенную в статье, как рецепт абсолютной защиты. Такого рецепта нет. Мы просто даем себе передышку, замедляем исследования, но не делаем это невозможным. Все это бесконечная игра в кошки-мышки, в которой исследователь ломает очередную защиту, а разработчик придумывает ей более изощренную замену.

Важный момент: я дам вам несколько различных методов защиты, и у вас может возникнуть соблазн сгруппировать их в класс (или собственную библиотеку) и, что удобно для вас, запустить их один раз в начале приложения. Не стоит этого делать, механизмы защиты должны быть распределены по всему приложению и запускаться в разное время. Это значительно усложняет жизнь злоумышленнику, который может определить назначение класса / библиотеки и полностью заменить его большим контуром.

Root
Права root — один из основных инструментов отмены. Root позволяет запускать Frida без исправления приложения, использовать модули Xposed для изменения поведения приложения и отслеживания приложений, а также изменять параметры системы низкого уровня. В общем, наличие root явно указывает на то, что среде выполнения нельзя доверять. Но как его найти?
Са­мый прос­той вари­ант — поис­кать исполня­емый файл su в одном из сис­темных катало­гов:

/sbin/su
/system/bin/su/system/bin/failsafe/su/system/xbin/su/system/sd/xbin/su/data/local/su/data/local/xbin/su/data/local/bin/su
Би­нар­ник su всег­да при­сутс­тву­ет на рутован­ном устрой­стве, ведь имен­но с его помощью при­ложе­ния получа­ют пра­ва root. Най­ти его мож­но с помощью при­митив­ного кода на Java:

private static boolean findSu() {
String[] paths = { "/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 (String path : paths) {
if (new File(path).exists()) return true;
Ли­бо исполь­зовать такую фун­кцию, поза­имс­тво­ван­ную из при­ложе­ния rootinspector:
jboolean Java_com_example_statfile(JNIEnv * env, jobject this, jstring filepath) {
jboolean fileExists = 0;
jboolean isCopy;
const char * path = (*env)->GetStringUTFChars(env, filepath, &isCopy);
struct stat fileattrib;

if (stat(path, &fileattrib) < 0) {
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NATIVE: stat error: [%s]", strerror(errno));
} else
{
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NATIVE: stat success, access perms: [%d]", fileattrib.st_mode);
return 1;
}

return 0;
}
Еще один вари­ант — поп­робовать не прос­то най­ти, а запус­тить бинар­ник su:
try {
Runtime.getRuntime().exec("su");
} catch (IOException e) {
// Телефон не рутован
}
Ес­ли его нет, сис­тема выдаст IOException. Но здесь нуж­но быть осто­рож­ным: если устрой­ство все‑таки име­ет пра­ва root, поль­зователь уви­дит на экра­не зап­рос этих самых прав.
Еще один вари­ант — най­ти сре­ди уста­нов­ленных на устрой­ство при­ложе­ний менед­жер прав root. Он как раз и отве­чает за диалог пре­дос­тавле­ния прав:
  • com.thirdparty.superuser
  • eu.chainfire.supersu
  • com.noshufou.android.su
  • com.koushikdutta.superuser
  • com.zachspong.temprootremovejb
  • com.ramdroid.appquarantine
  • com.topjohnwu.magisk
Для поис­ка мож­но исполь­зовать такой метод:

private static boolean isPackageInstalled(String packagename, Context context) {
PackageManager pm = context.getPackageManager();
try {
pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
return true;
} catch (NameNotFoundException e) {
return false;
}
}
Ис­кать мож­но и по кос­венным приз­накам. Нап­ример, SuperSU, неког­да популяр­ное решение для получе­ния прав root, име­ет нес­коль­ко фай­лов в фай­ловой сис­теме:
  • /system/etc/init.d/99SuperSUDaemon
  • /system/xbin/daemonsu — SuperSU
Еще один кос­венный приз­нак — про­шив­ка, под­писан­ная тес­товыми клю­чами. Это не всег­да под­твержда­ет наличие root, но точ­но говорит о том, что на устрой­стве уста­нов­лен кас­том:

private boolean isTestKeyBuild() {
String buildTags = android.os.Build.TAGS;
return buildTags != null && buildTags.contains("test-keys");
}

Magisk
Все эти методы обнаружения корневого доступа работают нормально, пока вы не встретите устройство с root-правами на Magisk. Это так называемый бессистемный метод рутирования, когда вместо размещения компонентов для корневого доступа в файловой системе поверх нее монтируется другая файловая система (оверлей), содержащая эти компоненты.
Этот рабочий механизм не только позволяет не трогать системный раздел, но и легко скрывает наличие рут-прав в системе. Встроенная функция Magisk в MagiskHide просто отключает оверлей для выбранных приложений, делая бесполезным любой классический метод обнаружения корневого каталога.


Про­цесс скры­тия root мож­но уви­деть в логах Magisk
Но в MagiskHide есть недостаток. Дело в том, что если приложение, которое находится в списке для скрытия корневого каталога, запускает службу в изолированном процессе, Magisk также отключит для него оверлей, но этот оверлей останется в списке подключенных файловых систем (/ proc / self / mounts). Следовательно, чтобы обнаружить Magisk, вам необходимо запустить службу в изолированном процессе и проверить список подключенных файловых систем.
Спо­соб был опи­сан в статье Detecting Magisk Hide, а исходный код proof of concept выложен на GitHub. Спо­соб работа­ет до сих пор на самой пос­ледней вер­сии Magisk — 20.4

Эмулятор
Ре­вер­серы час­то исполь­зуют эму­лятор для запус­ка подопыт­ного при­ложе­ния. Поэто­му нелиш­ним будет внес­ти в при­ложе­ние код, про­веря­ющий, не запуще­но ли оно в вир­туаль­ной сре­де. Сде­лать это мож­но, про­читав зна­чение некото­рых сис­темных перемен­ных. Нап­ример, стан­дар­тный эму­лятор Android Studio уста­нав­лива­ет такие перемен­ные и их зна­чения:

ro.hardware=goldfish
ro.kernel.qemu=1
ro.product.model=sdk
Про­читав их зна­чения, мож­но пред­положить, что код исполня­ется в эму­лято­ре:
public static boolean checkEmulator() {
try {
boolean goldfish = getSystemProperty("ro.hardware").contains("goldfish");
boolean emu = getSystemProperty("ro.kernel.qemu").length() > 0;
boolean sdk = getSystemProperty("ro.product.model").contains("sdk");

if (emu || goldfish || sdk) {
return true;
}
} catch (Exception e) {}

return false;
}

private static String getSystemProperty(String name) throws Exception {
Class sysProp = Class.forName("android.os.SystemProperties");
return (String) sysProp.getMethod("get", new Class[]{String.class}).invoke(sysProp, new Object[]{name});
}
Об­рати вни­мание, что класс android.os.SystemProperties скры­тый и недос­тупен в SDK, поэто­му для обра­щения к нему мы исполь­зуем реф­лексию.
В других эмуляторах значения системных переменных могут быть другими. Эта страница содержит таблицу со значениями системных переменных, которые могут прямо или косвенно указывать на эмулятор. Также имеется таблица значений стека телефонии. Например, серийный номер сим-карты 89014103211118510720 однозначно указывает на эмулятор. В этом ис­ходном фай­ле можно найти множество стандартных значений, а также готовые функции для обнаружения эмулятора.

Отладчик
Один из обратных методов — запустить приложение под управлением отладчика. Злоумышленник может декомпилировать ваше приложение, а затем создать проект с тем же именем в Android Studio, вставить полученные из него источники и начать отладку без компиляции проекта. В этом случае приложение само покажет вам свою логику работы.
Что­бы про­вер­нуть такой финт, взлом­щику при­дет­ся пересоб­рать при­ложе­ние с вклю­чен­ным фла­гом отладки (android:debuggable=»true»). Поэто­му наив­ный спо­соб защиты сос­тоит в прос­той про­вер­ке это­го фла­га:

public static boolean checkDebuggable(Context context){
return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;

}
Чуть более надеж­ный спо­соб — нап­рямую спро­сить сис­тему, под­клю­чен ли отладчик:
public static boolean detectDebugger() {
return Debug.isDebuggerConnected();
}
То же самое в натив­ном коде:
JNIEXPORT jboolean JNICALL Java_com_test_debugging_DebuggerConnectedJNI(JNIenv * env, jobject obj) {
if (gDvm.debuggerConnected || gDvm.debuggerActive) {
return JNI_TRUE;
}
return JNI_FALSE;
}
При­веден­ные методы помогут обна­ружить отладчик на базе про­токо­ла JDWP (как раз тот, что встро­ен в Android Studio). Но дру­гие отладчи­ки работа­ют по‑дру­гому, и методы борь­бы с ними будут ины­ми. Отладчик GDB, нап­ример, получа­ет кон­троль над про­цес­сом с помощью сис­темно­го вызова ptrace(). А пос­ле исполь­зования ptrace флаг TracerPid в син­тетичес­ком фай­ле /proc/self/status изме­нит­ся с нуля на PID отладчи­ка. Про­читав зна­чение фла­га, мы узна­ем, под­клю­чен ли к при­ложе­нию отладчик GDB:

public static boolean hasTracerPid() throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/status")), 1000);
String line;

while ((line = reader.readLine()) != null) {
if (line.length() > tracerpid.length()) {
if (line.substring(0, tracerpid.length()).equalsIgnoreCase(tracerpid)) {
if (Integer.decode(line.substring(tracerpid.length() + 1).trim()) > 0) {
return true;
}
break;
}
}
}

} catch (Exception exception) {
e.printStackTrace()
} finally {
reader.close();
}

return false;
}
Это слег­ка модифи­циро­ван­ная фун­кция из репози­тория anti-emulator. Ее ана­лог на язы­ке С будет нет­рудно най­ти на Stack Overflow.
Другой метод работы с отладчиками на основе ptrace — попытаться подключиться к себе (процессу приложения) в качестве отладчика. Для этого вам нужно выполнить форк (из нативного кода), а затем попытаться вызвать системный вызов ptrace:


Есть и другие способы найти встроенный отладчик IDA Pro: найдите в файле / proc / net / tcp строку 00000000: 23946 (это порт отладчика по умолчанию). К сожалению, этот метод больше не работает с Android 9.
В более старых версиях Android также можно было напрямую искать процесс отладчика в системе, где приложение просто просматривает дерево процессов в файловой системе / proc и ищет такие строки, как gdb и gdbserver, в файлах / proc / PID / cmdline. Начиная с Android 7, доступ к файловой системе / proc запрещен (кроме информации о текущем процессе).

Xposed
Xposed — это фреймворк для изменения времени работы приложений. И хотя он в основном используется для установки системных изменений и настроек приложений, существует множество модулей, которые вы можете использовать для отмены и взлома вашего приложения. Это различные модули для отключения закрепления SSL, трассировщики, такие как Inspection, и самописные модули, которые могут каким-либо образом изменять приложение.
Есть три дей­ствен­ных спо­соба обна­руже­ния Xposed:
  • по­иск пакета de.robv.android.xposed.installer сре­ди уста­нов­ленных на устрой­ство;
  • по­иск libexposed_art.so и xposedbridge.jar в фай­ле /proc/self/maps;
  • по­иск клас­са de.robv.android.xposed.XposedBridge сре­ди заг­ружен­ных в ран­тайм пакетов.
В статье Android Anti-Hooking Techniques in Java при­водит­ся реали­зация треть­его метода одновре­мен­но для поис­ка Xposed и Cydia Substrate. Под­ход инте­ресен тем, что мы не ищем нап­рямую клас­сы в ран­тай­ме, а прос­то вызыва­ем исклю­чение вре­мени исполне­ния и затем ищем нуж­ные клас­сы и методы в стек­трей­се:

try {
throw new Exception("blah");
}
catch(Exception e) {
int zygoteInitCallCount = 0;

for(StackTraceElement stackTraceElement : e.getStackTrace()) {
if(stackTraceElement.getClassName().equals("com.android.internal.os.ZygoteInit")) {
zygoteInitCallCount++;
if(zygoteInitCallCount == 2) {
Log.wtf("HookDetection", "Substrate is active on the device.");
}
}

Код:
if (stackTraceElement.getClassName().equals("com.saurik.substrate.MS$2") && stackTraceElement.getMethodName().equals("invoked")) {
Log.wtf("HookDetection", "A method on the stack trace has been hooked using Substrate.");
}

if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals("main")) {
Log.wtf("HookDetection", "Xposed is active on the device.");
}

if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals("handleHookedMethod")) {
Log.wtf("HookDetection", "A method on the stack trace has been hooked using Xposed.");
}
}
}
Выводы
Конечно, это далеко не все способы обратной инженерии и анализа поведения приложений. Есть много менее эффективных или узкоспециализированных методов. Поэтому ниже я приведу список литературы и проектов на GitHub, который вам обязательно стоит прочитать. Там вы найдете более подробное объяснение некоторых методов защиты, описанных в этой статье, а также многих других методов.
 

NyaMan

Участник клуба
Регистрация
24 Май 2018
Сообщения
410
Реакции
1
Только вчера была тема как легко их взламывать :D
 
Сверху Снизу