OldSchoolHack

Register / Login English

[C++] StackWalk


icon [C++] StackWalk #1

Join Date: Aug 2007

Posts: 8643

User-Rating:

199 positive
33 negative
Hallo,

wenn ihr bei Abstürzen eures Programms den Ablauf nachverfolgen wollt, hilft es ungemein, zu wissen, welche Funktion von wo aufgerufen wurde. Die managed Sprachen wie C# oder Java bieten dazu den CallStack an. Für C++ gibt es sowas direkt nicht, aber man kann sich ja helfen:

CPP Code:
  1. //StackWalk.h
  2. //KN4CK3R https://www.oldschoolhack.me
  3. //Credits: MSDN
  4.  
  5. #ifndef __STACKWALK_H__
  6. #define __STACKWALK_H__
  7.  
  8. #include <windows.h>
  9. #include <tchar.h>
  10. #include <list>
  11. #include <tlhelp32.h>
  12.  
  13. class StackWalk
  14. {
  15. private:
  16. class Module
  17. {
  18. public:
  19. DWORD adress;
  20. DWORD size;
  21. TCHAR name[256];
  22.  
  23. bool IsIn(DWORD address)
  24. {
  25. return address >= this->adress && address <= this->adress + size;
  26. }
  27. };
  28. //---------------------------------------------------------------------------
  29. void *stack[63];
  30. int stackSize;
  31. std::list<Module> moduleList;
  32. //---------------------------------------------------------------------------
  33. void GetModuleList()
  34. {
  35. MODULEENTRY32 module32;
  36. module32.dwSize = sizeof(MODULEENTRY32);
  37.  
  38. HANDLE snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
  39. if (snapShot != INVALID_HANDLE_VALUE)
  40. {
  41. if (Module32First(snapShot, &module32))
  42. {
  43. do
  44. {
  45. Module module;
  46. module.adress = (DWORD)module32.modBaseAddr;
  47. module.size = module32.modBaseSize;
  48. _tcscpy(module.name, module32.szModule);
  49.  
  50. moduleList.push_back(module);
  51.  
  52. } while (Module32Next(snapShot, &module32));
  53. }
  54. CloseHandle(snapShot);
  55. }
  56. }
  57. //---------------------------------------------------------------------------
  58. public:
  59. class StackFrame
  60. {
  61. private:
  62. DWORD address;
  63. DWORD offset;
  64. TCHAR moduleName[256];
  65.  
  66. public:
  67. StackFrame(DWORD address, DWORD offset, TCHAR *moduleName)
  68. {
  69. this->address = address;
  70. this->offset = offset;
  71. _tcscpy(this->moduleName, moduleName);
  72. }
  73. //---------------------------------------------------------------------------
  74. DWORD GetAddress()
  75. {
  76. return address;
  77. }
  78. //---------------------------------------------------------------------------
  79. DWORD GetOffset()
  80. {
  81. return offset;
  82. }
  83. //---------------------------------------------------------------------------
  84. TCHAR* GetModuleName()
  85. {
  86. return moduleName;
  87. }
  88. //---------------------------------------------------------------------------
  89. };
  90. //---------------------------------------------------------------------------
  91.  
  92. std::list<StackFrame> GetCallStack()
  93. {
  94. std::list<StackFrame> frames;
  95.  
  96. stackSize = RtlCaptureStackBackTrace(1, 63, stack, 0);
  97.  
  98. GetModuleList();
  99.  
  100. for (int i = 0; i < stackSize; ++i)
  101. {
  102. DWORD address = (DWORD)stack[i];
  103. for (std::list<Module>::iterator it = moduleList.begin(); it != moduleList.end(); it++)
  104. {
  105. Module module = *it;
  106. if (module.IsIn(address))
  107. {
  108. frames.push_back(StackFrame(address - 5, address - module.adress - 5, module.name));
  109.  
  110. break;
  111. }
  112. }
  113. }
  114.  
  115. return frames;
  116. }
  117. //---------------------------------------------------------------------------
  118. };
  119. //---------------------------------------------------------------------------
  120.  
  121. #endif

Als Beispiel, wie man die Klasse benutzen kann:

CPP Code:
  1. #include <windows.h>
  2. #include <iostream>
  3.  
  4. #include "StackWalk.h"
  5.  
  6. #if defined(UNICODE) || defined(_UNICODE)
  7. #define tcout wcout
  8. #else
  9. #define tcout cout
  10. #endif
  11.  
  12. void stack()
  13. {
  14. StackWalk swalk;
  15.  
  16. std::list<StackWalk::StackFrame> frames = swalk.GetCallStack();
  17.  
  18. for (std::list<StackWalk::StackFrame>::iterator it = frames.begin(); it != frames.end(); it++)
  19. {
  20. StackWalk::StackFrame frame = *it;
  21. std::tcout << frame.GetModuleName() << "!0x" << std::hex << frame.GetOffset() << " (0x" << frame.GetAddress() << ")" << std::endl;
  22. }
  23. }
  24. //---------------------------------------------------------------------------
  25. void func(int c)
  26. {
  27. if (c == 5)
  28. {
  29. stack();
  30. return;
  31. }
  32. func(++c);
  33. }
  34. //---------------------------------------------------------------------------
  35. int _tmain(int argc, TCHAR* argv[])
  36. {
  37. func(0);
  38.  
  39. return 0;
  40. }
  41. //---------------------------------------------------------------------------

Das Programm erzeugt zB diese Ausgabe:
Quote
StackTrace.exe!0x11d9f (0x1191d9f)
StackTrace.exe!0x12c94 (0x1192c94)
StackTrace.exe!0x12ca8 (0x1192ca8)
StackTrace.exe!0x12ca8 (0x1192ca8)
StackTrace.exe!0x12ca8 (0x1192ca8)
StackTrace.exe!0x12ca8 (0x1192ca8)
StackTrace.exe!0x12ca8 (0x1192ca8)
StackTrace.exe!0x12d00 (0x1192d00)
StackTrace.exe!0x1ab7a (0x119ab7a)
StackTrace.exe!0x1a9aa (0x119a9aa)
kernel32.dll!0x53c40 (0x772a3c40)
ntdll.dll!0x637f0 (0x773937f0)
ntdll.dll!0x637c3 (0x773937c3)

ModuleName!Offset (Moduladresse + Offset)

Ich werde die Klasse demnächst in meine Hacks einbauen. Sollte helfen dem Problem auf die Schliche zu kommen, warum die Hacks bei manchen Leuten nicht funktionieren.

greetz KN4CK3R

__________________

Hallo