gh0st错误修改
2016-05-17 18:45
399 查看
SetPaneText 的崩溃问题
WSAIoctl 参数类型导致栈异常
CIniFile 构造函数导致异常
栈上对象多线程析构函数导致程序崩溃
开始看 gh0st 源码,找来了一份比较纯净的官方代码来读,有点抓狂,听说使用很老的VC6.0写的,现在需要用 VS2010 重新创建工程,并拷贝代码过去,编译,分析整个执行流程,调试每一个遇到的bug,在这过程中学到了很多,记录下来,供后来参考:
关于状态栏StatusBar有几点需要说明:
1)刚刚创建工程 CMainFrame 类里面就有一个
2)在这个类的 OnCreate 函数里面调用
3)关于 CMFCStatusBar 使用方法可见 鸡啄米专栏 VS2010/MFC编程入门之三十八(状态栏的使用详解) 。
4)gh0st里面是这样使用
当异常的时候调用栈如下:
![](https://img-blog.csdn.net/20160517174938771)
跟踪到异常位置来到系统代码:
总之一句话,这个 SetPaneText 是从其它线程 ListenThreadProc 调用过来的,如果要正常使用可以修改为如下方式 :
g_pFrame 是一个 CMainFrame 类型指针,在CMainFrame 类里面加入一个消息处理过程:
在 ListenThreadProc 向 CMainFrame 类发送一个消息 PostMessage(UpdatePane),然后在 CMainFrame 类里面处理这个消息,至此问题完美解决。
参考:
MFC中从一个类向其他类发送消息的方法
WSAIoctl 原型声明如下:
倒数第三个参数应当是 LPDWORD 类型,而且是输出,传入的仅仅是char类型,虽然因为对齐 char 也分配了4字节,不会导致栈覆盖,但是在debug模式下系统加入了严苛的栈检测机制:虽然分配了四字节,因为是char类型,所以剩余的三字节是不应该修改的,在release下就没有这问题。
修改为 LONG 类型即可解决问题:
这个构造函数应该是在最早执行的,在 ChostApp 里面有一个成员
所以要首先调用 CIniFile 的构造函数
因为 AfxGetInstanceHandle() 调用导致异常。
具体可见CSDN论坛讨论。
在server端点击桌面管理可以正常显示被控端桌面,然后关闭远程桌面,此时被控端出现一个错误:
TestDll.exe 中的 0x5950cc6f (server.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x02ecfca4 时发生访问冲突
此时执行到的指令位置是 5950CC6F
对应的源代码是
寄存器edx的数值是
奇怪的是在关闭远程桌面以前这个函数执行了很多次,都没有出现这个问题。现在在关闭远程桌面之后就这样。通过对比发现 出现访问异常的内存 在关闭远程桌面之后数值出现了变化。
可以在关闭远程桌面之后 vs2010下内存访问断点,edx + 4 的位置
此时按F5发现中断在manager类的析构函数里面:
再看堆栈窗口 是从 Loop_ScreenManager 函数结尾调用而来的:
这样就大概分析出执行流程:
在上面函数中定义了一个CScreenManager类的对象manager,这个对象在栈中。CScreenManager基类是 CManager
当在主控端把远程桌面关闭之后run_event_loop 会返回,这样这个函数也就返回了,对象manager也就开始调用自己的析构函数,以前能访问的现在也就不能访问了。 所以就会出现上面的问题。
其实在运行的时候CScreenManager类的构造函数中创建了2个线程ControlThread ,WorkThread,当正常运行没有调试器中断的时候当函数 Loop_ScreenManager 执行完之后ControlThread 这个线程还未完全退出,不知道这样会产生什么意外后果??
经过试验在 函数 Loop_ScreenManager结束之前加入 sleep(20) 可以解决这个问题。
注:14年有段时间看过这个源码,发现了这个问题,发表在看雪论坛。这里转载过来。
WSAIoctl 参数类型导致栈异常
CIniFile 构造函数导致异常
栈上对象多线程析构函数导致程序崩溃
开始看 gh0st 源码,找来了一份比较纯净的官方代码来读,有点抓狂,听说使用很老的VC6.0写的,现在需要用 VS2010 重新创建工程,并拷贝代码过去,编译,分析整个执行流程,调试每一个遇到的bug,在这过程中学到了很多,记录下来,供后来参考:
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); }
当异常的时候调用栈如下:
跟踪到异常位置来到系统代码:
// 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); }
总之一句话,这个 SetPaneText 是从其它线程 ListenThreadProc 调用过来的,如果要正常使用可以修改为如下方式 :
void CALLBACK CMainFrame::NotifyProc(LPVOID lpParam, ClientContext *pContext, UINT nCode) { g_pFrame->PostMessageA(UpdatePane); }
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; }
在 ListenThreadProc 向 CMainFrame 类发送一个消息 PostMessage(UpdatePane),然后在 CMainFrame 类里面处理这个消息,至此问题完美解决。
参考:
MFC中从一个类向其他类发送消息的方法
WSAIoctl 参数类型导致栈异常
以前gh0st代码如下:const char chOpt = 1; WSAIoctl ( pContext->m_Socket, SIO_KEEPALIVE_VALS, &klive, sizeof(tcp_keepalive), NULL, 0, (unsigned long *)&chOpt, 0, NULL );
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 );
倒数第三个参数应当是 LPDWORD 类型,而且是输出,传入的仅仅是char类型,虽然因为对齐 char 也分配了4字节,不会导致栈覆盖,但是在debug模式下系统加入了严苛的栈检测机制:虽然分配了四字节,因为是char类型,所以剩余的三字节是不应该修改的,在release下就没有这问题。
修改为 LONG 类型即可解决问题:
unsigned long chOpt; *((char *)&chOpt) = 1;
CIniFile 构造函数导致异常
系统自动定义的一个对象// 唯一的一个 ChostApp 对象 ChostApp theApp;
这个构造函数应该是在最早执行的,在 ChostApp 里面有一个成员
CIniFile m_IniFile;
所以要首先调用 CIniFile 的构造函数
CIniFile::CIniFile(void) { char szAppName[MAX_PATH]; int len; HINSTANCE hinst; //hinst = AfxGetInstanceHandle(); ::GetModuleFileName(GetModuleHandle(NULL), szAppName, sizeof(szAppName)); len = strlen(szAppName); }
因为 AfxGetInstanceHandle() 调用导致异常。
具体可见CSDN论坛讨论。
栈上对象多线程,析构函数导致程序崩溃
打开主控端。开启被控端, 此时主控端显示上线。在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]
此时执行到的指令位置是 5950CC6F
对应的源代码是
int CManager::Send(LPBYTE lpData, UINT nSize) { int nRet = 0; try { nRet = m_pClient->Send((LPBYTE)lpData, nSize); }catch(...){}; return nRet; }
寄存器edx的数值是
edx 0x02ecfca0 unsigned long
奇怪的是在关闭远程桌面以前这个函数执行了很多次,都没有出现这个问题。现在在关闭远程桌面之后就这样。通过对比发现 出现访问异常的内存 在关闭远程桌面之后数值出现了变化。
可以在关闭远程桌面之后 vs2010下内存访问断点,edx + 4 的位置
调试 -> 新建断点 -> 新建内存断点
此时按F5发现中断在manager类的析构函数里面:
CManager::~CManager() { CloseHandle(m_hEventDlgOpen); }
再看堆栈窗口 是从 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; }
这样就大概分析出执行流程:
在上面函数中定义了一个CScreenManager类的对象manager,这个对象在栈中。CScreenManager基类是 CManager
当在主控端把远程桌面关闭之后run_event_loop 会返回,这样这个函数也就返回了,对象manager也就开始调用自己的析构函数,以前能访问的现在也就不能访问了。 所以就会出现上面的问题。
其实在运行的时候CScreenManager类的构造函数中创建了2个线程ControlThread ,WorkThread,当正常运行没有调试器中断的时候当函数 Loop_ScreenManager 执行完之后ControlThread 这个线程还未完全退出,不知道这样会产生什么意外后果??
经过试验在 函数 Loop_ScreenManager结束之前加入 sleep(20) 可以解决这个问题。
注:14年有段时间看过这个源码,发现了这个问题,发表在看雪论坛。这里转载过来。
相关文章推荐
- SourceProvider.getJniDirectories
- Linux 自检和 SystemTap
- Trac 中文语言安装
- Python 七步捉虫法
- 软件 bug 的生命周期
- Firefox2中输入框丢失光标bug的解决方法
- Ruby中的异常处理代码编写示例
- 路由器的配置与调试
- 对于技术人员的出现了运行时间错误,是否要进行调试的解决方法
- for命令的一些bug分析
- 修正IE下使用CSS属性overflow的bug
- 解决IE6 3像素Bug的css写法
- SQL Server 2005 中使用 Try Catch 处理异常
- MySQL抛出Incorrect string value异常分析
- 浅谈C#中简单的异常引发与处理操作
- 讲解WordPress开发中一些常用的debug技巧
- 跟我学习JScript的Bug与内存管理
- 详解C#编程中异常的创建和引发以及异常处理
- JS注释所产生的bug 即使注释也会执行
- JavaScript程序设计之JS调试