Self-Modifying Indecent Turing Hack (задачка)

Тема в разделе "WASM.A&O", создана пользователем Black_mirror, 17 июл 2008.

  1. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Нашёл я описание этого замечательного языка
    http://catseye.tc/projects/smith/doc/smith.html
    и решил что-то не сложное на нём написать. Программа ест 400 метров памяти, работает секунд 10, но всё же находит все простые числа от 2 до 10000.
    Код (Text):
    1. include '%fasminc%\win32ax.inc'
    2.  
    3. section '.text' code readable writeable executable
    4.  
    5. N = 10000 ;до какого числа искать простые(для N=10000 требуется примерно 400Мб памяти)
    6. M = $18000000;сколько выделить памяти
    7.  
    8. start:
    9.     mov ebx,buf ;сюда складывае простые числа
    10.     mov ebp,2   ;первое проверяемое число
    11.     mov esi,l1s-1   ;указатель на текущий блок, чтобы знать откуда копировать
    12.     std
    13. l1s:
    14. ;esi будет указывать на конец первого цикла(вернее текущей итерации)
    15.     add esi,l1e-l1s
    16. ;если ebp>=N то затираем тело первого цикла NOP'ами
    17.     cmp ebp,N  
    18.     cmc
    19.     sbb ecx,ecx
    20.     mov edi,esi
    21.     and ecx,l1e-l1b-1
    22.     inc ecx
    23.     mov al,90h
    24.     rep stosb
    25.     nop
    26. l1b:
    27.     push ebx    ;сохраняем перед началом второго цикла
    28. ;копируем всё начиная с метки l1s чтобы первый цикл мог выполниться еще раз
    29.     add esi,prog_end-l1e   
    30.     lea edi,[esi+l1e-l1s]
    31.     mov ecx,prog_end-l1s
    32.     rep movsb
    33.     add esi,l2s-l1s ;esi будет указывать на начало второго цикла
    34.     nop
    35. l2s:
    36.     add esi,l2e-l2s ;esi будет указывать на конец второго цикла
    37.     sub ebx,4
    38. ;если ebx<buf(больше не на что делить) то затираем тело второго цикла NOP'ами
    39.     cmp ebx,buf
    40.     sbb ecx,ecx
    41.     mov edi,esi
    42.     and ecx,l2e-l2b-1
    43.     inc ecx
    44.     mov al,90h
    45.     rep stosb
    46.     nop
    47. l2b:
    48. ;делим ebp на очередное простое число
    49.     mov eax,ebp
    50.     xor edx,edx
    51.     div dword [ebx]
    52.     cmp edx,1
    53. ;если разделилось нацело, то затираем тело второго цикла,
    54. ;а также, часть первого цикла, которая сохраняет новое простое число
    55.     sbb ecx,ecx
    56.     and ecx,l1f-l2c-1
    57.     inc ecx
    58.     lea edi,[esi+l1f-l2e]
    59.     mov al,90h
    60.     rep stosb
    61.     nop
    62. l2c:
    63. ;копируем всё с метки l2s чтобы еще раз выполнить второй цикл
    64. ;+l1e-l1s потому что у нас есть еще одна итерация первого цикла
    65.     add esi,prog_end-l2e+l1e-l1s
    66.     lea edi,[esi+l2e-l2s]
    67.     mov ecx,prog_end-l2s+l1e-l1s
    68.     rep movsb
    69.     add esi,l2e-l2s ;esi будет указывать на конец второго цикла
    70.     nop
    71. l2e:   
    72. ;сохраняем ebp в списке простых чисел
    73. ;эта часть бедёт затёрта NOP'ами если ebp не простое
    74.     pop ebx    
    75.     mov [ebx],ebp
    76.     add ebx,4
    77.     push ebx
    78.     nop
    79. l1f:
    80.     pop ebx     ;востанавливаем ebx
    81.     inc ebp         ;увеличиваем ebp
    82.     add esi,l1e-l2e ;esi будет указывать на конец первого цикла
    83.     nop
    84. l1e:
    85.     add esi,l3s-l1e
    86.     mov ebp,bufe-1  ;сюда будем записывать строку
    87.     mov byte [ebp],0
    88. l3s:
    89.     dec ebp
    90.     mov byte [ebp],' '
    91.     add esi,l3e-l3s
    92.     sub ebx,4
    93. ;если ebx<buf(больше нечего выводить) то затираем тело третьего цикла NOP'ами
    94.     cmp ebx,buf
    95.     sbb ecx,ecx
    96.     mov edi,esi
    97.     and ecx,l3e-l3b-1
    98.     inc ecx
    99.     mov al,90h
    100.     rep stosb
    101.     nop
    102. l3b:
    103.     mov eax,[ebx]   ;очередное простое число
    104. ;копируем тело третьего цикла, чтобы вывести следующее число
    105.     add esi,prog_end-l3e
    106.     lea edi,[esi+l3e-l3s]
    107.     mov ecx,prog_end-l3s
    108.     rep movsb
    109.     add esi,l4s-l3s
    110.     nop
    111. l4s:
    112. ;делим eax на 10, цифру записываем в строку(ebp)
    113.     add esi,l4e-l4s
    114.     xor edx,edx
    115.     mov ecx,10
    116.     div ecx
    117.     add edx,'0'
    118.     dec ebp
    119.     mov [ebp],dl
    120.     cmp eax,1
    121. ;если частное 0, то затираем тело 4го цикла
    122.     sbb ecx,ecx
    123.     mov edi,esi
    124.     and ecx,l4e-l4b-1
    125.     inc ecx
    126.     push eax
    127.     mov al,90h
    128.     rep stosb
    129.     pop eax
    130.     nop
    131. l4b:   
    132. ;копируем тело 4го цикла, чтобы вывести следующию цифру
    133.     add esi,prog_end-l4e+l3e-l3s
    134.     lea edi,[esi+l4e-l4s]
    135.     mov ecx,prog_end-l4s+l3e-l3s
    136.     rep movsb
    137.     add esi,l4e-l4s
    138.     nop
    139. l4e:
    140. l3e:
    141.     cld
    142.     invoke MessageBox,0,ebp,"primes",0
    143.     invoke ExitProcess,0
    144. prog_end:
    145.  
    146. rb M    ;память для самомодификации проги
    147.  
    148. .data
    149.  
    150. buf rb N*4  ;с начала буфера записываем числа
    151. bufe:       ;а с конца строку чтобы вывести
    152.  
    153. .end start
    А теперь предлагаю порешать следующую задачку:
    0) секцию кода размещаем первой, метку старт ставим на 401000h(это в целях упрощения сравнения программ) в конце секции резервируем 1Мб(думаю хватит)
    1) в начале программы вызываем GetCurrentDirectory, строку кладём в секцию данных(4К для строки наверно хватит)
    2) переставляем символы строки в обратном порядке (команд перехода не используем вообще, никаких функций здесь не вызываем, только копирование кода)
    3) вызываем MessageBox(чтобы вывести строку с переставленными символами), а после него int3 (этот кусок тоже придётся копировать)
    Минимизировать нужно расстояние от инструкции int3 до метки с которой началось выполнение программы. Куски кода можно размещать в секции данных и копировать их оттуда, считаем только длину выполненного кода.
     
  2. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Код (Text):
    1. include 'win32axp.inc'
    2.  
    3. section '.text' code readable writeable executable
    4.  
    5. start:  xor     eax, eax
    6.         mov     ebx, dir
    7.         push    eax eax ebx eax
    8.         invoke  GetCurrentDirectory, ebx, ebx
    9.  
    10.         mov     ecx, eax
    11.         mov     esi, l_from
    12.         lea     edi, [esi+l_to-l_from]
    13.         rep     movsd
    14.         lea     esi, [ebx-dir+l_msg]
    15.         movsd
    16.         movsd
    17.  
    18.         mov     edi, ebx
    19.         add     ebx, eax
    20.  
    21. l_from:
    22.         dec     ebx
    23.         mov     al, [edi]
    24.         nop
    25.         nop
    26.         xchg    [ebx], al
    27.         stosb
    28. l_to:
    29. .end start
    30.  
    31.  
    32. rb 0x1000000
    33.  
    34.  
    35. section '.data' data readable writeable
    36.  
    37. l_msg:  call    [MessageBox]
    38.         int3
    39.         nop
    40.  
    41.         dir        rb 0x4000
    Наверняка можно как-то сократить, но оставлю это для других желающих, а то мозг кипит уже..