Привет всем, почитал статью: http://www.uinc.ru/articles/48/ и не понял там последний пункт "6. Против лома нет приема". Код (Text): ... процесс расшифровки кода ... push ereg/value push offset continue jmp dword ptr [xxxxxxxxh] ... ; мусорные инструкции ret ; прощай эмулятор ... continue: ... продолжение процесса расшифровки ... Неясно что происходит: 1) При выполнении jmp dword ptr [xxxxxxxxh] под эмулятором. В частности неясно, куда вернется управление и что будет со стеком? 2) При вызове инструкции ret, написано "прощай эмулятор", но в пометке к этому коду сказано: Если переход-таки произойдет (я так понял что на вершине стека под эмулятором в момент выполнения ret находится offset continue. еще я так понял что после исполнения jmp dword ptr [xxxxxxxxh] под эмулятором управление каким-то образом окажется на "... ; мусорные инструкции" - если это так то неясно совсем почему) то управление передастся туда куда нужно, на расшифровывающий цикл. Вообщем помогите пожалуйста разобраться где тут собака порылась!
Код (Text): CALL (CALL) Вызов процедуры или задачи Схема команды: call цель Назначение: передача управления близкой или дальней процедуре с запоминанием в стеке адреса точки возврата; Алгоритм работы определяется типом операнда: метка ближняя — в стек заносится содержимое указателя команд eip/ip и в этот же регистр загружается новое значение адреса, соответствующее метке; метка дальняя — в стек заносится содержимое указателя команд eip/ip и cs. Затем в эти же регистры загружаются новые значения адресов, соответствующие дальней метке; r16, 32 или m16, 32 — определяют регистр или ячейку памяти, содержащие смещения в текущем сегменте команд, куда передается управление. При передаче управления в стек заносится содержимое указателя команд eip/ip; указатель на память — определяет ячейку памяти, содержащую 4 или 6-байтный указатель на вызываемую процедуру. Структура такого указателя 2+2 или 2+4 байта. Интерпретация такого указателя зависит от режима работы микропроцессора: в реальном режиме — в зависимости от размера адреса (use16 или use32) первые два байта трактуются как сегментный адрес, вторые два/четыре байта, как смещение целевой метки передачи управления. В стеке запоминается содержимое регистров cs и eip/ip; в защищенном режиме — интерпретация цели передачи управления зависит от значения байта AR дескриптора, определяемого селекторной частью указателя. Целью здесь являются дальний вызов процедуры без изменения уровня привилегий, дальний вызов процедуры с изменением уровня привилегий или переключение задачи. Состояние флагов после выполнения команды (кроме переключения задачи): выполнение команды не влияет на флаги При переключении задачи значения флажков изменяются в соответствии с информацией о регистре eflags в сегменте состояния TSS задачи, на которую производится переключение. Применение: Как видно из описания алгоритма, команда call позволяет организовать гибкую и многовариантную передачу управления на подпрограмму с сохранением адреса точки возврата. Подробно типовые примеры использования рассмотрены на уроках 10 и 14. См. также: уроки 10, 14 и команду ret Код (Text): RET/RETF (RETurn/RETurn Far from procedure) Возврат ближний (дальний) из процедуры Схема команды: ret ret число Назначение: возврат управления из процедуры вызывающей программе. Работа команды зависит от типа процедуры: для процедур ближнего типа — восстановить из стека содержимое eip/ip; для процедур дальнего типа — последовательно восстановить из стека содержимое eip/ip и сегментного регистра cs. если команда ret имеет операнд, то увеличить содержимое esp/sp на величину операнда число; при этом учитывается атрибут режима адресации — use16 или use32: если use16, то sp=(sp+число), то есть указатель стека сдвигается на число байт, равное значению число; если use32, то sp=(sp+2*число), то есть указатель стека сдвигается на число слов, равное значению число. Состояние флагов после выполнения команды: выполнение команды не влияет на флаги Применение: Команду ret необходимо применять для возврата управления вызывающей программе из процедуры, управление которой было передано по команде call. На самом деле микропроцессор имеет три варианта команды возврата ret - это ret, ее синоним retn, а также команда retf. Они отличаются типами процедур, в которых используются. Команды ret и retn служат для возврата из процедур ближнего типа. Команда retf — команда возврата для процедур дальнего типа. Какая конкретно команда будет использоваться, определяется компилятором; программисту лучше использовать команду ret и доверить транслятору самому сгенерировать ее ближний или дальний вариант. Количество команд ret в процедуре должно соответствовать количеству точек выхода из нее. Некоторые языки высокого уровня, к примеру Pascal, требуют, чтобы вызываемая процедура очищала стек от переданных ей параметров. Для этого команда ret содержит необязательный параметр число, который, в зависимости от установленного атрибута размера адреса, означает количество байт или слов, удаляемых из стека по окончании работы процедуры. Проще говоря, разберись с тем, что выполняют комманды call и ret - Тогда все 3 вопроса отпадут сами собой.
Magnum я все это знаю >>Проще говоря, разберись с тем, что выполняют комманды call и ret - Тогда все 3 вопроса отпадут сами собой. Ты лучше вопрос мой перечитай. Грубо говоря если лень читать все что я написал - в чем отличие исполнения этого фрагмента эмулятором и процессором?
2FED, что значит обходит? По-просту игнорирует? Почему, какой тогда смысл в этом эмуляторе? Кроме того в силе остается вопрос о передаче управления ret'ом, если он просто проигнорил джамп, то на вершине стека находится адрес цикла дешифровки и по идее программа будет работать дальше корректно
Старые эмуляторы не могли корректно эмулировать вызовы АПИ Управление возвращалось на инструкцию, следующую за кэлом/джампом. Но это было давно. Очень давно. Сейчас этот метод не работает. Инструкция ret находится внутри АПИ-функции, которую старый эмулятор эмулировать не мог. А значит инструкция ret отработать никак не могла. Вместо эмуляции тела апи, использовались танцы с бубном.
Грубо говоря, вот вот так эмулировался вызов АПИ mov eax, some_value ;то что обычно возвращает функция add esp, xxxxh ;выталкивание аргументов из стека jmp ....... ;прыжок на следующую за кэлом/джампом инструкцию
а вот теперь уже я нифига не понял, тут то не про старые эмуляторы статья. и действительно по рету( там где прощай эмулятор ) оно вернётся на оффсет( Continue: ) в стеке, если только не сделать перед этим ретом что то типо pop eax
==================================================== ==================================================== ==================================================== ==================================================== Если этот ret будет вызван. А старые эмуляторы до рета внутри апишек не добирались.
Видимо имеется ввиду что стек, включая адрес возврата очищается строчкой add esp, xxxxh, а джамп jmp ....... передает управление на "... ; мусорные инструкции", что вообщем-то действительно звучит нелогично, но м.б. Магнум просто прошарен в этой теме и значит так оно и было. если все и правда так, то на вершине стека уже не лежит оффсет на continue и значит управление ret'ом передастся неизвестно куда. Верно?
Novi4ek джамп передает управление на инструкцию, следующую за вызовом апи. Точнее передавал. Лет 5 назад. В нашем случае - это мусорные инструкции. Задача эмуляторов тех времен - раскрутить простые декрипторы, в которых не использовался вызов АПИ. аля вариации Код (Text): decryptor: lodsd xor eax, some_key stosd loop decryptor и аналогичные им. А таких тогда было большинство.
Потому что согласно коду Магнума, вместо ret'а внутри "псевдоAPI функции" используется джамп, значит адрес возврата им уже учтен.
ЗЫ: если нужно обойти современные эмуляторы - читайте блог Osen-а Стиль изложения грязный, но идеи толковые. И реализуется намного проще игры с сегментными регистрами.