ПРОСТОЙ МОДУЛЬ ДЛЯ ВЫКАЧИВАНИЯ ФАЙЛОВ С КОМПЬЮТЕРА ТЕХНИЧЕСКОЕ ЗАДАНИЕ Назначение программы - поиск и выкачивание данных с компьютера ОПИСАНИЕ И ОФОРМЛЕНИЕ Программа должна быть оформлена как .exe-файл, не принимающий параметров с командной строки. Программа собирает файлы программ (названия как указаны в реестре Windows): - 2018 Lacerte Tax - ProSeries 2018 - UltraTax CS 2018 - TaxWise 2018 on C Drive - ATX 2018 Программа ищет следующие файлы и папки по точному соответствию пути: - DRAKE18/DT - UT18DATA - 18tax/IData (уточнение - все папки, которые оканчиваются на Data) - 18Data - UTS18/database + UTS18/Users + UTS18/password.18 - TaxAct 2018 Professional Edition/Client Data Здесь важно совпадение иерархии - т.е. нужна не просто папка DT, а папка DT внутри папки DRAKE18. Поиск регистронезависимый. Число 18 в названиях папок - это номер года (2018) - его следует варьировать от 16 до 18. Стратегия поиска следующая: 1. Ищем на рабочем столе и в рабочих папках юзера (Documents, Downloads) ярлыки на следующие программы: - DRAKE18.EXE - DSTART.EXE - utw18.exe - w18tax.exe - protax18.exe - TWW17.exe - TaxAct18.exe - Sfs.ServerHost.exe - ATX.exe (17, 18 - номера годов, варьируем года от 16 до 18). Если ярлыков нет, скорее всего нужные данные на компьютере отсутствуют, т.к. не установлены соответствующие программы. Завершаем работу. 2. Начиная с диска C:, ищем на диске в папках первого уровня начало нужных нам иерархий, начиная со следующих папок: C:\ProWin18\18data C:\ProNet18\18data C:\Lacerte\18tax\******Data C:\WinCSI\UT18DATA C:\DRAKE18\DT C:\ProgramData\Wolters Kluwer\ATX 2018 Server C:\UTS18 C:\2018 Lacerte Tax C:\ProSeries 2018 C:\UltraTax CS 2018 C:\TaxWise 2017 Далее, обходим все папки первого уровня на текущем диске. Важно: мы не останавливаем поиск после нахождения первого результата. 3. Ищем на каждом диске, включая сетевые. 4. Полный рекурсивный поиск НЕ делаем! Поиск ограничен вторым уровнем каталогов - если на втором уровне нету признаков нужной иерархии, пропускаем папку. 5. Если при попытке открыть файл на чтение получаем ошибку File is busy или аналогичную (свидетельствующую о блокировке файла другим процессом), ищем в памяти процесс из пункта 1 и убиваем его. Если ошибка не устраняется, запоминаем путь к папке и продолжаем поиск. После завершения сканирования всех дисков, циклически обрабатываем все не-переданные папки, засыпая на таймаут в 10 минут после каждой неудачной попытки - и так до бесконечности. 6. Файлы отправляем по протоколу отправки файлов. 7. Читаем переменную окружения PROMPT. В этой переменной будет находиться не обычное для DOS/Windows приглашение командной строки, а данные идентификации программы. Парсим строку по разделителю , (запятая) на три части: - Client ID - Group ID - IP address Если строка не парсится (полей больше или меньше), или адрес не похож на адрес, принимаем значения этих полей за: Client ID: %MACHINE%-%USER%_W%winver%.%hex32% (генерируем по схеме, обозначенной ниже) Group ID: nop000 IP address: 0.0.0.0 Id клиента - это строка, состоящая из двух компонентов разделённых точкой. Первая часть имеет формат %MACHINE%-%USER%_XYYYYYYY, где MACHINE - имя компьютера USER - имя юзера X - символ обозначающий тип системы на которой работает клиент (W - windows, L - linux, A - андроид, M - Mac OS), YYYYYYY - 3-7 цифр содержащих major-version, minor-version и build операционной системы если таковые имеются у систем (например, длЯ 6.1 build 7600 это будет 617600). Вторая часть содержит 32 случайных символов 0-9, A-F. Пример id клиента - HOSTNAME-USER_W617600.11223344556677889900AABBCCDDEEFF. Параметр не чувствителен к регистру. 8. При передаче данных по сети (протокол HTTP), все HTTP-коды, не начинающиеся с 200, являются ошибкой. При проблеме передачи (код не-200 или отсутствие ответа) делаем десятикратный повтор попыток с таймаутом в час и умираем. 9. Адрес сервера зашивается в программе. Программа должна уметь работать как по HTTP, так и по HTTPS - для этого можно использовать функции WinInet/WinHTTP. 10. Программа должна удалить себя с диска после завершения. ОФОРМЛЕНИЕ МОДУЛЯ 1. Если выбран компилятор Microsoft, то должен иметься проект Microsoft Visual Studio версии не ниже 2015. 2. Проект Visual Studio должен быть настроен следующим образом: * Для ВСЕХ профилей сборки: - выходной каталог: $(SolutionDir)Bin\$(PlatformTarget)\$(Configuration)\ - Промежуточный каталог: $(SolutionDir)\obj\$(Platform)\$(Configuration)\$(ProjectName)\ - Многопроцессорная компиляция: да * Профиль Release: - Формат отладочной информации (С/С++ создание кода): нет - Создавать отладочную информацию (компоновщик/отладка): нет 3. Строки обфусцировать библиотекой Andrivet (приложена, см.макрос _STR()) 4. Системные вызовы обфусцировать библиотекой GetApi.h. Быть внимательным, обфускация сисвызовов может давать падения. 5. Модуль должен иметь две версии - x32- и x64-разрядную. 6. В боевой сборке должны быть обфусцированы по максимуму строки, отключен всяческий отладочный вывод. 7. Модуль должен иметь отладочную версию. Отладочный вывод должен выводиться в modulename.log (путь к логу настраивается в макросе). Каждая запись лога должна содержать временнУю метку с точностью до секунды. 8. В проекте должен быть файл настроек config.h (название неважно, важна суть - здесь все глобальные настройки - пути, макросы-переключатели условной компиляции итд). 9. Модуль должен работать на всех современных версиях Windows. Минимальная поддерживаемая версия Windows - Windows XP (если невозможно - Windows Vista). 10. Дополнительно к компоновке должен добавляться файл notelemetry.obj (https://stackoverflow.com/questions/37761768/how-to-prevent-visual-studio-2015-update-2-to-add-telemetry-main-invoke-trigger) ПРОТОКОЛ ПЕРЕДАЧИ ФАЙЛОВ 1) на сервер отправляется основная информация о компьютере через HTTP POST в контейнере multipart/form-data (аналогично обычной отправке html-формы). POST содержит следующие поля: timestamp - локальное UNIX-время ip - поле IP address ip1 - адрес первого сетевого интерфейса (в данной реализации поля с локальными адресами интерфейсов не используются; зарезервировано) ip2 - адрес второго сетевого интерфейса ... ipN - адрес N-го сетевого интерфейса cid - поле Client ID group - поле Group ID hostname - имя хоста, полученное через GetComputerName() source - строка `tax' Отправка происходит на url вида: http://foo.com/// junk - произвольные символы, допустимые в URI, кроме слеша / auth - авторизующая секция. Предполагается, что тот кто отправляет запрос, должен знать правила формирования этой секции. Это - рандом любой длины. В ней обязательны: - буква Z в любой позиции - сумма цифр (не чисел!) с 6 по 15-ю позицию должна быть 31. Символы между ними - рандом. В частности там может находиться и Z. Пример секции - abcde7ol7k9hi8mZ 2) далее отправляется каждый файл по частям, запросом HTTP POST, в контейнере multipart/form-data. Файл передается в поле file. Имя файла берется из тега Content-Disposition; имя временного файла из URI игнорируется. При этом: - отправка файла начинается с конца. К примеру, если файл длиной 100М, мы отправляем последние 10М файла. - после отправки куска файла и получения подтверждения, программа запоминает состояние, и отправляет следующий кусок. - перед отправкой, отправляемый кусок файла читается в память и сжимается алгоритмом gzip. - отправка производится на URL вида http://foo.com/////// где junk - произвольные символы, допустимые в URI, кроме слеша / auth - авторизующая секция. Это - рандом любой длины, в котором обязательны - буква S в любой позиции - сумма цифр (не чисел!) с 8 по 15-ю позицию должна быть 25. cid - поле Client ID filename - имя файла в кодировке URL Encoded start - начальное смещение передаваемого куска относительно начала файла; здесь допустимы и буквы, и цифры. Но значащими являются только цифры, в порядке появления в строке. Например, 0A -- это число 0 (цифра 0 значащая, буква A игнорируется). end - конечное смещение передаваемого куска относительно начала файла; правила те же, что и для start. Например, 3A5A2A3A9A5A9A - это 3523959. eof - признак конца файла. Если признак есть, это последний кусок файла; и наоборот (секция необязательная) Это рандом любой длины, в котором обязательны: - первая цифра чётная или 0 - последняя буква A или F При обработке ошибок, код HTTP-ответа 200 не говорит об успехе операции, но код не-200 говорит о неуспехе операции (например, 50* или 40* от прокси). Точный код операции содержится внутри XML в теле HTTP-ответа, внутри тега . При получении кода ответа вида 4041, добавочный символ 1 - это внутренний код ошибки сервера (включен только во время отладки). Например, следующий ответ свидетельствует об ошибке с кодом 9: HTTP/1.1 200 OK Server: nginx/1.10.3 (Ubuntu) Date: Mon, 07 Oct 2019 13:08:44 GMT Content-Type: application/xml; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept 4049 Следующий ответ - ошибки нету, все ок HTTP/1.1 200 OK Server: nginx/1.10.3 (Ubuntu) Date: Mon, 07 Oct 2019 13:08:44 GMT Content-Type: application/xml; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept 200