环境

VC6/VC7, MS Platform Core SDK, IE4.0+, WinNT/2K/XP (在英文/中文/日文版的Win2k/XP 及IE6.0+SP1上测试通过)

关键字

Windows 钩子,IE COM 对象,Win2k 安全上下文 IE编程 工具 系统

摘要

本文将介绍一个工具,它不仅能偷窥各种桌面程序的密码框,还能窥到IE页面中的密码框,这个程序就是本文要介绍的——SuperPasswordSpy++。

使用 Windows 钩子偷窥远程进程(或者说桌面程序)密码框内容不是太难,但要偷窥到网页上密码输入域的内容要如何做呢?显然,在网页里的密码输入框不是一个窗口,你得借助 IHTMLDocument2 接口来枚举并吸取密码。本文提供的工具程序将向你展示破解密码编辑公共控件和IE密码输入域的内容。下图是程序运行的截图:

SuperPasswordSpy++ 偷窥Hotmail 页面上的密码输入框:

程序架构

在你围绕屏幕拖动放大镜,程序便捕获鼠标位置并跟踪鼠标的移动,只要鼠标移到某个新窗口,程序便检查该窗口的类名以及窗口式样,确定窗口是否为密码编 辑框或IE(IE实际上是一个浏览器控件,为方便起见叫IE)。如果是IE,那么钩子DLL必须被立即注入到IE中,以确定IE是否包含密码输入域。

我们有两种可选的方法来实现钩子:

  • 第一种方法是设置 WH_GETMESSAGE 钩子,可以参考 Brian Friesen 的文章和代码:PasswordSpy(http://www.codeguru.com/samples/pwdspy.html)。该钩子DLL对消息进行截获并应用同步对象(互斥,事件等)。如下图:

    上图涉及到五个步骤:

    1. Spy程序将钩子DLL注入到目标程序;
    2. Spy程序发送(post)一个用户消息到目标程序,该消息将被注入的DLL截获;
    3. DLL截获用户消息并读取密码编辑框内容;
    4. DLL将数据发回到Spy程序;
    5. Spy程序获取数据并卸载钩子DLL;

因为Spy程序发送用户消息,第二步不会“阻塞”,Spy程序不知道第四步何时发生。通常这种Spy程序使用WM_COPYDATA来传输字节数据,即 “发送”消息。此处不足之处是当用户来回移动放大镜时可能会有这样的情况——Spy程序发现密码编辑框,注入DLL到目标程序,发送用户消息,这时用户突 然移动放大镜到另一个目标程序的密码输入框,此时Spy程序不得不从老的目标程序中卸载DLL钩子,钩子进入新的目标程序并发送消息。不幸的是,来自老的 目标程序的WM_COPYDATA 消息已经进入目标程序的消息队列,如果你不将目标窗口句柄信息添加到WM_COPYDATA,,你便无法告知当前目标程序的数据。

第二种方法是设置WH_CALLWNDPROC钩子。这种方法与第一种方法类似,只是第二步发送消息到目标程序的方法有所不同,这里不是POST,而是 SEND。钩子DLL将截获用户消息并进行密码的内部读取,使用WM_COPYDATA调用SendMessage将数据传到Spy程序,总之,第二步被 阻塞,直到第三步,第四步完成,所以第二步完成后,我们可以直接做第五步。这样一来,代码将比第一种方法简单多了。它类似于Block Socket和非Block Socket编程。

但是,第二种方法也有其弊端。考虑下面的情况,假 设相同的窗口中有两个密码编辑框,用户同时只能顾一个密码框,第一种方法,我们可以检查两个密码框属于同一个线程,钩子DLL只运作一次。而第二种方法, 钩子要运作两次,这造成一定的开销(本文本程序可以忽略这种开销)。

实现细节描述

如何从浏览器控件窗口句柄获取IHTMLDocument(参见MSDN KB Q249232——HOWTO: 如何从从HWND获取IHTMLDocument2)

BOOL HWnd2HtmlDocument()
{CoUninitialize();HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );if ( hInst == NULL ) return FALSE;LRESULT lRes;UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );::SendMessageTimeout( g_hTarget, nMsg,0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );LPFNOBJECTFROMLRESULT pfObjectFromLresult =(LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst,"ObjectFromLresult");if ( pfObjectFromLresult == NULL ){::FreeLibrary( hInst );CoUninitialize();return FALSE;}WCHAR strDoc[] = L"{626fc520-a41e-11cf-a731-00a0c9082637}";//IID_IHTMLDocument2 CLSIDCLSID uuidDoc;HRESULT hrDoc = CLSIDFromString((LPOLESTR)strDoc,&uuidDoc //IID_IHTMLDocument2);if(!SUCCEEDED(hrDoc)){::FreeLibrary( hInst );CoUninitialize();return FALSE;}HRESULT hr  = (*pfObjectFromLresult)( lRes, uuidDoc,//IID_IHTMLDocument,0, (void**)&g_lpHTMLDocument2);if ( SUCCEEDED(hr) ){//OK, We Get Here Successfully}else{::FreeLibrary( hInst );CoUninitialize();return FALSE;}::FreeLibrary( hInst );CoUninitialize();return TRUE;
}

在此我需要解释 g_hTarget 是浏览器句柄,其类名是“Internet Explorer_Server”。通常,如果使用MS IE浏览器,不会出现问题,但某些应用使用 Web 浏览器的ActiveX 控件,在浏览器导航之前,“Internet Explorer_Server”窗口是不存在的。如图我们来看一个例子:

上图是运行Spy++的一张截图,该对话框(00060294)有两个浏览器,只有浏览器000202D6导航到某些URL。你可以做个实验,在对话框中放一个WebBrowser ActiveX,用 Spy++看看结果。

当前页面是否包含密码输入域:

DWORD CheckHtmlDocument()
//返回: 0 —— 无密码输入,否则 —— 有密码输入
{MSHTML::IHTMLElementCollection *pForm;HRESULT hr = g_lpHTMLDocument2->get_all(&pForm);//g_lpHTMLDocument2 是一个IHTMLDocument2 指针if(FAILED(hr)) return 0;long len;pForm->get_length(&len); //How many elements on this form?DWORD dwRet = 0;for(int i = 0; i < len; i++){LPDISPATCH lpItem = pForm->item(CComVariant(i),CComVariant(i));MSHTML::IHTMLInputElementPtr lpInput;HRESULT hr = lpItem->QueryInterface(&lpInput);//它是输入域吗?if(FAILED(hr)) continue;_bstr_t type(_T("password"));if(lpInput->Gettype() == type) //Check Field Type{//_bstr_t x = lpInput->Getvalue();//If you want its stringdwRet++;}lpItem->Release();             //记住释放!lpItem = NULL;}pForm->Release();pForm = NULL;return dwRet;
}

从当前页面密码输入域吸取密码:

  _bstr_t x = lpInput->Getvalue();    //And you go!LPCTSTR lpWhatEver = (LPCTSTR)x;//在这里对密码进行处理

SuperPasswordSpy++ 程序说明——该程序基于Unicode,需要在WinNT/2K/XP + IE4.0+中运行。

读者可以通过本文附带的程序代码了解如何跟踪窗口和远程进程钩子。同时极力推荐读者研究 MS Platform SDK 的例子程序 SPY 和 Brian Friesen 先生的 PasswordSpy。笔者不喜欢“重新发明轮子”之类的事情,本文涉及的代码借鉴了 SPY 例子(如鼠标跟踪)以及PasswordSpy(如函数 SmallestWindowFromPoint和资源)的实现。如果读者有关于钩子技术的疑问,请阅读Brian Friesen 的相关文章,他的文章在这方面讲很详细。此外有关DLL中共享区的详细实现方法建议阅读 Jeffrey Richter 的“Programming Application for MS Windows”第四版。

下面是本文程序SuperPasswordSpy++ 实现中的其它一些细节:

判断密码编辑框的条件

BOOL IsPasswordEdit(HWND hWnd)
{TCHAR szClassName[64];int nRet = GetClassName(hWnd, szClassName, 64);if(nRet == 0) return FALSE;szClassName[nRet] = 0;if(::lstrcmp(szClassName, _T("Edit")) != 0 &&::lstrcmp(szClassName, _T("TEdit")) != 0&&| ::lstrcmp(szClassName, _T("ThunderTextBox"))!= 0 ) return FALSE;//Here, is it OK?DWORD dw = ::GetWindowLong(hWnd,GWL_STYLE);dw &= ES_PASSWORD;if(dw == ES_PASSWORD)return TRUE;return FALSE;
}

以上代码是SuperPasswordSpy++ 实现,要注意一点:密码编辑框的判断是根据类名实现的,笔者在代码中的判断方法是检查类名是否为“TEDIT," "IRIS.PASSWORD” 或者“"EDIT.”。这是Borland的命名规范:TxxxClass。“ThunderTextBox”是由Visual Basic创建得类名。我无法保证今后Windows系统中的应用程序密码编辑框的类名不会改变。谁知道Visual Studio今后的版本中密码编辑框会叫什么。如果不幸碰到这样的情况,请大家自行修改SuperPasswordSpy++的相关代码。

当HTML页面文件中存在多个 Frame 标签时,SuperPasswordSpy++目前的版本假设在HTML页面文件如果包含密码输入域,它只有一个 Frame。对于大多数有密码输入域的页面来说(如MSN Hotmail),SuperPasswordSpy++都能正常运行。但为了做得更完美些,我会在下个版本的SuperPasswordSpy++中添加对多个 Frame 的支持。请随时到我的站点检查更新。

其它说明

Windows 登陆密码: (仅适用于Win2K )

似乎有些疯狂,但是看看如下图片:

上图SuperPasswordSpy++ 窥视Win2K 服务器的“更改密码”的编辑框,用“Ctrl+Alt-Del”就可以看到“更改密码”按钮。PasswordSpy++在Win2K的登陆桌面的 SYSTEM上下文中已经启动,这时可以读取到“更改密码”框中的秘密。在Windows2003系统中这个方法就不灵了。

为了完成这个实验,你得借助工具在Windows的登陆桌面(Winlogon Desktop)来启动程序。你可以到 codeguru 获取“GUI-RunAs” 程序。选择Winlogon桌面,不要输入用户名,这样就可以使用“SYSTEM”身份,记住你必须具有 Administrator 权限来完成这个工作。按照文章中的说明,你可能需要注销当前会话一次(只要一次)以便启用某些还不具备的权限。有些读者来信说Windows系统已经有一 个“RunAs”命令行程序了。我当然知道,但是微软品牌的这个“RunAs”命令行工具无法选择“桌面”来启动程序,而我的工具能做到。如果你在使用这 个工具时有什么问题(例如,启动的程序GUI失败),请先用“SYSTEM”身份启动这个工具,然后再启动你使用的程序。

最后,为了获得屏幕截图,出现WinLogon桌面时按“Print Screen”,回到默认桌面,将它粘贴到MSPaint程序。你还可以用 RunAs工具在WinLogon屏幕启动MSPaint,不用来回切换屏幕。你还会发现这个 RunAs工具另一个好处,以“SYSTEM”身份启动任务管理器,杀死一些顽固的进程(包括Windows服务)。

编辑框的偷窥与反偷窥

有人如何反偷窥。其实不需要花费太大的功夫就可以实现反偷窥。下面的代码例子使用MFC,首先派生一个 CEdit,我最初想改写PreTranslate函数,就像下面这样:

BOOL CAntiPeekEdit::PreTranslateMessage(MSG* pMsg)
//这个方法不灵!
{if(pMsg->message == WM_GETTEXT){//Only Report Text When Passing a Fixed Length Buffer;if(pMsg->wParam == 1024)  //The Number Only You Know{}else{::lstrcpy((LPTSTR)(pMsg->lParam), _T("Nothing"));return TRUE;}}return CEdit::PreTranslateMessage(pMsg);
}

可惜 if 语句中的代码不会被调用,为什么呢?只有MFC 开发团队知道。没办法我把注意力转到函数 WindowsProc,这样就可以行得通了。

LRESULT CAntiPeekEdit::WindowProc( UINT message,WPARAM wParam,LPARAM lParam)
//This works!
{if(message == WM_GETTEXT){if(wParam == 1024)  //The Number Only You Know{return CEdit::WindowProc(message, wParam, lParam);}else{::lstrcpy((LPTSTR)(lParam), _T("Nothing"));//Insert Dummy Text Here To the Peekerreturn 7;}}return CEdit::WindowProc(message, wParam, lParam);
}

在你自己的程序中,如果想要获得密码框的文本,你得像下面这样做:

TCHAR sz[1024];
::SendMessage(hPasswordEdit, WM_GETTEXT, 1024, (LPARAM)sz);

如果其它例程调用以获取秘密,由WM_GETTEXTLENGTH 会得到正确的长度,但是当正确的长度缓冲给了我们的 AntiPeekEdit,我们便知道它由某些其它的非安全源代码调用,所以我们可以返回垃圾数据。你还可以完全放弃 WM_GETTEXT 并使用 WM_USER + 123 消息来获取文本。 让我们回头来考虑如何化解这种AntiPeekEdit。我们知道为何要使用钩子DLL,同时在远程进程中查询密码,Win2K密码编辑框是不接受来自本 进程边界以外的 WM_GETTEXT 消息的。以上策略以用户定义的过程代替标准的Edit类窗口过程,那么,反过来当 SuperPasswordSpy++ 进行偷窥活动时,如何用标准的Edit类窗口过程代替用户定义的过程呢。

HWND hParent = ::GetParent(g_hTarget);
//g_hTarget 是我们要的秘密编辑框句柄
HWND hwndEdit = CreateWindow(
_T("EDIT"),  // 预定义类
NULL,  // 没有窗口标题
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 0, 0,  // 在WM_SIZE 消息中设置大小
hParent,     // 父窗口
(HMENU)123,
// 编辑框ID——注意在同胞窗口中必须唯一
(HINSTANCE) GetWindowLong(g_hTarget, GWL_HINSTANCE),
NULL);    // 不需要指针
//获得标准的Edit 类窗口过程
LONG_PTR lpNewEdit = GetWindowLongPtr(hwndEdit, GWLP_WNDPROC);
LONG_PTR lp = ::SetWindowLongPtr(g_hTarget, GWLP_WNDPROC,(LONG_PTR)lpNewEdit);//在这里取密码——只在这里调用
//SuperPasswordSpy++
SendMessage(g_hTarget, WM_GETTEXT, sizeof(szBuffer) /sizeof(TCHAR), (LPARAM)szBuffer);//重置原来的窗口过程
::SetWindowLongPtr(g_hTarget, GWLP_WNDPROC, (LONG_PTR)lp);

请注意控件ID参数何时创建伪编辑框,在同胞中它必须唯一,我此处使用123作为占位符。你可以编写额外代码来枚举同胞窗口并获得唯一ID,并记住最 后销毁伪编辑框。 在大多数情况下,这样做实在是有牛刀杀鸡之嫌,所以我在SuperPasswordSpy++中没有这种方法,以便保证性能和高稳定性。然而,一旦你真的 遇到这样的反偷窥秘密编辑框,去掉SuperPasswordSpy++中注释的代码即可,并牢记伪编辑框的控制ID一定要惟一。 如果有人热衷于反-反-反偷窥,那么也许你可以添加一个全局变量标志,在取密码前设置该标志,取完之后再置回来…那么为何不用某种算法在 WM_GETTEXT消息处理例程中加密文本呢?

其它的偷窥Spy工具

如果你想偷窥 MSN Messenger/Windows Messenger 的聊天信息,请参考笔者的另外一篇文章“MessengerSpy++”。如下图所示:

我们可以获得100%的 RTF文本以及MSN Messenger的表情图像(右边窗口)。注意支持操作系统是 Win2k/XP,支持 MSN Messenger 4.6, 4.7 和5.0.。此外这个程序还可以发送文本和ICON图标到MSN Messenger 并让Messenger 将它发送给另一个人。

WinXP “修改用户密码”控制面板小程序

对于这个控制面板小程序,即便获取了“Internet Explorer_Server” 窗口类名,由于密码输入域含在一个ActiveX中,在我的英文 WinXP专业版系统中,其CLSID为A5064426-D541-11D4-9523-00B0D022CA64(res://D:\WINDOWS \system32\nusrmgr.cpl/nusrmgr.hta)。所以从ActiveX 中读取密码几乎完全不可能。

转载于:https://www.cnblogs.com/rogee/archive/2011/03/31/2000504.html

偷窥桌面程序和IE浏览器的密码编辑框相关推荐

  1. 关于password导致input弹出浏览器记住密码弹框问题

    关于password导致input弹出浏览器记住密码弹框问题 问题描述 问题解决 代码实现 问题描述 当有input有password的输入框在的时候,其他input输入框可能会在获取光标的时候会弹出 ...

  2. 【Qt】Qt 开发桌面程序 ( Qt 版本 5.14.2 | 编辑 Qt 桌面按钮控件 | 修改按钮文本 | 为按钮添加点击事件 | 系统调用 | 去掉系统调用命令窗口 )

    文章目录 一.添加按钮控件 二.修改按钮文本 三.为按钮添加点击事件 ( 弹出对话框 ) 四.为按钮添加点击事件 ( 打开记事本 ) 五.为按钮添加点击事件 ( 打开计算器 ) 六.去掉系统调用时弹出 ...

  3. web网页浏览器唤起wpf,winform exe桌面程序,并跳转到指定页面

    背景案例 我们看到网页上打开百度网盘,下载的时候会通过浏览器唤起百度网盘桌面端,并进入到指定页面,我们要做的,就是达到类似的效果 实现流程 1.写注册表 在桌面软件首次启动的时候,像注册表中写入程序的 ...

  4. PyQT6的从零开始(三):在pyqt桌面程序简单内置网页浏览器

    文章目录 说明 一.安装PyQtWebEngine 二.设计方法 1.QtDesinger设计界面 2.主程序调用 3.实现效果 说明 结合自己的毕设需求,要在基于pyqt的桌面程序中内置一个web浏 ...

  5. windows桌面程序开发_每个软件开发人员都需要的6个Windows桌面实用程序

    windows桌面程序开发 大多数在Windows上工作的软件开发人员都有相当标准的工具集:代码编辑器或IDE: Git或其他版本控制系统: 消息传递客户端(Slack或其克隆之一),等等. 由于大多 ...

  6. python可以写桌面软件吗-python能写桌面程序吗

    其实Python/Java/PHP都不适合用来做桌面开发,Java还是有几个比较成熟的产品的,比如大名鼎鼎的Java集成开发环境IntelliJ IDEA.Eclipse就是用Java开发的,不过PH ...

  7. python能写桌面程序吗_python能写桌面程序吗

    其实Python/Java/PHP都不适合用来做桌面开发,Java还是有几个比较成熟的产品的,比如大名鼎鼎的Java集成开发环境IntelliJ IDEA.Eclipse就是用Java开发的,不过PH ...

  8. Vue项目打包成桌面程序exe除了使用electron-vue你还可以这样

    场景 electron-vue 基于 vue (基本上是它听起来的样子) 来构造 electron 应用程序的样板代码. 该项目的目的,是为了要避免使用 vue 手动建立起 electron 应用程序 ...

  9. 关于某些 Visual Studio Code 扩展程序无法在浏览器中运行的原因

    只有一部分扩展程序可以在浏览器中运行. 您可以使用"扩展"视图在 Web 中安装扩展,无法安装的扩展将显示警告图标和"了解原因"链接. 安装扩展程序时,它会保存 ...

  10. 用node-webkit(NW.js)创建桌面程序

    以往写windows桌面程序需要用MFC.C#之类的技术,那么如果你只会web开发技术呢?或者说你有一个网站,但是你想把你的网站打包成一个桌面应用程序,该如何做呢? 答案就是用node-webkit这 ...

最新文章

  1. 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
  2. python打破循环_python – 为什么“c.execute(…)”打破循环?
  3. python三大神器===》迭代器
  4. CString比较相等不得不说的故事
  5. 无效0_一场时代的变革,一场与时间的较量,“0”无效载体、“0”空气氧化、“0”细菌生存。...
  6. visual-studio – 使用TFS 2010防止在Visual Studio 2012上签入pdb文件
  7. Gridview光棒效果
  8. spring中的@Bean是否一定要与@Configuration一起用
  9. 使用js调用摄像头拍照
  10. html空间登录页面制作,免费HTML网页空间(每月200 GB 流量托管静态网页超简单)...
  11. 正态性检验ks和sw区别_非参数检验思路总结,清晰理解就靠它了!
  12. 饭店合同免费下载|股份合同免费|餐厅股份合作协议书
  13. 【转】问答 - 挑灯看剑 的最新日记
  14. java 接口耗时分析_性能优化案例(2019-案例78)-接口性能耗时问题分析
  15. 转载内存授予(memory grants)的理解
  16. java数值精度_java数字运算精确度
  17. 公众号开发精品教程(2)——将项目接入微信及简单交互
  18. 【CF940E】Cashback(单调队列dp)
  19. 2476 购买贺年卡
  20. vue-tree-chart

热门文章

  1. Unity3D设置天空盒skybox
  2. SVNAdmin - 好用的开源SVN管理系统
  3. html5拼音显示,HTML5:给汉字加拼音?收起展开组件?
  4. python划分训练集和测试集_python机器学习:如何划分训练集和测试集
  5. 利用bat修复office文件图标
  6. 【你好,windows】windows 7 X86X64 旗舰纯净版2020.3.18
  7. 机器人路径规划之RRT算法
  8. cad图纸怎么看懂_教你如何快速看懂建筑施工图纸
  9. c4dr20怎么安装oc渲染器怎么安装_[C4D插件] OTOY正式发布OC渲染器OctaneRender4 For C4D 支持R16-R20 Demo版已开放下载(Win)...
  10. Windows DLL 注入技术