ДЖОЙНЕР МОЕЙ МЕЧТЫ :)
=====================
Доброе время суток, дорогой читатель. Буду краток. Я написал мега крутой джойнер и решил выложить его на паблик. На
первый взгляд довольно глупое решение. Ты знаешь почему. Дай мне шанс оправдаться.
Я полагаю, что после прочтения этой статьи любой более-менее умный человек сможет без особого труда изготовить себе
сам свой единственный и неповторимый, заточенный только под его нужды, джойнер. Представь себе - тысячи вариаций моего
джойнера, и ни одна из них не палится. Если когда-нибудь кто-нибудь спросит как склеить 2 файла - смело говори ему где
достать этот текст. Я хочу решить эту проблему раз и навсегда.
В этой статье я покажу, как написать джойнер, обладающий, по меньшей мере следующими способностями:
- Склеивание любого количества файлов тремя различными способами
- Шифрование их опять же тремя способами
- Упаковка двумя методами
- Запуск двумя методами
- Украшение лоадера любой иконкой
Склеивать мы будем таким образом: просто в зависимости от установленных нами опций будет компилироваться тот или
иной лоадер. Для компиляции будем использовать MASM. Так как лоадеры между собой очень похожи, писать придется не
много. Благо была придумана условная компиляция.
Джойнер будет состоять из билдера и исходников лоадера. Билдер не представляет для нас особого интереса, при желании
ты сможешь изучить его исходники самостоятельно. Скажу только, что написан он на Дельфи с использованием KOL. Функция
его заключается в приготовлении необходимых файлов (.rc + некоторые инклуды) и компиляции загрузчика.
Исходники лоадера лежат в директории Stub вместе с билдером. Ключевым является файл Stub.asm. Остальные инклудятся в
него в зависимости от параметров, заданных при компиляции.
Устроен лоадер таким образом:
1) Сначала определяются функции упаковки, шифрования и извлечения файлов. Или не определяются, если мы их не
используем. О них позже.
2) Определяется директория, в которую будут извлекаться склеенные файлы.Делается это уже при запуске лоадера жертвой
с помощью функции GetEnvironmentVariable, GetWindowsDirectory, GetSystemDirectory или GetTempPath. Эти функции
лежат в одноименных inc-файлах. Все они помещают в переменную tempdir
tempdir db MAX_PATH dup (?)
путь до места, куда будут извлекаться все файлы. Например, файл GetWindowsDirectory.inc содержит всего лишь одну
строчку
invoke GetWindowsDirectory, offset tempdir, sizeof tempdir
Это была самая простая часть.
3) Извлечение файлов и их запуск.
ИЗВЛЕЧЕНИЕ
----------
Как я и сказал, склеиваться файлы будут тремя способами. Соответственно извлекаться они будут тоже тремя способами.
Первый и самый распространенный - дописывание файлов в конец лоадера.
Возьми любой экзешник и допиши в его конце какую-нибудь чушь (напомню на всякий случай, что блокнот для этого не
подходит =))) - он будет работать как раньше. В конце экзешника мы запишем файлы, которые следует склеить, а извлекать
их будем с помощью обычного ReadFile().
Вот содержимое файла file.inc
;---------------------------------------------------------------------------------------------------------------------
00 .data?
01 selfname db MAX_PATH dup (?)
02
03
04 .code
05
06 invoke GetModuleFileName, 0, offset selfname, sizeof selfname
07 invoke CreateFile, offset selfname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0
08
09 cmp eax, INVALID_HANDLE_VALUE
0A je PROGEXIT
0B
0C mov hRead,eax
0D invoke SetFilePointer,hRead,selfsize,0,FILE_BEGIN
0E
0F mov ecx, filesjoined
10 mov esi, offset filesizes - 4
11 EXTRACT_LOOP:
12 push ecx
13 invoke GetTempFileName, offset tempdir,offset tmpprefix,FALSE, offset currname
14 add esi, 4
15
16 push esi
17 invoke WriteFunc, dword ptr[esi]
18 pop esi
19
1A pop ecx
1B loop EXTRACT_LOOP
1C
1D invoke CloseHandle, hRead
;---------------------------------------------------------------------------------------------------------------------
Массив selfname нужен для хранения пути до самого лоадера. В [06] мы определяем этот самый путь. Открываем себя и
устанавливаем указатель на selfsize от начала файла. selfsize определяется билдером перед компиляцией и записывается в
config.inc. filesjoined - это количество склеенных файлов, тоже определяется билдером. filesizes - это массив двойных
слов. Что это за слова попытайся угадать из названия ;). Тоже храниться в config.inc. WriteFunc - это функция
извлечения файлов. Она лежит в file_func.inc и не должна вызывать вопросов.
Второй способ хранения файлов заключается в использовании ресурсов. При компиляции файлы помещаются в ресурсы а
извлекаются при помощи соответствующих API. Смотри res.inc
Третий способ - хранение файлов в секции данных. Билдер должен создать файл с массивом, содержащий в себе все файлы.
Лоадер получится при этом наиболее маленького размера, однако создание файла с массивом займет много времени, так что
способ годен только для небольших файлов. (См res.inc)
ШИФРОВАНИЕ
----------
Функция crypt находится в файлах notcrypt.inc, simcrypt.inc и rc4crypt.inc:
crypt proc cData:DWORD, cSize:DWORD
Она принимает 2 параметра - указатель на данные, которые надо расшифровать и длину этих самых данных. Все 3 функции
crypt - однобайтовые поточные шифры. В зависимости от алгоритма шифрования, который мы выбираем, будет определена одна
из функций crypt.
Самый простой, символический алгоритм шифрования - это инвертирование каждого байта открытого текста.
;---------------------------------------------------------------------------------------------------------------------
00 .code
01
02 crypt proc cData:PCHAR, cSize:DWORD ; cData - pointer of data, cSize - size of data
03 mov eax, cData
04 .WHILE cSize > 0
05 not byte ptr[eax]
06 inc eax
07 dec cSize
08 .ENDW
09 ret
0A crypt endp
;---------------------------------------------------------------------------------------------------------------------
Второй алгоритм немного сложнее.
;---------------------------------------------------------------------------------------------------------------------
00 .data?
01 xorbyte db ?
02
03 .code
04
05 crypt proc cData:PCHAR, cSize:DWORD ; cData - pointer of data, cSize - size of data
06 mov eax, cData
07 .WHILE cSize > 0
08 inc xorbyte
09 xor xorbyte, 0AAh
0A rol xorbyte, 1
0B
0C mov cl, xorbyte
0D xor byte ptr [eax], cl
0E inc eax
0F dec cSize
10 .ENDW
11 ret
12 crypt endp
;---------------------------------------------------------------------------------------------------------------------
Есть байт xorbyte. Изначально он равен нулю.Шифрование заключается в выполнении побитного xor этого байта по очереди
с каждым байтом открытого текста. Перед каждым таким xor с xorbyte выполняются операции [08-0A]. Алгоритм равносилен
циклическому xor с ключом длиной 250 байт. Дешифрование производится аналогично шифрованию.
Последний алгоритм - это rc4 (см rc4crypt.inc). Его описание несложно найти в инете. Если предыдущие алгоритмы
несложно пропалить с помощью hiew или restorator'a при одном только взгляде на шифротекст (второй - сложнее), то rc4
лишен этого недостатка.
Я написал целых три алгоритма шифрования, чтобы каждый сам мог выбрать компромисс между размером лоадера и
криптостойкостью.
THE SMALLER THE BETTER
----------------------
Для сжатия склеиваемых файлов я буду использовать aPlib (ibsensoftware.com).В lib-файле находятся функции для сжатия
данных с помощью алгоритма LZ77. Пакует, как мне показалось, сильнее, чем zip или даже rar. Лучше оказался только
малоизвестный архиватор rk, правда ему на сжатие/распаковку требуется значительно больше времени - на 1 bmp файл может
уйти порядка 10 секунд.
Есть 2 распаковывающие функции - aP_depack_asm и aP_depack_asm_fast. Обе делают одно и тоже. Разница в том, что
вторая быстрее, однако займет в лоадере на пол килобайта больше. Функцию распаковки смотри в файле pack.inc.
ITS ALL
-------
Я думал еще что-нибудь рассказать, но как мне кажется, в этом нет смысла - все, что тебя может интересовать, ты без
труда найдешь в сурсах.
О многом я умолчал. Например, джойнер получился настолько сложным, что я сам стал путаться в исходниках 0_o. Посему,
например, упаковка предусмотрена только в том случае, если ты хранишь файлы в ресурсах лоадера. А еще запуск файлов
осуществляется с помощью только WinExec(), хотя я планировал добавить возможность использовать ShellExecute(). Посему
склеивать можно только exe-файлы, так как их имена генерируются с помощью функции GetTempFileName().То есть, если тебе
нужно приклеить Пинч к картинке,то придется поработать над джойнером - нужно где-нибудь хранить расширения склеиваемых
файлов.
Как видишь, у тебя большой простор для творчества. На месте читателя я бы потер все функции,которые я точно не будут
использовать, и дописал бы то, чего мне не хватает, например убивание файервола и отправление сообщения на аську при
запуске =). Как показывает мой опыт написания джойнеров на заказ, написать хорошую вещь проще, когда в ней меньше
функций ;).
На этой веселой ноте я оставляю тебя наедине с исходниками. Будь здоров, не кашляй.
P.S. Чтобы все удачно скомпилировать, нужно поместить в папку Bin джойнера следующие файлы (из пакета масма):
- cvtres.exe
- link.exe
- ml.exe
- mspdb50.dll
- rc.exe
- rcdll.dll
02/06/05 drmist