使用windbug调试内存问题的时候有的时候需要查看变量的值,
下面我们通过一个例子来总结一下相关的指令使用。
#include <windows.h>
#include <stdio.h>include <conio.h>
VOID SimulateMemoryCorruption();
class CAppInfo
{
public:
CAppInfo( LPWSTR wszAppName, LPWSTR wszVersion)
{
m_wszAppName = wszAppName;
m_wszVersion = wszVersion;
}
VOID PrintAppInfo()
{
wprintf(L"\nFull application Name: %s\n", m_wszAppName);
wprintf(L"Version: %s\n", m_wszVersion);
}
private:
LPWSTR m_wszAppName;
LPWSTR m_wszVersion;
};
CAppInfo* g_AppInfo;
int __cdecl wmain(int argc, WCHAR* args[])
{
wint_t iChar = 0;
const wchar_t* myName = L"MyAppName";
const wchar_t* myVersion = L"1.0";
g_AppInfo = new CAppInfo(const_cast<LPWSTR>(myName), const_cast<LPWSTR>(myVersion));
if (!g_AppInfo)
{
return 1;
}
wprintf(L"Press: \n");
wprintf(L" 1 To display application information\n");
wprintf(L" 2 To simulated memory corruption\n");
wprintf(L" 3 To exit\n\n\n>");
while ((iChar = _getwche()) != '3')
{
switch (iChar)
{
case '1':
g_AppInfo->PrintAppInfo();
break;
case '2':
SimulateMemoryCorruption();
wprintf(L"\nMemory Corruption completed\n");
break;
default:
wprintf(L"\nInvalid option\n");
}
wprintf(L"\n\n> ");
}
return 0;
}
VOID SimulateMemoryCorruption()
{
const char* pszWrite = "Corrupt";
BYTE* p = (BYTE*)g_AppInfo;
CopyMemory(p, pszWrite, strlen(pszWrite));
}
编译以后生成exe和pdb 文件(在debug模式下编译)
添加好符号路径,然后使用windbg 来启动exe 程序
当第二次输入1的时候会发生异常,windbg会捕获一个异常
可以看出异常处的的地址 ds:002b:72726f43=??? 里面的内容有问题。用指令查看堆栈的调用情况
从里面可以看到windbgTest1!CAppInfo::PrintAppInfo+0x3a 地址处出现了问题,从源代码中可以看到问题的异常似乎和m_wszAppName,m_wszVersion两个参数有关。
VOID PrintAppInfo()
{
wprintf(L"\nFull application Name: %s\n", m_wszAppName);
wprintf(L"Version: %s\n", m_wszVersion);
}
指令取出 CAppInfo* g_AppInfo ,变量的地址
然后查看里面的参数:
接在需要查看0x72726f43 和0x00747075 两处的内存中的内容
查看g_AppInfo 实例的内存布局
我们以文本的格式查看内存处的内容
似乎 g_AppInfo 类对象的实例被字符串“Corrupt ”覆盖了
const char* pszWrite = "Corrupt";
BYTE* p = (BYTE*)g_AppInfo;
CopyMemory(p, pszWrite, strlen(pszWrite));
这一段代码正好就是覆盖了这个部分。
备注:
类CAppInfo包含两个LPWSTR(长指针到宽字符)类型的私有成员变量m_wszAppName和m_wszVersion,以及一个构造函数和一个公有成员函数PrintAppInfo。由于LPWSTR在Windows平台上通常是一个指向宽字符(即wchar_t)的指针,它的大小在32位系统上通常是4字节(指针大小)。因此,每个LPWSTR成员将占用4字节。此外,由于PrintAppInfo成员函数不占用类的实例内存(它们通常存储在代码段中),因此它们在类的内存布局中不占用空间。