Конференция "WinAPI" » Стек вызовов
 
  • Unknown user © (02.06.09 13:37) [0]
    Скажите, есть ли возможность получить стек вызовов (call stack) для другого процесса (основной поток). Если этот процесс запущен с флагом отладки и находится в остановленном состоянии?

    Нашел в JEDI Code Library функции для работы со стеком. но они похоже работают лишь внутри вызывающего процесса.
  • Игорь Шевченко © (02.06.09 14:59) [1]
    Есть. Руссинович в Process Explorer получает, но детали мне неизвестны
  • Rouse_ © (02.06.09 16:28) [2]
    Разворачивать стек нужно через контекст нити из которой вытаскивай указатель на фрейм стека EBP, текущий указатель на вершину стека ESP и собственно адрес некущей инструкции, где мы остановили нить EIP (на нее можно ориентироваться в случае трассирования кода с целью поиска инструкций, манипулирующих с ESP). Соответственно разбирай фреймы, выбирая из них адреса возврата.
    Вот эта статья может помочь: http://www.codeproject.com/KB/threads/StackWalker.aspx
  • Unknown user © (03.06.09 11:25) [3]
    >Rouse_

    Спасибо за идею. Функция StackWalk работает, навигация по стеку вызовов происходит. Но есть 2 проблемы:

    1. Функция StackWalk для стека вызовов больше 3-х фреймов пропускает тот, что на вершине стека. Выдает адрес возврата для предыдущей функции не для текущей. При этом работает верно если задать текущий адрес не из EIP, а указать 0. Однако для других случаев 0 не срабатывает.

    2. Функция StackWalk64 в ImageHlp.pas не объявлена, хотя в статье рекомендуется использовать именно ее. Объявил сам аналогично StackWalk параметры судя по MSDN правильны (хотя там не нашел даже упоминания про StackWalk, описана лишь StackWalk64) однако объявленная мною функция вызывает исключение.

    Вобщем, путаница со StackWalk и StackWalk64. Еще непонятно зачем эти 2 функции экспортируются и в dbghelp.dll и в imagehlp.dll.
  • Rouse_ © (03.06.09 13:06) [4]
    Ты используй именно 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
       //
       // address of kernel thread object, as provided in the
       // WAIT_STATE_CHANGE packet.
       //
       Thread: DWORD64;
       //
       // offset in thread object to pointer to the current callback frame
       // in kernel stack.
       //
       ThCallbackStack: DWORD;
       //
       // offset in thread object to pointer to the current callback backing
       // store frame in kernel stack.
       //
       ThCallbackBStore: DWORD;
       //
       // offsets to values in frame:
       //
       // address of next callback frame
       NextCallback: DWORD;
       // address of saved frame pointer (if applicable)
       FramePointer: DWORD;
       //
       // Address of the kernel function that calls out to user mode
       //
       KiCallUserMode: DWORD64;
       //
       // Address of the user mode dispatcher function
       //
       KeUserCallbackDispatcher: DWORD64;
       //
       // Lowest kernel mode address
       //
       SystemRangeStart: DWORD64;
       Reserved: array [0..7] of DWORD64;
     end;
     KDHELP64 = _KDHELP64;
     TKdHelp64 = KDHELP64;

     LPSTACKFRAME64 = ^STACKFRAME64;
     _tagSTACKFRAME64 = record
       AddrPC: ADDRESS64; // program counter
       AddrReturn: ADDRESS64; // return address
       AddrFrame: ADDRESS64; // frame pointer
       AddrStack: ADDRESS64; // stack pointer
       AddrBStore: ADDRESS64; // backing store pointer
       FuncTableEntry: PVOID; // pointer to pdata/fpo or NULL
       Params: array [0..3] of DWORD64; // possible arguments to the function
       Far: BOOL; // WOW far call
       Virtual: BOOL; // is this a virtual frame?
       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'

  • Unknown user © (03.06.09 16:25) [5]
    Спасибо за код, теперь функция исключения не вызывает. Но все равно не работает. Хотя возвращает 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 в своих проектах?
  • Rouse_ © (03.06.09 18:20) [6]
    Как то у тебя параметры отличаются от тех которые я привел, во вторых предпоследним параметром должен идти адресу функции SymGetModuleBase64, которую экспортирует dbghelp, прочти еще раз внимательней справку по StackWalk64.
    В догонку вот тебе самый простейший шаблон: http://www.rsdn.ru/forum/src/1342099.1.aspx
  • Unknown user © (04.06.09 19:12) [7]
    Rouse_ спасибо за помощь.
  • DeedeledFlank (27.07.09 23:44) [8]
    Удалено модератором
 
Конференция "WinAPI" » Стек вызовов
Есть новые Нет новых   [134434   +27][b:0][p:0.003]