Как получить адрес основного указателя вершины стека

В дополнение к инструментам рефакторинга и управления исходным кодом, перечисленным здесь, , AQTime является великим профилировщиком окон. Это может работать как плагин или автономный, и это работает с.NET и собственным кодом.

16
задан jww 9 March 2019 в 03:50
поделиться

4 ответа

Правильнее всего было бы переписать все, что делает эта функция, так, чтобы она не требовала доступа к фактическому указателю кадра. Это определенно плохое поведение.

Но для того, чтобы делать то, что вы ищете, вы должны уметь:

int CallStackSize() {
    __int64 Frame = 0; /* MUST be the very first thing in the function */
    PDWORD pFrame;

    Frame++; /* make sure that Frame doesn't get optimized out */

    pFrame = (PDWORD)(&Frame);
    /*... do stuff with pFrame here*/
}

Причина, по которой это работает, заключается в том, что в C обычно первое, что делает функция - это сохраняет местоположение базовый указатель (EBP) перед выделением локальных переменных. Создавая локальную переменную (Frame), а затем получая адрес if, мы действительно получаем адрес начала фрейма стека этой функции.

Примечание: некоторые оптимизации могут привести к удалению переменной «Frame». Вероятно, нет, но будьте осторожны.

Второе примечание: Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель, и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

re действительно получает адрес начала фрейма стека этой функции.

Примечание: некоторые оптимизации могут привести к удалению переменной "Frame". Вероятно, нет, но будьте осторожны.

Второе примечание: Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель, и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

re действительно получает адрес начала фрейма стека этой функции.

Примечание: некоторые оптимизации могут привести к удалению переменной "Frame". Вероятно, нет, но будьте осторожны.

Второе примечание: Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

Некоторые оптимизации могли привести к удалению переменной "Frame". Вероятно, нет, но будьте осторожны.

Второе примечание: Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

Некоторые оптимизации могли привести к удалению переменной "Frame". Вероятно, нет, но будьте осторожны.

Второе примечание: Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

Ваш исходный код, а также этот код манипулируют данными, на которые указывает «pFrame», когда сам «pFrame» находится в стеке. Здесь можно случайно перезаписать pFrame, и тогда у вас будет плохой указатель и может возникнуть странное поведение. Особенно помните об этом при переходе с x86 на x64, потому что pFrame теперь составляет 8 байтов вместо 4, поэтому, если ваш старый код «делать что-то с pFrame» учитывал размер Frame и pFrame до того, как возиться с памятью, вы необходимо учитывать новый, больший размер.

13
ответ дан 30 November 2019 в 21:19
поделиться

Вы можете использовать внутреннюю функцию _AddressOfReturnAddress () для определения местоположения в указателе текущего кадра, предполагая, что он не был полностью оптимизирован. Я предполагаю, что компилятор не позволит этой функции оптимизировать указатель кадра, если вы явно на него ссылаетесь. Или, если вы используете только один поток, вы можете использовать IMAGE_NT_HEADER.OptionalHeader.SizeOfStackReserve и IMAGE_NT_HEADER.OptionalHeader.SizeOfStackCommit для определения размера стека основного потока. См. this , чтобы узнать, как получить доступ к IMAGE_NT_HEADER для текущего изображения.

Я бы также не рекомендовал использовать IsBadWritePtr для определения конца стека. По крайней мере, вы, вероятно, заставите стек расти, пока не достигнете резерва, так как вы откроете страничку. Если вы действительно хотите узнать текущий размер стека, используйте VirtualQuery с адресом, который вы проверяете.

А если исходное использование - обход стека, вы можете использовать StackWalk64 за это.

7
ответ дан 30 November 2019 в 21:19
поделиться

Если вам нужен точный «базовый указатель», то единственный выход - встроенная сборка.

Удивительно, но возможно написать код, который изменяет стек с относительно небольшим количеством кода для конкретной платформы, но трудно полностью избежать сборки (в зависимости от того, что вы делаете).

Если все, что вы пытаетесь сделать, это чтобы избежать переполнения стека, вы можете просто взять адрес любой локальной переменной.

1
ответ дан 30 November 2019 в 21:19
поделиться
.code

PUBLIC getStackFrameADDR _getStackFrameADDR
getStackFrameADDR:
    mov RAX, RBP
    ret 0

END

Что-то подобное может сработать для вас.

Скомпилируйте его с помощью ml64 или jwasm и вызовите его, используя это в своем коде extern "C" void getstackFrameADDR (void);

1
ответ дан 30 November 2019 в 21:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: