Всем привет!
Столкнулся с проблемой, что
Здесь значения в поле "Frame[3]" это адрес-возврата после вызова
Столкнулся с проблемой, что
RtlCaptureStackBackTrace() из Kernel32.dll всегда возвращает одинаковое значение - это так задумано, или есть нюансы? На х64 всегда получаю всего 1 фрейм с текущим адресом-возврата, а на х32 через WOW уже 3 фрейма. При этом такое впечатление, что значения где-то кэшируются, т.к. если вызываю одну и ту же процедуру из разных мест своего-же кода, значение фремов всегда одинаковые. Система 64-бит Win7, пишу на ассемблере FASM, вот исходник (в скрепке ехе для тестов). Может кто сталкивался с подобным?
C-подобный:
format pe console
include 'win32ax.inc'
entry start
;//-----------
section '.data' data readable writeable
struct IMAGEHLP_SYMBOL
SizeOfStruct dd sizeof.IMAGEHLP_SYMBOL
Address dd 0
Size dd 0
Flags dd 0
MaxNameLen dd 128
Name rb 128
ends
pSymInfo IMAGEHLP_SYMBOL
pHandle dd 0
count dd 0
stacks dd 32 dup(0)
;//-----------
section '.text' code readable executable
start: invoke GetCurrentProcessId
invoke OpenProcess,PROCESS_ALL_ACCESS,0,eax
mov [pHandle],eax
invoke SymInitialize,eax,0,1
invoke RtlCaptureStackBackTrace,0,32,stacks,0 ;//<----- Запрашиваю 32 кадра от текущего(0),
mov [count],eax ;//<----------------------- а возвращается макс 3
call PrintStackTrace
invoke GetTickCount
invoke RtlCaptureStackBackTrace,0,32,stacks,0
mov [count],eax
call PrintStackTrace
invoke GetModuleHandle,<'user32.dll',0>
invoke RtlCaptureStackBackTrace,0,32,stacks,0
mov [count],eax
call PrintStackTrace
@exit: cinvoke _getch
cinvoke exit,0
;//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
align 8
proc PrintStackTrace
mov eax,[count]
cmp eax,32
ja @fuck
push eax
cinvoke printf,<10,10,' Found stack frames: %d',0>,eax
pop ecx
mov esi,stacks
@@: push ecx esi esi
invoke SymGetSymFromAddr,[pHandle],dword[esi],0,pSymInfo
lea ebx,[pSymInfo.Name]
pop esi
cinvoke printf,<10,' Frame[%d]: 0x%08x %s',0>,[count],dword[esi],ebx
pop esi ecx
add esi,4
dec [count]
loop @b
;//----- Зачистить структуру и буфер для сл.вызова -------
mov [count],0
mov ecx,sizeof.IMAGEHLP_SYMBOL -4
mov edi,pSymInfo
add edi,4
xor al,al
rep stosb
mov dword[pSymInfo.MaxNameLen],128
mov edi,stacks
mov ecx,32/4
rep stosd
@fuck: ret
endp
;//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
section '.idata' import data readable writeable
library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',\
dbghelp,'dbghelp.dll',user32,'user32.dll'
import dbghelp,SymInitialize,'SymInitialize',SymGetSymFromAddr,'SymGetSymFromAddr'
include 'api\msvcrt.inc'
include 'api\kernel32.inc'
include 'api\user32.inc'
Здесь значения в поле "Frame[3]" это адрес-возврата после вызова
RtlCaptureStackBackTrace(), что совпадает с адресом инструкций mov [count],eax в коде. Как видно, хоть RetAddr и разный, остальные 2 указателя во-всех вызовах совпадают, при этом всегда макс(3) фрейма, хотя если запросить вместо 32 всего два фрейма, то возвращаются 2. Почему так, не могу сообразить. Кстати из Kernel32.dll функция форвардится в Ntdll, и я без результатно пробовал звать её напрямую.