int test_vmp_stk(int arg)
{
int loc[2];
loc[arg - 0x0B] = 0x50;
return arg + loc[0];
}
int main()
{
int x = test_vmp_stk(0x0B);
printf("Test stk (ret = 0x%08x) \n", x);
return 0;
}
По коду видно, что в консоль должно всегда выводится число 0x0000005B.
Так вот после виртуализации функции test_vmp_stk программа выдаёт некорректные значения (случайные).
И где в C-коде чтение ниже “границы стека” ? Укажите на некорректную строчку кода.
Вы не правы.
Инструкция sub esp, XXX не определяет “границу стека”. Граница стека будет тогда, когда функцию пишет человек на асме (для этого он оформляет пролог и эпилог).
Но код функции может быть сгенерирован с использованием СУПЕР ПУПЕР оптимизации, когда значение регистра esp не изменяется явно, а значение ebp не используется для хранения этой “границы стека”.
Вот более корректное написание ЧУДО функции:
int test_vmp_stk(int arg)
{
int loc[2];
loc[arg & 0x80000000] = 0x50;
return arg + loc[0];
}
Вы лучше напишите где вы прочитали о том, что функция не имеет права обращаться к памяти, расположенной ниже “границы стека” ?
Хотя сама функция постоянно меняет эту границу.
не имеет вызовов других функций (инструкции call отсутствуют);
не нуждается в хранении на стеке временных данных (регистров вполне хватает);
имеет несколько локальных переменных (для них не хватило регистров).
Так вот этой функции совсем не нужно изменять “границу стека”.
Конечно вы можете сказать что это сферический конь в вакууме. И отчасти вы будете правы, т.к. я не знаю компиляторов, которые в этом случае не будут использовать инструкцию sub esp, XXX
Хотя, выше описанная функция test_vmp_stk очень похожа на описанного коня.
Да и можно представить ситуацию, когда в компилятор VS2016 добавят такую вот оптимизацию, и тогда автор протектора должен будет всем советовать отключить эту оптимизацию.