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

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

Так что все пароли, ключи шифрования и другую действительно важную информацию засовывать в код приложения уж точно не стоит. Нужно дать приложению доступ к какому-то веб-сервису? Используй его API для получения токена сервиса в момент подключения к нему. Приложение использует специальный скрытый API твоего сервиса? Сделай так, чтобы оно запрашивало его URL у самого сервиса и этот URL был уникальным для каждой копии приложения. Делаешь приложение для шифрования файлов? Запрашивай пароль шифрования у пользователя. В общем, любыми средствами сделай так, чтобы внутри приложения не было никакой информации, которая может привести к взлому твоих аккаунтов, твоего веб-сервиса или данных пользователя.

А если ты все-таки решил вшить важные данные в код приложения и не хочешь, чтобы их увидели, есть несколько рецептов, как это сделать, от простейших до действительно сложных.

 

Сохраняем строки в strings.xml

Это, наверное, простейший метод скрытия строк. Смысл метода в том, чтобы вместо размещения строки внутри константы в коде, что приведет к ее обнаружению после декомпиляции, разместить ее в файле res/values/strings.xml:

<resources>
    ...
    <string name="password">MyPassword</string>
    ...
</resources>

А из кода обращаться через getResources():

String password = getResources().getString(R.string.password);

Да, многие инструменты для реверса приложений позволяют просматривать содержимое strings.xml, поэтому имя строки (password) лучше изменить на что-то безобидное, а сам пароль сделать похожим на диагностическое сообщение (что-то вроде Error 8932777), да еще и использовать только часть этой строки, разделив ее с помощью метода split():

String[] string = getResources().getString(R.string.password).split(" ");
String password = strings[1];

Естественно, переменным тоже лучше дать безобидные имена, ну или просто включить ProGuard, который сократит их имена до одно-двухбуквенных сочетаний типа a, b, c, ab.

 

Разбиваем строки на части

Ты можешь не только использовать части строк, но и дробить их, чтобы затем собрать воедино. Допустим, ты хочешь скрыть в коде строку MyLittlePony. Совсем необязательно хранить ее в одной-единственной переменной, разбей ее на несколько строк и раскидай их по разным методам или даже классам:

String a = "MyLi";
String b = "ttle";
String c = "Pony";
...
String password = a + b + c;

Но здесь есть опасность столкнуться с оптимизацией компилятора, который соберет строку воедино для улучшения производительности. Поэтому директивы static и final к этим переменным лучше не применять.

 

Кодируем данные с помощью XOR

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

// Кодируем строку
public static String encode(String s, String key) {
    return Base64.encodeToString(xor(s.getBytes(), key.getBytes()), 0);
}

// Декодируем строку
public static String decode(String s, String key) {
    return new String(xor(Base64.decode(s, 0), key.getBytes()));
}

// Сама операция XOR
private static byte[] xor(byte[] a, byte[] key) {
    byte[] out = new byte[a.length];
    for (int i = 0; i < a.length; i++) {
        out[i] = (byte) (a[i] ^ key[i%key.length]);
    }
    return out;
}

Придумай вторую строку (ключ) и закодируй с ее помощью строки, которые ты хочешь скрыть (для примера пусть это будут строки password1 и password2, ключ 1234):

String encoded1 = StringXOR.encode("password1", "1234");
String encoded2 = StringXOR.encode("password2", "1234");
Log.e("DEBUG", "encoded1: " + encoded1);
Log.e("DEBUG", "encoded2: " + encoded2);

Открыв Android Monitor в Android Studio, ты найдешь строки вида:

encoded1: RVRCRQ==
encoded2: ACHBDS==

Это и есть закодированные с помощью XOR оригинальные строки. Добавь их в код вместо оригинальных, а при доступе к строкам используй функцию декодирования:

String password1 = StringXOR.decode(encodedPassword1, "1234");

Благодаря этому методу строки не будут открыто лежать в коде приложения, однако раскодировать их тоже будет совсем нетрудно, так что всецело полагаться на этот метод не стоит. Да и ключ тоже придется как-то прятать.

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

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи одну статью

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


1 комментарий

Подпишитесь на ][, чтобы участвовать в обсуждении

Обсуждение этой статьи доступно только нашим подписчикам. Вы можете войти в свой аккаунт или зарегистрироваться и оплатить подписку, чтобы свободно участвовать в обсуждении.

Check Also

Конкурс хаков: пишем на PowerShell скрипт, который уведомляет о днях рождения пользователей Active Directory

В компаниях часто встречается задача уведомлять сотрудников о приближающихся днях рождения…