не могу изменить машинный код call-a Вот например Код (Text): exitproc proc invoke ExitProcess,0 exitproc endp .... ; разрешаем запись push offset tmp push PAGE_EXECUTE_READWRITE push 8 push offset offfset call VirtualProtect mov eax,offfset mov ecx,exitproc mov dword ptr [eax+1],ecx offfset: call Mylstrlen Отладчик показывает что команда call Mylstrlen состоит из опкода E805010000(исправлено) , E8 это опкод call так? тогда что такое 05010000? ничо не пойму Бред какойто получается. Например с push-ем всё просто, первым байтом 68h, потом адрес 4 байта. А тут я не знаю что делать к стате с jmp та же фигня
я немного ошибся, там был опкод E805010000 сейчас попробовал поставить два вызова так Код (Text): call Mylstrlen ;Опкод E805010000 call exitproc ;Опкод E815010000 .... Mylstrlen proc s:dword .... ret Mylstrlen endp exitproc proc invoke ExitProcess,0 exitproc endp Если отнять от адреса функции смещение следующей инструкции то не сходится с тем что в опкоде, темболее откуда нам знать от какого адреса функции отнимать когда нам только предстоит это узнать?
2FED Еще как сходится. Для call Mylstrlen разница должна быть 105h. Для call exitproc разница - 115h. Кому "вам"? Если компилятору, то Вы сообщаете (явно или неявно) ему базу загрузки кода. А адреса остальных инструкций, функций, данных он просчитывает.
тоесть там байты перевёрнуты? получается 15 01 00 00 = 00 00 01 15 Получается мне надо сделать "Адрес - База" а потом его перевернуть и только после этого записывать в опкод.. правильно?
2FED Это называется не "перевернуты". Это один из основных принципов работы x86: младший байт по младшему адресу. И переворачивать его не надо. Т.е. если Вы хотите сформировать опкод, то просто высчитываете его, а потом записываете. В синтаксисе фасма это выглядит примерно так: Код (Text): jmp @F callOpcode db 0E8h callOffset dd 0 retLabel db 0C3h msgText db 'Text',0 msgCaption db 'Caption',0 @@: mov eax,[MessageBox] ;помещаем адрес MessageBoxA в eax sub eax,retLabel ;из адреса назначения прыжка вычитаем адрес старт (стартом является начало следующей инструкции) mov dword[callOffset],eax ;как видно, никакого переворота не нужно, т.к. x86 сразу записывает младший байт по младшему адресу push 0 \ push msgCaption \ push msgText > Пихаем параметры в стэк и прыгаем на только что сформированный call. push 0 / jmp callOpcode /
А как заколбасить обсолютную адресацию, у меня чото не выходит. пишу опкод 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] и так далее. Нигде в документации по опкодам не нашел инструкции относительно второго байта.
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]'.
Mika0x65 Да ладно нет. А 9A на что? В WORD'e после 9A, правда, должен быть правильный селектор, а потом еще DWORD, указывающий абсолютное смещение. 2FED А вообще для абсолютных переходов используется комбинация PUSH + RET: и на байт дешевле и удобнее. А если необходимо, чтобы адрес возврата обязательно был в стэке, то его предварительно можно забить туда.
l_inc EDIT: А, нет, шлюз вызова не понадобится, т.к. нет перехода между кольцами привелегий. 2FED Тогда дальний переход в помощь.
Mika0x65 Какой еще шлюз вызова? Используется стандартный селектор кодового сегмента. Никто ж не собирается прыгать в нулевое кольцо. Блин. Опоздал.
Спасибо всем, картина начала прояснятся =) ps Вот так вот кодишь себе не задумываясь, а как полезешь в недры так понимаешь что не всё так просто.