Ког­да задумы­ваешь­ся о защите при­ложе­ния от ревер­са, в пер­вую оче­редь на ум при­ходят такие сло­ва, как обфуска­ция и шиф­рование. Но это толь­ко часть решения проб­лемы. Вто­рая полови­на — это детект и защита от самих инс­тру­мен­тов ревер­са: отладчи­ков, эму­лято­ров, Frida и так далее. В этой статье мы рас­смот­рим тех­ники, которые мобиль­ный софт и злов­реды исполь­зуют, что­бы спря­тать­ся от этих инс­тру­мен­тов.

warning

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

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

 

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;
}
return false;
}

Ли­бо исполь­зовать такую фун­кцию, поза­имс­тво­ван­ную из при­ложе­ния 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. Это так называ­емый systemless-метод рутин­га, ког­да вмес­то раз­мещения ком­понен­тов для root-дос­тупа в фай­ловой сис­теме поверх нее под­клю­чают дру­гую фай­ловую сис­тему (овер­лей), содер­жащую эти ком­понен­ты.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


Подписаться
Уведомить о
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии