Otebebe То есть ты таким способом хочешь резидентную прогу сделать? После вызова функции завершения в PSP может оказаться что угодно. Или ты хочешь сделать TSR без PSP?
Для защиты конечно. Для чего ж еще. В дизасме ты такой код уже не посмотришь (плагинами иды прошу не упрекать). Самомодификация - это то же самое шифрование. Только не в цикле меняется целый блок кода, а "вручную" каждая инструкция.
Vov4ick Пока сделал следующее: a)процедуру таймера (примерно через секунду бросает в видеобуффер символ единицы) описал через DB в segment data (так как гружу по смещению 80H то все смещения в коде естественно пересчитать легко) б) при старте осн.прг сохраняю вектор старого обработчика в) забрасываю DS:SI в PSP:0080H г) устанавливаю новый вектор на PSP:0080H д)....(ну жду AH=01H int21H cимвол,пока BIOS арбайтен.) из основной. Теперь думаю о инициализации вектора из PSP и из PSP же завершить "программу-папу" место то еще есть. Но пока отложил и буду изучать cтруктуру TSR.
Вот вам рабочий резидент! Это нужная понимаешь вещь. Можно управлять громкостью SB16 из под DOS. Было такое время когда ВИНДЫ мы не могли поставить на свое железо. Компилилось каким-то ТАСМОМ. 3-й что-ли. Ну давно это ... Код (Text): .286 ;режим МП 80286 .model tiny ;незнаю зачем, но эти строки тут нужны .code ;для COM файлов org 100h ;обязательно для COM файлов prg: jmp ini newint9 proc far push ax in al,60h cmp al,54h ;активация по ALT+Print Screen .ТОЧНО не помню давно это было попробуй F12 pop ax je do_pop jmp cs:vector endp do_pop: pusha in al,61h mov ah,al or al,80h out 61h,al xchg ah,al out 61h,al mov al,20h out 20h,al mov ah,0bh mov bx,001fh int 10h Voice equ 04h Mic equ 0Ah Volume equ 22h FM equ 26h CD equ 28h Line equ 2eh start: mov ah,10h int 16h mov bl,FM cmp al,'f' jz Down cmp al,'F' jz Up mov bl,Voice cmp al,'w' jz Down cmp al,'W' jz Up mov bl,Line cmp al,'l' jz Down cmp al,'L' jz Up mov bl,Volume cmp al,'v' jz Down cmp al,'V' jz Up mov bl,CD cmp al,'c' jz Down cmp al,'C' jz Up mov bl,Mic cmp al,'m' jz Down cmp al,'M' jz Up exit: cmp al,'q' ;выход по q jnz start mov ah,0bh mov bx,0000h int 10h eexit: popa iret Up: call PUp jmp exit Down: call PDown jmp exit PDown proc push ax mov al,bl call MixPort call MixDataIn sub al,022h jc zero rzero: call MixDataOut pop ax ret PDown endp zero: mov al,00h jmp rzero PUp proc push ax mov al,bl call MixPort call MixDataIn add al,011h jc full rfull: call MixDataOut pop ax ret PUp endp full: mov al,0ffh jmp rfull MixPort proc mov dx,224h out dx,al ret MixPort endp MixDataOut proc mov dx,225h out dx,al ret MixDataOut endp MixDataIn proc mov dx,225h in al,dx ret MixDataIn endp vector dd ? endd: ini: push cs ;запись во все сегментные регистры push cs ;одного значения. pop ds ;только для COM файлов pop es ; cs=dc=es lea dx, message mov ah,09h int 21h mov ax,3509h ;перехват int9 int 21h mov word ptr vector [2],es mov word ptr vector [0],bx push ds mov ax,cs mov ds,ax mov dx, offset newint9 mov ax,2509h int 21h pop ds mov dx, offset endd int 27h ;функция завершения программы,отаться резедентной message db 13,10 db 'драйвер микшера установлен',13,10,'$' end prg
Ну примеров можно много привести... Типовой резидент. Правда нет проверки на повторный запуск и памяти много кушает. ЗЫ Активируется по printscreen, альтом в нём и не пахнет.
leo Угу, а также автоматическое отслеживание записи в код, поэтому старые фокусы с предвыборкой как на 486 давно не прокатывают. - Иструкции сеарилизации позволяют модифицировать код даже на Core 2 Duo. Otebebe Нет код который приведен мной не модифицирует сам код, а лишь пишет впеременную в кодовом сегменте приусловии что es=cs, сама фишка - чтобы самомодифицирующийся код мог работать необходимо посе модификации исполнить любую инструкцию сеарилизации процессора. Т.е. все вышеприведенные примеры не используют иструкции сеарилизации, и работа модифицированного кода может оказаться непредсказуемой, тем более на многоядерных процессорах.
PROFi Про сериализацию пока...:-(. Но ЕS=CS понял. Вот построил... "колхозно-обфускаторную без джампово-поп модификацию" ;ЕXIT в DOS Код (Text): push CS mov AX,CS ;"привязываемся" к некоторой базе xor BX,BX K0: inc AX cmp AX,42A7H jne K0 K1: shr AH,01H ;AX=21A7H add AL,26H ;AX=21CDH xchg AX,BX ;BX=21CDH AX=0000H add AH,26H ;AX=2600H shl AX,01 ;AX=4C00H BX=21CDH pop ES ;ES=CS push AX push BX sar BX,08H mov AH,BH ;AX=0000H BX=0021H pop ES:[BX] pop AX CS:0021 <----cюда строим 0CD21H
PROFi Повторяю, современные процессоры устроены намного сложнее i4086 поэтому они сами отслеживают модификацию кода и при необходимости сбрасывают не только конвеер, но и T-кэш в P4 и служебную инфу преддекодера длин в L1\L2 AMD К7,К8. Поэтому требование обязательной сериализации рулит только для древних процев, а в современных манулах Intel и AMD ты такого требования не найдешь
Vov4ick В чем смысл ? Смотрите какие уже видели приемы самомодификации: a) xor-подход.Инструкция "Б"готовится через преобразование байт-строки представляющей команду "А". "A"-в коде есть,но не выполняется.Обфускация. б) DS:SI-->ESI."Забрасывание кода".Несколько возможностей.Например с замещением кода. Или с дополнением.Видимо лучший подход в модификации. в) сall/jmp через регистр/mem. Пока у меня нет комментариев. г) "меточный мув".(Применен в статье "Заклинание кода").Во многом похож на a) д)В примере же с CS=ES:[BX] BX-можно рассматривать как параметр.Который...грубо...представляет длину инструкций.Это позволяет _достраивать_ код ....в общем не знаю как сказать точнее...
Самомодификация на стеке/куче. Код (Text): // определяем размер самомодифицирующейся функции Idefine SELFSIZE ((int) x_self_mod_end - (int) x_self_mod_code) // начало самомодифицирующейся функции // спецификатор naked, поддерживаемый компилятором MS VC, указывает компилятору // на необходимость создания чистой ассемблерной функции, то есть такой функции. // куда компилятор не внедряет никакой посторонней отсебятины __declspecC naked ) int x_selfjnod_code(int a. int b ) { _asm { begin_sm: ; начало самомодифицирующегося кода mov eax. [esp+4] ; получаем первый аргумент > call get_eip ; определяем свое текущее положение в памяти get_eip: add eax, [esp + 8 + 4] ; складываем/вычитаем из первого аргумента второй pop edx ; в edx адрес начала инструкции add eax. ... хог byte ptr [edx],28h ; меняем add на sub и наоборот ret ; возвращаемся в материнскую функцию } } x_self_mod_end() { /* конец самомодифицирующейся функции */ } mainO { int a: int (__cdecl *se1f_mod_code)(int a. int b); // раскомментируйте следующую строку, чтобы убедиться, что непосредственная // самомодификация под Windows невозможна (система выплюнет исключение) // self_rrod_code(4,2): // выделяем память из кучи (в куче модификация кода разрешена) // с таким же успехом мы могли бы выделить память из стека: // se1fjiiod_code[SELF_SIZE]; self_mod_code = (int (_cdecl*)(int. int)) malloc(SELF_SIZE); // копируем самомодифицирующийся код в стек/кучу memcpy(self_mod_code. x_self_mod_code, SELF_SIZE): // вызываем самомодифицирующуюся процедуру 10 раз for (а - 1:а< 10;а++) printf("*02X ", self_mod_code(4.2)); printf("\n"); }
Или вот ещё... Код (Text): #define CRYPT_LEN ((int)crypt_end - (int)for_crypt) // маркер начала mark_begin() { _asm _emit 'K' _asm _emit 'P' _asm _emit 'N' _asm _erait 'C' } // зашифрованная функция for_crypt(int a. int b) { return a + b; } crypt_end(){} // маркер конца mark_end () { _asm _emit 'K' _asm _emit '?' _asm _emit 'N' _asm _emit 'C' } // расшифровщик crypt_it(unsigned char *p, int c) { int a; for (a - 0; a < c; a++) *p++ *- 0x66; } main() { // расшифровываем защитную функцию crypt_it((unsigned char*) for_crypt, CRYPT_LEN); // вызываем защитную функцию printf ("%02Xh\n",forcrypt(0x69, 0x66)); // зашифровываем опять crypt_it((unsigned char*) for crypt, CRYPT_LEN); }
sxd Не понимаю я по вашему символы ('К','P',...) какие-то получаются(выводятся) из входного(выходного) потока ? И с помощью них происходит шифровка/де-шифрование...А чего шифруют, и на выходе код или что ? Код (Text): { begin_sm: ; начало самомодифицирующегося кода mov eax. [esp+4] ; получаем первый аргумент > call get_eip ; определяем свое текущее положение в памяти get_eip: add eax, [esp + 8 + 4] ; складываем/вычитаем из первого аргумента второй pop edx ; в edx адрес начала инструкции add eax. ... хог byte ptr [edx],28h ; меняем add на sub и наоборот ret ; возвращаемся в материнскую функцию } Складываем EAX с чем-то из стэка(адрес возврата ? )и... ничего про ЕDX нигде не написано.... Т.е имеем специальным образом заполненные EAX(размер этой функции использующей хor-модифицирование ?) и некий байт, косвенно адресуемый через ЕDX... И что будет дальше ? Сорри
; "ленточный экзекьютор" ??? ; Программу можно представить как конгломерат подпрограмм. ; ; Например "программу" ; mov AX,4C00H ; mov BX,0EE00H ; можно представить в виде ; toAX proc ; mov AX,4C00H ; ret ; toAX endp ; toBX proc ; mov BX,0EE00H ; ret ; toBX endp ; main proc ; call toAX ; call toBX ; main endp ; Место возврата (для ret) можно подготовить предварительным push'ем в самой подпрограмме ; Тогда ; а) сам oп.код ret'a 0C3H можно использовать как маркер ; б) все подпрограммы выполнять в одном фиксированном месте ; Пусть данные и код лежат в виде: ; .......C3.............C3..C3......C3..... ("лента") ; доставляя такие куски(....C3) в сегмент кода и передавая на них управление ; получим программу. Код (Text): ;Хэлло Ворлд! TASM 2.0 .286 text segment 'code' assume CS:text,DS:data main proc mov AX,data mov DS,AX cld xor SI,SI xor DI,DI PREPARE: lodsb mov byte ptr CS:[DI+0014H],AL inc DI cmp AL,0C3H jne PREPARE ;CS:0014H main endp text ends data segment DB 0EBH,0FH,48H,65H,6CH,6CH,6FH,20H,77H,6FH,72H,6CH,64H,21H,0DH,0AH,24H,1EH,0EH,1FH DB 0B8H,00H,09H,0BAH,16H,00H,0CDH,21H,1FH,68H,08H,00H,0C3H,0B8H,00H,4CH,0CDH,21H,0C3H data ends stack segment para stack 'STACK' db 80H dup (?) stack ends end main
Otebebe, только надо следить чтоб c3 не встретилась в какойто другой команде типа mov,eax,0c3h... идея веселоя, но толку мало. любую программу делят на подпрограммы, а то что ты их извращенно запускаешь. это не есть самомодифицирующийся код, это просто другой подход к использованию подпрограмм но в развитие данного я б сделал так: каждую подпрограмму разбиваем на кучу мелких подпрограмм. убераем повторяющиеся подпрограммы нумеруем их. строим таблицу для каждой подпрограммы, получится типа db 10,01,02,08 где 10: push ebp mov ebp,esp 01,02: какието действия подпрограммы 08: leave retn