Как правильно закодировать call?

Тема в разделе "WASM.BEGINNERS", создана пользователем 2FED, 10 авг 2008.

  1. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    не могу изменить машинный код call-a

    Вот например
    Код (Text):
    1. exitproc proc
    2.     invoke  ExitProcess,0
    3. exitproc endp
    4. ....
    5.  
    6. ; разрешаем запись
    7.     push    offset tmp
    8.     push    PAGE_EXECUTE_READWRITE
    9.     push    8
    10.     push    offset offfset
    11.     call    VirtualProtect
    12.  
    13.  
    14.     mov     eax,offfset
    15.     mov     ecx,exitproc
    16.     mov     dword ptr [eax+1],ecx
    17.    
    18. offfset:
    19.     call Mylstrlen
    Отладчик показывает что команда call Mylstrlen состоит из опкода

    E805010000(исправлено) , E8 это опкод call так? тогда что такое 05010000? ничо не пойму

    Бред какойто получается. Например с push-ем всё просто, первым байтом 68h, потом адрес 4 байта. А тут я не знаю что делать :dntknw: к стате с jmp та же фигня :dntknw:
     
  2. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    00010000 = Mylstrlen-(offfset+5), где offfset+5 = начало след инструкции
     
  3. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    GoldFinch
    Неверно. :) Забываете об одном из основных принципов работы x86.
     
  4. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    я немного ошибся, там был опкод E805010000 сейчас попробовал поставить два вызова так

    Код (Text):
    1. call Mylstrlen  ;Опкод E805010000
    2. call exitproc   ;Опкод E815010000
    3. ....
    4.  
    5. Mylstrlen proc  s:dword
    6. ....
    7.     ret
    8. Mylstrlen endp
    9.  
    10. exitproc proc
    11.     invoke  ExitProcess,0
    12. exitproc endp
    Если отнять от адреса функции смещение следующей инструкции то не сходится с тем что в опкоде, темболее откуда нам знать от какого адреса функции отнимать когда нам только предстоит это узнать?
     
  5. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    2FED
    Еще как сходится. Для call Mylstrlen разница должна быть 105h. Для call exitproc разница - 115h.
    Кому "вам"? Если компилятору, то Вы сообщаете (явно или неявно) ему базу загрузки кода. А адреса остальных инструкций, функций, данных он просчитывает.
     
  6. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    тоесть там байты перевёрнуты?

    получается
    15 01 00 00 =
    00 00 01 15

    Получается мне надо сделать "Адрес - База" а потом его перевернуть и только после этого записывать в опкод.. правильно?
     
  7. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    2FED
    Это называется не "перевернуты". Это один из основных принципов работы x86: младший байт по младшему адресу. И переворачивать его не надо. Т.е. если Вы хотите сформировать опкод, то просто высчитываете его, а потом записываете. В синтаксисе фасма это выглядит примерно так:

    Код (Text):
    1. jmp @F
    2.    callOpcode db 0E8h
    3.    callOffset dd 0
    4.    retLabel db 0C3h
    5.    msgText db 'Text',0
    6.    msgCaption db 'Caption',0
    7. @@:
    8. mov eax,[MessageBox]        ;помещаем адрес MessageBoxA в eax
    9. sub eax,retLabel                 ;из адреса назначения прыжка вычитаем адрес старт (стартом является начало следующей инструкции)
    10. mov dword[callOffset],eax    ;как видно, никакого переворота не нужно, т.к. x86 сразу записывает младший байт по младшему адресу
    11.  
    12. push 0                               \
    13. push msgCaption                   \
    14. push msgText                         > Пихаем параметры в стэк и прыгаем на только что сформированный call.
    15. push 0                                 /
    16. jmp callOpcode                    /
     
  8. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    А как заколбасить обсолютную адресацию, у меня чото не выходит.

    пишу опкод 0FFh потом там надо ещё один байт заполнить а я не знаю чем.
    в мануалах написано

    FF /3 CALL m16:32 Call far, absolute indirect, address given in m16:32

    MemNear 11111111oo100mmm (это из другово мануала)

    что такое /3? и что значит oo100mmm?

    Пока самое большее к чему я пришел это

    FF 15 mem32 - Всё бы ничего но опкод 15 прыгает по значению в памяти а не по самой памяти, тоесть вот отладчике получается так

    CALL [mem32] ; =(

    пробовал другие значения, например 11,12 они для регистров, например call [eax] и так далее. Нигде в документации по опкодам не нашел инструкции относительно второго байта.
     
  9. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
  10. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    2FED
    Если я не ошибаюсь, это расширенный опкод инструкции. Многие инструкции, имеющие один операнд (или один операнд и непосредственное значение) кодируются так:

    db код операции
    db MOD(2 бита) OPCODE_EXTENSION(3 бита) RM(3 бита)
    ...
    Т.е. инструкция, имеющая непосредственный операнд так или иначе теряет одно поле в байте MODRM, поэтому поле reg этого байта используется как расширение кода операции. Т.е. на одном опкоде может сидеть несколько инструкций, а поле reg байта MODRM "уточняет", что это за инструкция. Например, на опкоде 0xFF сидят и абсолютный call и inc .
    'inc dword [eax]', например, будет выглядеть так:
    0xFF 00000000b
    Т.е. MOD = 0, REG, он же расширенный код операции = 0 RM = 0, что соотвествует eax.
    А 'call ecx' будет такой:
    0xFF 11010001
    MOD = 11b, REG = 010b, RM = 001b (ecx).

    Команды call, которая брала абсолютное смещение из самой инструкции нет, поэтому приходится пользоваться либо инструкцией 'call reg', либо 'call [mem]'.
     
  11. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Mika0x65
    Да ладно нет. А 9A на что? В WORD'e после 9A, правда, должен быть правильный селектор, а потом еще DWORD, указывающий абсолютное смещение.
    2FED
    А вообще для абсолютных переходов используется комбинация PUSH + RET: и на байт дешевле и удобнее. А если необходимо, чтобы адрес возврата обязательно был в стэке, то его предварительно можно забить туда.
     
  12. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    l_inc
    EDIT: А, нет, шлюз вызова не понадобится, т.к. нет перехода между кольцами привелегий.
    2FED
    Тогда дальний переход в помощь.
     
  13. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Mika0x65
    Какой еще шлюз вызова? Используется стандартный селектор кодового сегмента. Никто ж не собирается прыгать в нулевое кольцо.
    Блин. Опоздал. :)
     
  14. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    Спасибо всем, картина начала прояснятся =)

    ps Вот так вот кодишь себе не задумываясь, а как полезешь в недры так понимаешь что не всё так просто.