-
Скажите, есть ли возможность получить стек вызовов (call stack) для другого процесса (основной поток). Если этот процесс запущен с флагом отладки и находится в остановленном состоянии?
Нашел в JEDI Code Library функции для работы со стеком. но они похоже работают лишь внутри вызывающего процесса.
-
Есть. Руссинович в Process Explorer получает, но детали мне неизвестны
-
Разворачивать стек нужно через контекст нити из которой вытаскивай указатель на фрейм стека EBP, текущий указатель на вершину стека ESP и собственно адрес некущей инструкции, где мы остановили нить EIP (на нее можно ориентироваться в случае трассирования кода с целью поиска инструкций, манипулирующих с ESP). Соответственно разбирай фреймы, выбирая из них адреса возврата. Вот эта статья может помочь: http://www.codeproject.com/KB/threads/StackWalker.aspx
-
>Rouse_
Спасибо за идею. Функция StackWalk работает, навигация по стеку вызовов происходит. Но есть 2 проблемы:
1. Функция StackWalk для стека вызовов больше 3-х фреймов пропускает тот, что на вершине стека. Выдает адрес возврата для предыдущей функции не для текущей. При этом работает верно если задать текущий адрес не из EIP, а указать 0. Однако для других случаев 0 не срабатывает.
2. Функция StackWalk64 в ImageHlp.pas не объявлена, хотя в статье рекомендуется использовать именно ее. Объявил сам аналогично StackWalk параметры судя по MSDN правильны (хотя там не нашел даже упоминания про StackWalk, описана лишь StackWalk64) однако объявленная мною функция вызывает исключение.
Вобщем, путаница со StackWalk и StackWalk64. Еще непонятно зачем эти 2 функции экспортируются и в dbghelp.dll и в imagehlp.dll.
-
Ты используй именно StackWalk64, т.к. StackWalk устарела, просто указывай IMAGE_FILE_MACHINE_I386 для 32-битных платформ. Почему декларация в двух библиотеках: imagehlp - устаревшая библиотека и присутствует только в целях совместимости со старым ПО, это просто врапер на dbghelp - которая повяилась начиная с W2K. Вот тебе декларация, проверь со своей: type
HANDLE = THandle;
PVOID = Pointer;
DWORD64 = Int64;
ADDRESS_MODE = (
AddrMode1616,
AddrMode1632,
AddrModeReal,
AddrModeFlat);
TAddressMode = ADDRESS_MODE;
LPADDRESS64 = ^ADDRESS64;
_tagADDRESS64 = record
Offset: DWORD64;
Segment: WORD;
Mode: ADDRESS_MODE;
end;
ADDRESS64 = _tagADDRESS64;
TAddress64 = ADDRESS64;
PAddress64 = LPADDRESS64;
PKDHELP64 = ^KDHELP64;
_KDHELP64 = record
Thread: DWORD64;
ThCallbackStack: DWORD;
ThCallbackBStore: DWORD;
NextCallback: DWORD;
FramePointer: DWORD;
KiCallUserMode: DWORD64;
KeUserCallbackDispatcher: DWORD64;
SystemRangeStart: DWORD64;
Reserved: array [0..7] of DWORD64;
end;
KDHELP64 = _KDHELP64;
TKdHelp64 = KDHELP64;
LPSTACKFRAME64 = ^STACKFRAME64;
_tagSTACKFRAME64 = record
AddrPC: ADDRESS64; AddrReturn: ADDRESS64; AddrFrame: ADDRESS64; AddrStack: ADDRESS64; AddrBStore: ADDRESS64; FuncTableEntry: PVOID; Params: array [0..3] of DWORD64; Far: BOOL; Virtual: BOOL; Reserved: array [0..2] of DWORD64;
KdHelp: KDHELP64;
end;
STACKFRAME64 = _tagSTACKFRAME64;
TStackFrame64 = STACKFRAME64;
PStackFrame64 = LPSTACKFRAME64;
PREAD_PROCESS_MEMORY_ROUTINE64 = function (hProcess: HANDLE; qwBaseAddress: DWORD64;
lpBuffer: PVOID; nSize: DWORD; var lpNumberOfBytesRead: DWORD): BOOL; stdcall;
PReadProcessMemoryRoutine64 = PREAD_PROCESS_MEMORY_ROUTINE64;
PFUNCTION_TABLE_ACCESS_ROUTINE64 = function (hProcess: HANDLE;
AddrBase: DWORD64): PVOID; stdcall;
PFunctionTableAccessRoutine64 = PFUNCTION_TABLE_ACCESS_ROUTINE64;
PGET_MODULE_BASE_ROUTINE64 = function (hProcess: HANDLE;
Address: DWORD64): DWORD64; stdcall;
PGetModuleBaseRoutine64 = PGET_MODULE_BASE_ROUTINE64;
PTRANSLATE_ADDRESS_ROUTINE64 = function (hProcess: HANDLE; hThread: HANDLE;
const lpaddr: ADDRESS64): DWORD64; stdcall;
PTranslateAddressRoutine64 = PTRANSLATE_ADDRESS_ROUTINE64;
function StackWalk64(MachineType: DWORD; hProcess: HANDLE; hThread: HANDLE;
var StackFrame: STACKFRAME64; ContextRecord: PVOID;
ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64;
FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64;
GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64;
TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64): BOOL; stdcall;
external 'dbghelp.dll'
-
Спасибо за код, теперь функция исключения не вызывает. Но все равно не работает. Хотя возвращает TRUE. Однако Винда говорит об ошибке 203 - системе не удается найти указанный параметр среды. Привожу код. function ReadProcMem64(hProcess: HANDLE; qwBaseAddress: DWORD64;
lpBuffer: PVOID; nSize: DWORD; var lpNumberOfBytesRead: DWORD): BOOL; stdcall;
begin
Result := ReadProcessMemory(hProcess, Pointer(qwBaseAddress),
lpBuffer, nSize, lpNumberOfBytesRead);
end;
function GetImgBase64(hProcess: HANDLE; Address: DWORD64): DWORD64; stdcall;
begin
Result := $400000; end;
begin
...
FillChar(StackFrame64, SizeOf(StackFrame64), 0);
StackFrame64.AddrPC.Offset := FLastBreakAddr;
StackFrame64.AddrPC.Mode := DbgHelp.AddrModeFlat;
StackFrame64.AddrFrame.Offset := Context.Ebp;
StackFrame64.AddrFrame.Mode := DbgHelp.AddrModeFlat;
StackFrame64.AddrStack.Offset := Context.Esp;
StackFrame64.AddrStack.Mode := DbgHelp.AddrModeFlat;
res := StackWalk64(IMAGE_FILE_MACHINE_I386, FProcInfo.hProcess, FProcInfo.hThread,
@StackFrame64, @Context, ReadProcMem64, nil, GetImgBase64, nil); В StackFrame64.AddrReturn.Offset после вызова функции записано значение StackFrame64.AddrPC.Offset. Ты использовал StackWalk64 в своих проектах?
-
Как то у тебя параметры отличаются от тех которые я привел, во вторых предпоследним параметром должен идти адресу функции SymGetModuleBase64, которую экспортирует dbghelp, прочти еще раз внимательней справку по StackWalk64. В догонку вот тебе самый простейший шаблон: http://www.rsdn.ru/forum/src/1342099.1.aspx
-
Rouse_ спасибо за помощь.
-
Удалено модератором
|