- Регистрация
- 08.03.2017
- Сообщения
- 1 278
- Благодарностей
- 623
- Баллы
- 113
И снова здравствуйте, молодые (и не очень) люди! В этой статьей я хотел бы познакомить вас со своим решением для работы с трафиком напрямую из Android! Название сему, с Вашего позволения, великолепию, было принято решение дать SystemCallAndroidMonitoring. И уже после нейминга проекта я понял, что наделал - аббревиатуре представляет из себя ничто иное как SCAM.
Но я решил его таковым и оставить.
А почему нет?
Дисклеймер: Я не позиционирую себя как профессионального разработчика. Я не проходил профильного обучения в учебных заведениях, а знакомился с языком программирования по мере вовлеченности в автоматизацию различных действий. Решение поставляется по системе “as is”, то есть – как есть. В случае возникновения проблем, трудностей, вопросов, я всё-таки оставлю за собой право не решать их и не отвечать на них. Однако, это не значит, что я полностью пущу все на самотек и закрою глаза на вопросы пользователей. Я буду все решать по мере возможностей и доступного времени. Надеюсь на ваше понимание.
Теперь к тому, что мы имеем. А имеем мы 2 вещи:
1. ASP.NET приложение, которое выступает в качестве API. Его вы можете увидеть на скриншоте выше. С помощью него мы поднимаем инстансы Titanium.Web.Proxy, выполняем добавление данных подмены, получаем и чистим список трафика.
2. Библиотека для работы напрямую из ZennoDroid.
Исходники всего будут прикреплены ниже, как и готовые билды для работы.
Использование
1. Добавляем ссылку на библотеку
А также, добавляем в общий код метод, который пригодится при установке сертификата
В общем коде на вкладке "Директивы using" прописываем
2. Подключаем рабочий телефон по WiFi к той же сети, к которой подключен и компьютер, на котором развернут ScamAPI
3. Запускаем ScamAPI
4. Выполняем код для создания нового инстанса Titanium.Web.Proxy (далее: TWP)
И разбиваем на нужные переменные через split
5. Устанавливаем сертификат
6. Запускаем браузер с примененными скриптами Frida
7. Применяем нужные нам методы
Но я решил его таковым и оставить.
А почему нет?
Дисклеймер: Я не позиционирую себя как профессионального разработчика. Я не проходил профильного обучения в учебных заведениях, а знакомился с языком программирования по мере вовлеченности в автоматизацию различных действий. Решение поставляется по системе “as is”, то есть – как есть. В случае возникновения проблем, трудностей, вопросов, я всё-таки оставлю за собой право не решать их и не отвечать на них. Однако, это не значит, что я полностью пущу все на самотек и закрою глаза на вопросы пользователей. Я буду все решать по мере возможностей и доступного времени. Надеюсь на ваше понимание.
Теперь к тому, что мы имеем. А имеем мы 2 вещи:
1. ASP.NET приложение, которое выступает в качестве API. Его вы можете увидеть на скриншоте выше. С помощью него мы поднимаем инстансы Titanium.Web.Proxy, выполняем добавление данных подмены, получаем и чистим список трафика.
2. Библиотека для работы напрямую из ZennoDroid.
Исходники всего будут прикреплены ниже, как и готовые билды для работы.
Использование
1. Добавляем ссылку на библотеку
А также, добавляем в общий код метод, который пригодится при установке сертификата
Общий код целиком:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Text.RegularExpressions;
using ZennoLab.CommandCenter;
using ZennoLab.InterfacesLibrary;
using ZennoLab.InterfacesLibrary.ProjectModel;
using ZennoLab.InterfacesLibrary.ProjectModel.Collections;
using ZennoLab.InterfacesLibrary.ProjectModel.Enums;
using ZennoLab.Macros;
using Global.ZennoExtensions;
using ZennoLab.Emulation;
using ZennoLab.CommandCenter.TouchEvents;
using ZennoLab.CommandCenter.FullEmulation;
using ZennoLab.InterfacesLibrary.Enums;
using ZennoLab.InterfacesLibrary.ZennoDroid;
using ZennoLab.InterfacesLibrary.ZennoDroid.Enums;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
namespace ZennoLab.OwnCode
{
/// <summary>
/// A simple class of the common code
/// </summary>
public class CommonCode
{
/// <summary>
/// Lock this object to mark part of code for single thread execution
/// </summary>
public static object SyncObject = new object();
public static string GenerateCertificateHash(string certPath)
{
using (var cert = new X509Certificate2(certPath))
{
using (var sha1 = System.Security.Cryptography.SHA1.Create())
{
byte[] certHash = sha1.ComputeHash(cert.RawData);
return BitConverter.ToString(certHash)
.Replace("-", "")
.ToLowerInvariant();
}
}
}
// Insert your code here
}
}
В общем коде на вкладке "Директивы using" прописываем
Директивы using:
using ScamClient;
3. Запускаем ScamAPI
Код для создания инстанса TWP:
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
var newInstanceData = client.NewInstance(project.Variables["proxy"].Value, 3000);
project.Variables["scam_endPoint"].Value = newInstanceData.InstanceData.ProxyEndpoint;
project.Variables["scam_certPEM"].Value = newInstanceData.InstanceData.CertificatePemData;
project.Variables["scam_certPath"].Value = newInstanceData.InstanceData.CertificatePath;
И разбиваем на нужные переменные через split
5. Устанавливаем сертификат
Установка сертификата:
IDroidInputAPI input = instance.DroidInstance.Input;
try
{
// Проверка root-доступа
input.Shell("su -c 'touch /data/_zd_test'");
}
catch (Exception ex)
{
throw new Exception("Нет root-доступа", ex);
}
// Проверка root-доступа
if (!"ok".Equals(input.Shell("su -c 'test -f /data/_zd_test && echo ok && rm -f /data/_zd_test || echo false'")))
throw new Exception("Нет root-доступа");
// Путь к сертификату
string str = project.Variables["scam_certPath"].Value;
// Генерация хеша сертификата
string certHash = CommonCode.GenerateCertificateHash(str);
// Отправка сертификата на устройство
if (!input.Shell($"adb push \"{str}\" /data/local/tmp/proxy-cert.crt").Contains("1 file pushed"))
throw new Exception("Не удалось отправить сертификат");
try
{
// Создание пользовательской папки для сертификатов, если не существует
input.Shell("su -c 'mkdir -p /data/misc/user/0/cacerts-added'");
input.Shell("su -c 'chmod 755 /data/misc/user/0/cacerts-added'");
// Копирование сертификата в пользовательскую папку
input.Shell($"su -c 'cp /data/local/tmp/proxy-cert.crt /data/misc/user/0/cacerts-added/{certHash}.0'");
// Установка корректных прав доступа
input.Shell($"su -c 'chmod 644 /data/misc/user/0/cacerts-added/{certHash}.0'");
input.Shell($"su -c 'chown system:system /data/misc/user/0/cacerts-added/{certHash}.0'");
// Альтернативный путь для некоторых устройств
input.Shell("su -c 'mkdir -p /data/misc/certificates'");
input.Shell($"su -c 'cp /data/local/tmp/proxy-cert.crt /data/misc/certificates/{certHash}.0'");
input.Shell($"su -c 'chmod 644 /data/misc/certificates/{certHash}.0'");
input.Shell($"su -c 'chown system:system /data/misc/certificates/{certHash}.0'");
// Дополнительные проверки
if (!"ok".Equals(input.Shell($"su -c 'test -f /data/misc/user/0/cacerts-added/{certHash}.0 && echo ok || echo false'")))
throw new Exception("Не удалось скопировать сертификат в пользовательскую папку");
// Перезагрузка менеджера сертификатов (может потребоваться перезагрузка устройства)
input.Shell("su -c 'am broadcast -a android.intent.action.CERTIFICATE_CHANGED'");
project.SendInfoToLog("Сертификат успешно установлен в пользовательскую папку");
}
catch (Exception ex)
{
project.SendInfoToLog($"Ошибка установки сертификата: {ex.Message}");
throw;
}
7. Применяем нужные нам методы
[AddDomainForChange] Подмена URL (2ip.ru -> ipify.org):
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
client.AddDomainForChange(new DomainsForReplace(@"https://2ip.ru", @"2ip.ru", "ipify.org"));
Подмена фрагмента URL (Ручной_труд -> Автоматизация):
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
// @"/wiki/Ручной_труд" - regex для поиска изначального URL
// @"Ручной_труд" - regex для замены
// "Автоматизация" - текст, НА который заменяем вхождение по regex для замены
client.AddDomainForChange(new DomainsForReplace(@"/wiki/Ручной_труд", @"Ручной_труд", "Автоматизация"));
[GetInstances] Запрос перечня активных инстансов и вывод их эндпоинтов в лог:
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
var instances = client.GetInstances();
foreach (var titaniumInstance in instances)
{
project.SendInfoToLog($"Активный инстанс: {titaniumInstance.EndPoint}");
}
[AddChangeResponse] Подменяем картинки на википедии на иконку ZennoLab:
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
client.AddChangeResponse(new ChangeBody(@"wikipedia\.org/wiki/",
new string[] {
@"/wiki/[^/]+:[^/]+\.(jpg|jpeg|png|PNG)",
@"//upload\.wikimedia\.org/[^""'\s]+\.(jpg|jpeg|png|PNG)"
},
new string[] {
@"https://zenno.club/discussion/data/avatars/m/31/31536.jpg?1548149173",
@"https://zenno.club/discussion/data/avatars/m/31/31536.jpg?1548149173"
})
);
[AddChangeRequest] Подменяем тело запроса. Заставляем FunCaptcha загрузиться на русском языке:
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
client.AddChangeRequest(new ChangeBody(@"/fc/gfct/",
new string[] {
@"lang=[a-z]{0,2}"
},
new string[] {
@"lang=ru"
})
);
[GetTraffic] Получаем весь собранный трафик в качестве JSON массива:
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
var traf = client.GetTraffic().TrafficRecords;
return Global.ZennoLab.Json.JsonConvert.SerializeObject(traf);
[GetTraffic] Получаем картинку-задание FunCaptcha в base64 в переменную:
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
var traf = client.GetTraffic().TrafficRecords;
foreach (var t in traf)
{
if (t.RequestUrl.Contains("image?challenge"))
{
// В этой переменной будет тело картинки в base64
project.Variables["response_base64"].Value = t.ResponseBodyBase64;
// В этой переменной будет текстовое представление ответа
project.Variables["response_raw"].Value = t.ResponseBodyRaw;
return "ok";
}
}
[GetTraffic] Получение текстового значения ответа. В данном случае JSON, хранящий в себе задание FunCaptcha:
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
var traf = client.GetTraffic().TrafficRecords;
foreach (var t in traf)
{
if (t.RequestUrl.Contains("gfct"))
{
// Массив байт ответа в base64 (не интересует в данном варианте)
project.Variables["response_base64"].Value = t.ResponseBodyBase64;
// Текстовое представление ответа
project.Variables["response_raw"].Value = t.ResponseBodyRaw;
return "ok";
}
}
Очистка массива трафика:
// Объявляем клиент
var client = new ScamClient.ScamClient(project, "http://localhost:65002/");
// Объявляем в рамках клиента инстанс для работы
client.AttachTitaniumInstance(project.Variables["scam_endPoint"].Value);
client.ClearTraffic();
Последнее редактирование: