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.