Вместо предисловия: Код (Text): ; rus: опьяняющее средство, созданное на фасме ; 1ый параметр имя_файла или "имя файла" если то содержит пробелы ; старайтесь разделять параметры пробелами ; далее идут смещения и данные, которые будут записаны за ими ; смещения отсчитываются с 0 и ограничены размером файла ; если смещение не указано, подставится 0 ; определить смещение просто: @offset ; смещения без данных будут опускаться: @offset1 @offset3 ; после определения смещения все данные после него будут принадлежать ему пока не встретиться следующее оглашение смещения ; к примеру строка @offset1 1 @offset2 1 2 внесет байт 1 за адресом offset1 и байты 1 2 по адресу offset2 ; при старте размер данных = байт ; без учета регистра можно этот размер изменить: bwdq т.е. байт, слово, двойное слово, учетверенное слово ; как и с адресами, обределитель размера действует до следующего определителя ; таким образом b@offset1 1 w @offset2 1 2 @offset3 b1 w2 d4 q8 внесет $01 по адресу offset1, $0001 $0002 по адресу offset2, $01 $0002 $0000'0004 $00000000'00000008 по адресу offset3 ; адреса и данные могут записываться в двоичной(0b), десятичной(0 0d 0D), шестнадцатеричной($0 0x0 0X0), строковой('', "", '''', """", '12''4', "12""4") формах ; для строк '' и "" ровно нулю, '' станет ' если строка начиналась с ', "" станет " если строка начиналась с " ; в числах ' пропустится(1'204 $'00'00' ...) ; для удобства (все символы из таких кавычек считываются как есть) (не закрывайте ее, если хотите читать до конца ; встретив {, программа пропустит все, пока не встретит } ; {} можно сравнить с пробелами т.е. разделителями параметров, помните об этой особенности ; ничего не будет записано до полной проверки ; иногда возможны сообщения ; пример использования: ; start /wait alco.exe test\test.exe @647 0 @756 0 ; start /wait test\test.exe ; start /wait alco.exe test\test.exe @647(моей погибшей флешке)0 @756(почему укр. И не совпадает с англ.)10(почему в наших языках столько запятых)0 {умеет игнорить :)}@$1'0000'0000 ; start /wait test\test.exe ; для писем: edemko@rambler.ru В сорсе комментарии на английском. Если чего не получает?ся, вы только спросите. Комментарии на русском к get_number лежат тут. Есть желание поддерживать VA, скоро должно появиться. Перед компиляцией измените LNG equ ENU на RUS. Сюда возможны посылания из других мест... Код (Text): ; enu: this is an alcoholic tool written in fasm ; 1st parameter must be victim_name or "victim name" if it contains spaces ; parameters should be separated with spaces ; next offsets and data for the offsets come ; offsets counted from 0 and limited to file size ; if no offset specified 0 one implied ; to define an offset type @offset ; empty offsets like @offset1 @offset3 will be skipped ; after an offset defined, any values after that place belong to it until another definition is met ; so @offset1 1 @offset2 1 2 string will put byte value 1 at offset1 and bytes 1 2 at offset2 ; default value size is byte ; other ones, neglecting case, are bwdq i.e. byte, word, dword, qword ; once put, it acts until other size is met ; so b@offset1 1 w @offset2 1 2 @offset3 b1 w2 d4 q8 string will put $01 at offset1, $0001 $0002 at offset2, $01 $0002 $0000'0004 $00000000'00000008 at offset3 ; offsets and values can be in binary(0b), decimal(0 0d 0D), hexadecimal($0 0x0 0X0), string('', "", '''', """", '12''4', "12""4") ; for strings '' or "" mean zero, '' become ' if string was stated by ', "" become " if string was stated by " ; for numbers ' gets ignored(1'204 $'00'00' etc) ; to read symbols as is (use such braces) or (if you need all to be read ; having met { all chars treaded spaces i.e. parameter separators until } found ; no writings will be performed until everything checked ; also messages possible ; command line example: ; start /wait alco.exe test\test.exe @647 0 @756 0 ; start /wait test\test.exe ; start /wait alco.exe test\test.exe @647(title)0 @756(you touched me deeply)10(line 2)0 {etc}@$1'0000'0000 ; start /wait test\test.exe ; mailme: edemko@rambler.ru alco
А как это работает? И что должно делать? Создал батник с этой строкой start /wait alco.exe test\test.exe @647(моей погибшей флешке)0 @756(почему укр. И не совпадает с англ.)10(почему в наших языках столько запятых)0 {умеет игнорить }@$1'0000'0000 Теперь test.exe какие-то крякозябры начал показывать.
s_d_f ;Теперь test.exe какие-то крякозябры начал показывать. Батник видимо делает конвертацию символов из 866 в 1251. У меня тоже. AkelPad(люблю его плужки) умеет работать со множеством кодировок. Сохранив в 866 - все в порядке. Попробуйте вставить(кодировка win1251) в окне cmd.exe или totalcmd.exe - все в порядке. ;А как это работает? Приведенная в примере строчка расположит?ся по статическому адресу bytes: db "моей погибшей флешке",0 dd 674,0,длина тех байт db "почему укр. И не совпадает с англ.",10,"почему в наших языках столько запятых",0 dd 756,0,длина тех байт Потом они запишут?ся каждая одним проходом. fsd ;трой же ? кряк, патч, оно?
ссылка на загрузку из первого поста будет временно недоступна код стал компактнее и менее запутан появится ключ S, отключающий запрос на запись файла преобразования виртуальных адресов в физические по прежнему нет но они будут(дошло как делать) программа в целях уменшения размера использует заглушку временно она закомментирована также в комментах стоит контроль инструкций(386, 486...) Код (Text): см. ниже
тестовая обнаруженные ошибки отмечены гггг_мм_дд, Ошибка №... нод говорит, что она - неизвестный вирус win32, пришлось добавить в доверенные пример: - скопируйте alco.exe в test.exe - выполните комманду "alco.exe test.exe @$40'153bV $eb$f7 s {отключили сообщение холостого вызова}" - запустите патченый файл Код (Text): ; языки программы ---------------------------------------------- LNG equ ENU match lng,`LNG{display 13,10,'LNG equ ',lng} match =ENU,LNG{ string_cannot_open_a_file equ 'cannot open a file' string_invalid_file equ 'file size = 0 or >= 2^32' string_invalid_value equ 'invalid value' string_nothing_to_do equ 'nothing to do' string_out_of_file equ 'out of file' string_out_of_memory equ 'out of memory' string_write_file? equ 'write file?' } match =RUS,LNG{ string_cannot_open_a_file equ 'не открыть файл' string_invalid_file equ 'размер файла = 0 или >= 2^32' string_invalid_value equ 'плохое число' string_nothing_to_do equ 'холостой запуск' string_out_of_file equ 'вне файла' string_out_of_memory equ 'вне памяти' string_write_file? equ 'писать файл?' } ; контроль инструкций от revo ---------------------------------- ;include 'revolution\compatibility.inc' ;.386 format pe gui; on 'stub\stub.exe' section '' code executable import readable writable ; импорт ------------------------------------------------------- dd 0,0,0,rva kernel_name,rva kernel_table,\ 0,0,0,rva user_name,rva user_table,\ 0,0,0,0,0 kernel_name db 'kernel32.dll',0 align 4 kernel_table: CloseHandle dd rva CloseHandle_ CreateFileA dd rva CreateFileA_ ExitProcess dd rva ExitProcess_ GetCommandLineA dd rva GetCommandLineA_ GetFileSize dd rva GetFileSize_ ReadFile dd rva ReadFile_ SetFilePointer dd rva SetFilePointer_ WriteFile dd rva WriteFile_ dd 0 CloseHandle_ dw 0 db 'CloseHandle',0 CreateFileA_ dw 0 db 'CreateFileA',0 ExitProcess_ dw 0 db 'ExitProcess',0 GetCommandLineA_ dw 0 db 'GetCommandLineA',0 GetFileSize_ dw 0 db 'GetFileSize',0 ReadFile_ dw 0 db 'ReadFile',0 SetFilePointer_ dw 0 db 'SetFilePointer',0 WriteFile_ dw 0 db 'WriteFile',0 user_name db 'user32.dll',0 align 4 user_table: MessageBoxA dd rva MessageBoxA_ dd 0 MessageBoxA_ dw 0 db 'MessageBoxA',0 entry $ ; пропустить себя в командной строке --------------------------- call [GetCommandLineA] mov esi,eax lodsb mov ah,al cmp ah,'"' je skip_myself ;имена с кавычками mov ah,' ' ;без skip_myself: lodsb cmp al,0 je nothing_to_do ;нет праметров cmp al,ah jne skip_myself ; пропустить пустоты после себя в командной строке ------------- skip_myself_spaces: lodsb cmp al,0 je nothing_to_do ;нет параметров cmp al,' ' je skip_myself_spaces ; найти начало и конец имени жертвы ---------------------------- mov ah,al cmp ah,'"' je skip_victim ;имена с кавычками mov ah,' ' ;без dec esi skip_victim: mov [victim.path],esi ;начало имени skip_victim_: lodsb cmp al,0 je nothing_to_do ;нет параметров cmp al,ah jne skip_victim_ mov byte[esi-1],0 ;конец имени ; открываем файл-жертву ---------------------------------------- sub eax,eax push eax ;hTemplateFile push eax ;dwFlagsAndAttributes push 3 ;dwCreationDistribution = OPEN_EXISTING push eax ;lpSecurityAttributes push 1 ;dwShareMode = FILE_SHARE_READ push $8000'0000+$4000'0000 ;dwDesiredAccess = GENERIC_READ+WRITE push [victim.path] ;lpFileName call [CreateFileA] inc eax jnz check_victim_size push eax ;uType call @f ;lpCation db string_cannot_open_a_file,0 @@: push [victim.path] ;lpText push eax ;hWnd call [MessageBoxA] jmp exit check_victim_size: dec eax push eax ;CloseHandle.hObject push 0 ;lpFileSizeHigh push eax ;hFile call [GetFileSize] test eax,eax jnz victim_size_ok push eax ;uType call @f ;lpCaption db string_invalid_file,0 @@: push [victim.path] ;lpText push eax ;hWnd call [MessageBoxA] jmp leave_victim victim_size_ok: mov [victim.size],eax ; поддержка перевода pe32 адресов в физические ----------------- ;IDH = IMAGE_DOS_HEADER ;INH = IMAGE_NT_HEADERS ;IOH = IMAGE_OPTIONAL_HEADER ;IFH = IMAGE_FILE_HEADER ;ISH = IMAGE_SECTION_HEADER @v_init:mov edi,@v.size lea ebx,[edi+4] mov ebp,[esp] push esi push 0 edi $40 ebx ebp call [ReadFile] ;считываем IDH cmp dword[edi],$40 jne .nok cmp word[ebx],'MZ' ;проверяем IDH.Signature jne .nok push 0 0 dword[ebx+$3c] ebp call [SetFilePointer] ;смещаемся к INH cmp eax,-1 je .nok mov esi,eax ;INH push 0 edi $58 ebx ebp call [ReadFile] ;читаем по IOH.SizeOfHeaders включно cmp dword[edi],$58 jne .nok cmp dword[ebx],'PE' ;проверяем INH.Signature jne .nok movzx eax,word[ebx+$14] ;читаем IFH.SizeOfOptionalHeader add eax,$18 ;прибавляем к нему sizeof.INH.Signature($04) и sizeof.IFH($14) add esi,eax ;получаем смещение ISH jc .nok cmp esi,[victim.size] ja .nok movzx ecx,word[ebx+$06] ;читаем IFH.NumberOfSections imul eax,ecx,$28 ;IFH.NumberOfSections * sizeof.ISH = размеру заголовков секций add eax,esi ;заголовки сзаду(смещение) jc .nok cmp eax,[victim.size] ja .nok ; lea eax,[ecx+1] ;@v.size = секция заголовков + остальные секции stosd mov eax,[ebx+$34] stosd ;@v.base = IOH.ImageBase sub eax,eax stosd ;rva заголовков = 0 mov eax,[ebx+$54] stosd ;размер заголовков в файле = IOH.SizeOfHeaders sub eax,eax stosd ;смещение заголовков в файле = 0 push 0 0 esi ebp mov ebx,ecx call [SetFilePointer] ;сместиться к ISH .loop:dec ebx js .ok sub esp,$28 mov esi,esp push 0 esi $28 esi ebp call [ReadFile] ;прочитать 1 заголовок секции add esp,$28 add esi,$0c ;ISH.{Rva, SizeOfRawData, PointerToRawData} mov ecx,3 rep movsd ;чередовой элемент @v.rva_size_addr готов jmp .loop ; .nok: sub eax,eax stosd .ok: pop esi ; заполняем bytes.body: db b1,b2,..bn; dd @1,0,sizeof(db b1,b2,..bn) ; db b3,b4,..bn; dd @2,0,sizeof(db b3,b4,..bn) ; ... mov [element.size],1 sub eax,eax mov [option.s],al ;вкл/откл запрос на запись файла mov edi,bytes.body ;создаем пустую цепочку stosd ; по смещению 0 stosd ; ... get_bytes_: stosd ; и с числом байт 0 get_bytes: lodsb cmp al,0 je write_bytes cmp al,' ' je get_bytes cmp al,'(' je long_string cmp al,'@' je chain cmp al,'{' je pascal_comment call ascii_lower cmp al,'b' mov ah,1 je set_element.size cmp al,'w' mov ah,2 je set_element.size cmp al,'d' mov ah,4 je set_element.size cmp al,'q' mov ah,8 je set_element.size cmp al,'s' je set_option.s bwdq: cmp edi,bytes.limit-$ff +12;2011_03_14, ошибка №3(не грубая): +12 отсутствовало ja out_of_memory ;особенность get_number cmp dword[edi-8],0 jnz out_of_file ;вне файла mov ebx,[edi-12] ;смещение цепочки в файле mov edx,[edi-4] ;данных в цепочке add edx,[element.size] ;станет данных в цепочке mov ecx,ebx add ecx,edx jc out_of_file cmp ecx,[victim.size] ja out_of_file ;вне файла push ebx push edx push esi ;данные об ошибке sub edi,12 ;2011_03_14, ошибка №2: линия отсутствовала call get_number pop eax pop edx pop ebx jc invalid_value lea ecx,[edi-8] ;начало qword'a add ecx,[element.size] ;начало байт которые должны быть 0, их мы перепишем шапкой цепочки .loop:cmp edi,ecx je long_string.loop_ok dec edi cmp byte[edi],0 je .loop invalid_value: mov esi,eax push 0 ;uType call @f ;lpTitle db string_invalid_value,0 out_of_file: push 0 ;uType call @f ;lpTitle db string_out_of_file,0 @@: dec esi push esi ;lpText push 0 ;hWnd call [MessageBoxA] jmp leave_victim out_of_memory: push 0 ;uType call @b ;lpTitle db string_out_of_memory,0 set_option: .s: mov [option.s],al jmp get_bytes set_element.size: mov byte[element.size],ah jmp get_bytes chain: cmp dword[edi-4],0 jnz .keep_previous sub edi,12 ;переписать пустую цепочку .keep_previous: lodsb cmp edi,bytes.limit-$ff ja out_of_memory ;особенность get_number push esi call get_number pop eax jc invalid_value cmp byte[esi],'V' je .@v_init cmp byte[esi],'v' je .@v_init sub eax,eax jmp get_bytes_ ;данных в цепочке = 0 .@v_init: cmp dword[edi-4],0 jnz invalid_value mov ebx,[@v.base] sub [edi-8],ebx ;-IOH.ImageBase = размер относительно начала загрузки jc invalid_value mov ebx,@v.rva_size_addr-12 mov ecx,[@v.size] .loop:dec ecx js invalid_value ;физ. адрес не найден add ebx,12 ;чередовой ISH.{Rva, SizeOfRawData, PointerToRawData} mov edx,[edi-8] sub edx,[ebx] ;-ISH.Rva = размер относительно начала секции jc .loop cmp edx,[ebx+4] ;ISH.SizeOfRawData ja .loop add edx,[ebx+8] ;+ISH.PointerToRawData = смещение в файле jc .loop mov [edi-8],edx ;физ. адрес inc esi ; sub eax,eax jmp get_bytes_ ;данных в цепочке = 0 long_string: lodsb cmp al,0 je write_bytes ;( cmp al,')' je get_bytes ;() cmp dword[edi-8],0 jnz out_of_file ;вне файла mov ebx,[edi-12] ;сохранить смещение цепочки mov ecx,[victim.size] sub ecx,ebx ;максимум байт для цепочки в файле при таком смещении jna out_of_file ;для цепочки не осталось места mov edx,[edi-4] ;сохранить байт_в_цепочке_на_данный_момент sub ecx,edx ;столько мы можем взять сичас jna out_of_file ;ни`сколько sub edi,12 ;вытрем шапку, она всегда в хвосте .loop:sub ecx,1 ;2011_03_09, ошибка №1: стояло dec ecx jc out_of_file ;вне файла ; jz ... cmp edi,bytes.limit-12 jae out_of_memory ;мало памяти stosb inc edx ;байт_в_цепочке_на_данный_момент +1 lodsb cmp al,0 je .loop_ok ;( cmp al,')' jne .loop .loop_ok: mov eax,ebx ;обновлеям шапку цепочки stosd sub eax,eax stosd mov eax,edx jmp get_bytes_ pascal_comment: lodsb cmp al,0 je write_bytes ;{ cmp al,'}' je get_bytes ;{} jmp pascal_comment ; записать цепочки --------------------------------------------- write_bytes: cmp dword[edi-4],0 jnz .ask_write sub edi,12 cmp edi,bytes.body je nothing_to_do .ask_write: cmp [option.s],'s' je .skip_ask_write ;запрос на запись файла отключен push 4 ;uType = MB_YESNO call @f ;lpCaption db string_write_file?,0 @@: push [victim.path] ;lpText push 0 ;hWnd call [MessageBoxA] cmp eax,6 ;IDYES jne leave_victim .skip_ask_write: mov ebx,[esp] ;CloseHandle.hObject .loop:push 0 ;dwMoveMethod = FILE_BEGIN push 0 ;lpDistanceToMoveHigh push dword[edi-12] ;lDistanceToMove = смещение цепочки push ebx ;hFile call [SetFilePointer] push 0 ;lpOverlapped sub edi,4 push edi ;lpNumberOfBytesWritten mov eax,[edi] push eax ;nNumberOfBytesToWrite sub edi,12-4 sub edi,eax push edi ;lpBuffer push ebx ;hFile call [WriteFile] cmp edi,bytes.body jne .loop ; выход(ы) ----------------------------------------------------- leave_victim: call [CloseHandle] exit: push eax ;uExitCode call [ExitProcess] nothing_to_do: sub eax,eax push eax ;uType push eax ;lpCaption call @f ;lpText db string_nothing_to_do,0 @@: push eax ;hWnd call [MessageBoxA] jmp exit ; см. больше тут: http://fasmme.googlecode.com/files/calc.rar -- ascii_lower: cmp al,'A' jb @f cmp al,'Z' ja @f add al,' ' ;'A..Z' -> 'a..z' @@: ret 0 get_number: cmp al,1 jnc @f ret 0 ;конец строки @@: xor ecx,ecx ;чисел записано в буфер cmp al,'"' je .raw ;как есть cmp al,"'" je .raw ;как есть cmp al,'$' je .set_number_notation_hex cmp word[esi-1],'0x' je .set_number_notation_hex_ cmp word[esi-1],'0X' je .set_number_notation_hex_ mov bl,0 ;примем за десятичное jmp .check_load .set_number_notation_hex_: inc esi ;сместиться за 0x mov al,'$' .set_number_notation_hex: mov bl,al ;и так, шестн. или десятичное .load: lodsb ;соберем цифры cmp al,"'" je .load ;fasm .check_load: call ascii_lower cmp al,'b' ;попробуем установить двоичную форму числа je .try_set_number_notation cmp al,'d' ;попробуем установить десятич. форму числа je .try_set_number_notation cmp al,'0' jb .load_to_number ;меньше "0" cmp al,'9' ja .load_hex? ;больше "9" sub al,'0' ;"0..9" -> 0..9 jmp .store_load ;сохранить цифру .load_hex?: cmp al,'a' jb .load_to_number ;меньше 10 cmp al,'f' ja .load_to_number ;больше 15 .load_hex: sub al,'a'-10 ;"a..f" -> 10..15 .store_load: add cl,1 jnc @f ret 0 ;вне памяти @@: stosb ;сохраняем наконец jmp .load ;продолжаем сбор .try_set_number_notation: cmp bl,'$' je .load_hex ;b, d в шестнадц. числе mov bl,al inc esi ;вспомнит?ся позже .load_to_number: cmp cl,1 jnc @f ret 0 ;буфер пуст @@: push esi ebp ;на выходе esi и edi вказывают на конец буферов в случае все ОК, ebp не трогаем mov ebp,esp ;бедет leave для освобождения стэка cmp bl,'$' je .load_hex_to_number cmp bl,'b' je .load_bin_to_number ;.load_dec_to_number: xor ebx,ebx ;степень десятки push ebx ebx ;результат .ldtn: dec edi movzx eax,byte[edi] ;загрузили цифру cmp al,9 ja .stc_leave_pepsi_ret ;но шестн. :) cmp al,0 je .ldtn_continue ;0 * 10^x = 0 test ebx,ebx jnz .ldtn_rank_nz mov [ebp-8],al jmp .ldtn_continue ;al * 10^0 = al * 1 = al .ldtn_rank_nz: push ebx ecx mov ecx,ebx mov ebx,eax ;младшее xor esi,esi ;старшее .ldtn_rank: mov eax,10 mul esi jc .leave_pepsi_ret ;вне qword mov esi,eax mov eax,10 mul ebx add esi,edx jc .leave_pepsi_ret ;вне qword mov ebx,eax loop .ldtn_rank add [ebp-8],ebx ;получаем общее adc [ebp-4],esi jc .leave_pepsi_ret ;вне qword pop ecx ebx ;восстанавливаемся и ... .ldtn_continue: inc ebx ;увеличим степень 10 loop .ldtn pop ebx esi .load_ok: mov eax,ebx stosd mov eax,esi stosd leave pop esi dec esi clc ret 0 .stc_leave_pepsi_ret: stc .leave_pepsi_ret: leave pop esi ret 0 .load_hex_to_number: mov edx,ecx xor ecx,ecx ;степень 16ти xor esi,esi ;конечный результат xor ebx,ebx ;... .lhtn: dec edi movzx eax,byte[edi] ;загрузили из очередного млад. разряда cmp al,0 jz .lhtn_continue ;0 cmp ecx,64 jae .stc_leave_pepsi_ret ;вне числа cmp cl,32 jae .lhtn_high shl eax,cl add ebx,eax jmp .lhtn_continue .lhtn_high: sub cl,32 shl eax,cl add cl,32 add esi,eax .lhtn_continue: dec edx jz .load_ok add ecx,4 ;*16 = *2^4 = shl 4 jmp .lhtn .load_bin_to_number: ;почти так само mov edx,ecx xor ecx,ecx xor esi,esi xor ebx,ebx .lbtn: dec edi movzx eax,byte[edi] cmp al,1 ja .stc_leave_pepsi_ret jb .lbtn_continue cmp ecx,64 jae .stc_leave_pepsi_ret cmp cl,32 jae .lbtn_high shl eax,cl add ebx,eax jmp .lbtn_continue .lbtn_high: sub cl,32 shl eax,cl add cl,32 add esi,eax .lbtn_continue: dec edx jz .load_ok inc ecx jmp .lbtn .raw: mov ah,al ;запомнить " или ' .raw_loop: lodsb cmp al,1 jc .raw_ret ;нет завершающей кавычки ah cmp al,ah jne .raw_store ;не кавычка lodsb cmp al,ah je .raw_store ;ahah -> ah dec esi mov al,0 ;подложка neg cl add cl,8 rep stosb clc ret 0 .raw_store: inc ecx ;счетчик записаных чисел cmp cl,8 ja .raw_stc_ret ;вне числа stosb jmp .raw_loop .raw_stc_ret: stc .raw_ret: ret 0 ; виртуальные данные ------------------------------------------- victim: .path dd ? ;имя файла-жертвы .size dd ? ;размер в байтах bytes: .body rb $fffc ;статический буфер .limit: ;и его кордон element: .size dd ? ;как писать числа: 1=байт, 2=слово, 4=двойное слово, 8=учетверенное слово @v: ;см. @v_init и .@v_init .size dd ? ;имеем записей .base dd ? ;база образа .rva_size_addr rb 3*4*65'536 ;записи option: .s db ? ;вкл\откл запрос на запись файла
все бы было хорошо, если бы где нибудь вначале было кратко намекнуто в общих чертах что это и для чего это. приблизительно