如果要使用那些不受控制的字符串复制操作,如gets()或strcpy(),来覆盖掉由"密探"保护的返回地址(EIP)、基指针(EBP)、或堆栈上的其他值,一个攻击者将首先要覆盖掉这个"密探"。如果"密探"被修改了,当函数返回时,将会产生一个错误,导致攻击失败--除非是为了进行"拒绝服务攻击"。通过暴力枚举猜测这个值,或其他方法,还是有可能挫败这个"密探"的,但是,进行一次成功攻击的难度增加了。
打开/GS选项不会让程序对缓冲区溢出漏洞彻底免疫,堆栈中的缓冲区溢出仍会使程序崩溃,攻击者利用基于堆栈的溢出来执行任意代码的可能性,即使在打开/GS的情况下仍然存在。更重要的是,/GS选项不会检测堆中或数据段中的缓冲区溢出。
为举例说明,例2使用Win32 GUI重写了前面那个示例程序,这个程序提供一个带有一些简单选项的菜单栏--File菜单下有两个菜单项:"Login"和"Exit"。Login会用一个对话框来提示用户输入密码,一旦输入了密码,在用户点击"OK"按钮之后,将把输入的密码与之前记录的密码相比较。
例2:
| 1. #include "stdafx.h" 2. #include "TestItDan.h" 3. #include <stdlib.h> 4. #include <stdio.h> 5. #include <windows.h> 6. #define MAX_LOADSTRING 100 7. struct user { 8. wchar_t *name; 9. size_t len; 10. int uid; 11. }; 13. HINSTANCE hInst; 14. TCHAR szTitle[MAX_LOADSTRING]; 15. TCHAR szWindowClass[MAX_LOADSTRING]; 16. TCHAR lpszUserName[16] = L"guest"; 17. TCHAR lpszPassword[16] = L"0123456789abcde"; 18. struct user *userP = (struct user *)0xcdcdcdcdcdcdcdcd; 19. size_t userNameLen = 16; 20. size_t userPasswordLen = 0xffffffff; 25. int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { 26. UNREFERENCED_PARAMETER(hPrevInstance); 27. UNREFERENCED_PARAMETER(lpCmdLine); 28. MSG msg; 29. HACCEL hAccelTable; 30. LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 31. LoadString(hInstance, IDC_TESTITDAN, szWindowClass, MAX_LOADSTRING); 32. MyRegisterClass(hInstance); 33. userP = (struct user *)malloc(sizeof(user)); 34. if (!InitInstance (hInstance, nCmdShow)) { 35. return FALSE; 36. } 37. hAccelTable =LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTITDAN)); 38. while (GetMessage(&msg, NULL, 0, 0)) { 39. if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 40. TranslateMessage(&msg); 41. DispatchMessage(&msg); 42. } 43. } 44. return (int) msg.wParam; 45. } 109. INT_PTR CALLBACK GetPassword(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { 110. TCHAR lpszGuestPassword[16] = L"NCC-1701"; 111. UNREFERENCED_PARAMETER(lParam); 112. switch (message) { 113. case WM_INITDIALOG: 114. return (INT_PTR)TRUE; 115. case WM_COMMAND: 116. if (LOWORD(wParam) == IDOK) { 117. EndDialog(hDlg, LOWORD(wParam)); 118. SendDlgItemMessage(hDlg, 119. IDC_EDIT1, 120. EM_GETLINE, 121. (WPARAM) 0, // line 0 122. (LPARAM) lpszPassword 123. ); 124. userP->len = userNameLen; 125. if (wcscmp(lpszPassword, lpszGuestPassword) == 0) { 126. return true; 127. } 128. else { 129. MessageBox(hDlg, 130. (LPCWSTR)L"Invalid Password", 131. (LPCWSTR)L"Login Failed", 132. MB_OK 133. ); 134. } 135. return (INT_PTR)TRUE; 136. } 137. break; 138. } 139. return (INT_PTR)FALSE; 140. } |

