Этот пролог состоит из двух частей.
Настройка стекового кадра
Сохраняет текущий регистр EBP в стеке, а затем присваивает значение указателя стека (ESP) для EBP.
push ebp
mov ebp,esp
Если в стеке хранятся локальные переменные (т. Е. Недостаточно места в доступных регистрах), ESP будет перемещен на их размер для построения стекового кадра текущей функции.
И в конце функции вы увидите, что эти операции перевернуты, поэтому стековый фрейм предыдущей функции восстанавливается.
EBP всегда должен указывать на начало стекового фрейма текущей функции
ESP до конца (который имеет меньший адрес на x86, потому что стек растет вниз).
Это часть общих соглашений о вызовах, необходимая для развертывания стека при возникновении исключения. Это не специфично для .net и используется большинством соглашений о вызовах в windows / x86.
После настройки стекового кадра принято хранить некоторые регистры в стеке. Это потому, что вы можете использовать определенные регистры в качестве временных переменных, но соглашение о вызовах требует от вашей функции их сохранения. Таким образом, вы должны сохранить их в стеке. Какие регистры должны быть сохранены, а какие могут быть изменены, зависит от используемого соглашения о вызовах.
При обращении к локальным переменным в стеке вы можете использовать [ebp-x]
, где ebp
указывает на начало стекового кадра, а x - это смещение, которое указывает, где в стековом кадре хранится переменная. В качестве альтернативы вы можете использовать [esp+y]
со смещением от конца стекового кадра.
вызов статического конструктора / инициализатора
Как заметил danbystrom , вторая часть, скорее всего, является вызовом статического конструктора / инициализатора. Поскольку статический конструктор вызывается не при запуске программы, а при первом доступе, каждый доступ, для которого дрожание не может гарантировать, что статический конструктор уже выполнен, должен проверять, был ли он вызван, а затем вызывает его, если нет.
00000004 cmp dword ptr ds:[006914A4h],0
0000000b je 00000012
0000000d call 65CC36CF
Это что-то вроде if (globalVar!=0) Call Function_65CC36CF
. Где, скорее всего, глобальная переменная указывает, был ли запущен статический конструктор, а вызов - это вызов статического конструктора.
Насколько я знаю, ваши комментарии по разборке верны.
Проверьте эту запись блога OldNewThing на стековых фреймах: Как восстановить поврежденную трассировку стека: восстановление цепочки EBP