在win2000、winXP下看 **********

原创 2004年07月29日 23:08:00

本文将讲述如何在win2000下如何编程实现得到应用程序中的密码框中的密码及网页密码框中的密码
记得在win98的时候,只要向一个密码框发一个WM_GETTEXT的消息就可以很容易的得到了其中的密码,微软可能已经意识到了,这一个不安的因素,在win2000/xp中,像以前那样写一个应用程序,向别的程序的密码框简单的发送一个WM_GETTEXT的消息就得到密码了,原因是在进程间数据是相互隔离的,如果参数窗口句柄不属于该进程的调用线程,函数执行就会失败,为了解决这个问题,我们可以用钩子函数实现,钩子函数一般存于动态链接库中,win32会自动把动态链接库映射到它影响的各个进程,在这其间该动态链接库的其它函数也会连带映射到运行的进程之中。这样钩子函数也就会和它的寄主程序窗口融为一体。在这样的一个进程中,由于dll的插入映射使得函数参数窗口句柄hwnd就属于该进程了,而这是win32所允许的。所以写一个dll并将其注入到有密码的进程中,这样就可以dll看成进程的一步分了,再用WM_COPYDATA来进行进程的通信,来将密码显示发送到我们要显示的程序中。
好了理论说完了,开始动手用vc做一个程序了。
先建立一个基于对话框的程序GetPass,其它选项为默认值。
再加入一个edit控件,其ID为IDC_EDIT1用来显示得到的密码信息。
在CGetPassDlg::OnInitDialog()的最后中加入
const CWnd * pWndInsertAfter;
 pWndInsertAfter = &wndTopMost;
 SetWindowPos(pWndInsertAfter,0,0,0,0,SWP_NOSIZE);//将窗口放于最上层

 SetTimer(1,100,NULL);//每隔500毫秒来取得一次密码。

 BOOL k=InitHook(this->m_hWnd);//挂接钩子
 if(k==FALSE)
  AfxMessageBox("false");
重载OnTimer函数,加入如下代码
 HWND hwnd;
 CPoint MousePos;
 GetCursorPos(&MousePos); //取得当前鼠标的坐标

 hwnd= ::WindowFromPoint(MousePos);//得到当前坐标的对应窗口的句柄
 GetPassText(hwnd, m_hWnd);//调用这个函数来取得密码

 得用classwzard为消息WM_COPYDATA加入响函数OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)加入如下代码,来得到dll传来的密码:
 SetDlgItemText(IDC_EDIT1, (LPCTSTR)pCopyDataStruct->lpData);
这时编译我们的程序时会有两个错误如下
error C2065: 'InitHook' : undeclared identifier
error C2065: 'GetPassText' : undeclared identifier
这两个函数是我们要在dll中建立。所以我们再新建一个名为Password的project,选择MFC AppWizard(dll),并且Add to Current Workplace
并且选择add to current workspace.其它的按照默认值。
先在Password.cpp的最上面加入变量与宏定义

#define MAX_TEXTLEN 1024
#define UM_GETPASS WM_USER + 0x392
HINSTANCE ghInstance = 0;
#pragma data_seg("ALLDATA")
 HHOOK g_hHook = NULL;
 HINSTANCE g_hDllIns = NULL;
 HWND g_hHostWnd = NULL;
#pragma data_seg()

再改写一下Password.def其代码如下:
LIBRARY      "Password"
DESCRIPTION  'Password Windows Dynamic Link Library'
EXPORTS
   InitHook   @1
 ReleaseHook   @2
 GetPassText   @3
SECTIONS
 ALLDATA SHARED


//我们手动加入的函数声明与变量
利用classwzard为CPasswordApp加入CPasswordApp::InitInstance()
其中的代码为:

  g_hDllIns =AfxGetInstanceHandle();
 DisableThreadLibraryCalls(g_hDllIns);
再在Password.cpp中的全局变量CPasswordApp theApp之后加入如下代码:

LRESULT CALLBACK GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
{
 try {
  if (code >= 0){

   LPMSG pMsg = (LPMSG)lParam;

   HWND hShowPassWnd = (HWND)pMsg->lParam;

   if (pMsg->message == UM_GETPASS && g_hHostWnd == hShowPassWnd){ //获取*号中的内容

    HWND hPassWnd = (HWND)pMsg->wParam; //*号窗口的HWND

    if (hPassWnd){
     TCHAR szPassText[MAX_TEXTLEN];
     ZeroMemory(szPassText, MAX_TEXTLEN);
     ::SendMessage(hPassWnd, WM_GETTEXT, MAX_TEXTLEN, (LPARAM)szPassText); //获取内容
    
     COPYDATASTRUCT cd;
     ZeroMemory(&cd, sizeof(cd));
     cd.dwData = (DWORD)hPassWnd;
     cd.cbData = strlen(szPassText) + 1;
     cd.lpData = szPassText;
     SendMessage(hShowPassWnd, WM_COPYDATA, (WPARAM)hPassWnd, (LPARAM)&cd);//发送给ShowPass窗口
    }
   }
  }
 }
 catch(...){
 }

 return CallNextHookEx(g_hHook, code, wParam, lParam);
}
 BOOL  InitHook(HWND hWnd)
{
 try {
  if (!hWnd){
   return FALSE;
  }

  g_hHostWnd = hWnd;
  g_hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hDllIns, 0);
  return g_hHook != NULL;
 }
 catch (...){
 
  return FALSE;
 }
}
HWND WINAPI GetParentFromHwnd(HWND hWnd)
{
 HWND hParWnd;
 try {
  do {
   hParWnd = GetParent(hWnd);
   if (hParWnd){
    hWnd = hParWnd;
   }
  }while (hParWnd);
 }
 catch (...){
 }

 return hWnd;
}

void  GetPassText(HWND hWndPass, HWND hWndShowPass)
{
 try {
  HWND hParWnd = GetParentFromHwnd(hWndPass);
  ::PostMessage(hParWnd, UM_GETPASS, (WPARAM)hWndPass, (LPARAM)hWndShowPass);
 }
 catch(...){
 }
}
//卸载
 BOOL  ReleaseHook()
{
 BOOL bSuccess = FALSE;
 try {
  if(g_hHook != NULL)
  {
   bSuccess = UnhookWindowsHookEx(g_hHook) ? TRUE : FALSE;
   g_hHook = NULL;
   g_hHostWnd = NULL;
  }
 }
 catch (...){
 }
 return bSuccess;
}
再在Password.h中加入函数导出声明
extern "C" _declspec(dllexport) void  GetPassText(HWND hWndPass, HWND hWndShowPass);
extern "C" _declspec(dllexport) BOOL  InitHook(HWND hWnd);
extern "C" _declspec(dllexport) BOOL  ReleaseHook();

最后编译、链接,把生成的Password.dll,Password.lib拷贝到GetPass工程的目录下,在GetPass工程的GetPassDlg.cpp的最上面加入如下代码
#pragma comment(lib,"Password.lib")
//隐式链接
extern "C" _declspec(dllexport) void  GetPassText(HWND hWndPass, HWND hWndShowPass);
extern "C" _declspec(dllexport) BOOL  InitHook(HWND hWnd);
extern "C" _declspec(dllexport) BOOL  ReleaseHook();
最后运行程序,把鼠标指向应用程序的密码框就可以看到密码了。
但是我们把鼠标指向网页上的密码框时我们无法得到其内容,因为网页密码框不是一般的EDIT控件,因此不能取得网页密码框的句柄.要实现这个功能,只好通过WebBrowser控件的有关COM接口了.因此取得这些接口是整个程序的关键.
在msdn上可以找到在不同的进程中取得IE的Webbrowser控件的IHTMLDocument2接口的方法它的实现机理是向Webbrowser控件(窗口类名是"Internet Explorer_Server")发一个WM_HTML_GETOBJECT,然后把返回值传给Microsoft Active Accessibility (MSAA) 函数ObjectFromLresult,这样你会取得一个已经编排(Marshaling)过的COM接口.如下函数所示:
IHTMLDocument2* GetDocInterface(HWND hWnd)
{
 // 我们需要显示地装载OLEACC.DLL,这样我们才知道有没有安装MSAA
 HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
 IHTMLDocument2* pDoc2=NULL;
 if ( hInst != NULL ){
  if ( hWnd != NULL ){
   CComPtr<IHTMLDocument> spDoc=NULL;
   LRESULT lRes;
   /*由于WM_HTML_GETOBJECT非Windows标准消息,所以需要RegisterWindowMessage*/
   UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );
   ::SendMessageTimeout( hWnd, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );

   /*取得ObjectFromLresult函数的地址*/
   LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, _T("ObjectFromLresult") );
   if ( pfObjectFromLresult != NULL ){
    HRESULT hr;
    hr=pfObjectFromLresult(lRes,IID_IHTMLDocument,0,(void**)&spDoc);
    if ( SUCCEEDED(hr) ){
     CComPtr<IDispatch> spDisp;
     CComQIPtr<IHTMLWindow2> spWin;
     spDoc->get_Script( &spDisp );
     spWin = spDisp;
     spWin->get_document( &pDoc2 );
    }
   }
  }
  ::FreeLibrary(hInst);
 }
 else{//如果没有安装MSAA
  AfxMessageBox(_T("请您安装Microsoft Active Accessibility"));
 }
 return pDoc2;
}

请注意.如果程序在Windows95,98和NT 4.0 Service With  Pack 4 or 5下运行必须要把Microsoft Active Accessibility (MSAA)运行时组件(RDK)与程序一起发布(Windows2000及Windows NT 4.0 Service With Pack 6中已经有了,所以不用)..3.使用这种方法前要调用CoInitialize(NULL);然后应该相应地调用CoUninitialize(); 所以我们先在CGetPassDlg::OnInitDialog()的最后加入CoInitialize(NULL);再重载WM_DESTROY消息,在其对应函数void CGetPassDlg::OnDestroy()中加入如下代码:
 CoUninitialize();//卸载com组件
KillTimer(1); //卸载时钟

这样,我们就取得了IHTMLDocument2*接口了,要取得密码框的密码还得一番周折,现在改写我们刚才的GetPass工程的void CGetPassDlg::OnTimer(UINT nIDEvent)函数,其改写后的内容如下:
 HWND hwnd;
 CPoint MousePos;
 GetCursorPos(&MousePos); //取得当前鼠标的坐标
 static TCHAR buf[100];
 hwnd= ::WindowFromPoint(MousePos);//得到当前坐标的对应窗口的句柄
 if(hwnd!=NULL){
   ::GetClassName( hwnd, (LPTSTR)&buf, 100 );
   if ( _tcscmp( buf, _T("Internet Explorer_Server") ) == 0 )
//如果是ie则用别的方法
   {
    POINT iept=MousePos;
    ::ScreenToClient(hwnd,&iept);
    GetPassword(GetDocInterface(hwnd),iept);
   }
   else //如果是其它窗口则用原来的方法来取得密码

     GetPassText(hwnd, m_hWnd);

  }
  CDialog::OnTimer(nIDEvent);
再在CgetPassDlg类中加入两个成员函数
void CGetPassDlg::GetPassword(IHTMLDocument2 *pDoc2, POINT pt)
IHTMLDocument2* CGetPassDlg::GetDocInterface(HWND hWnd)
IHTMLDocument2* CGetPassDlg::GetDocInterface(HWND hWnd)函数的代码如前所述
void CGetPassDlg::GetPassword(IHTMLDocument2 *pDoc2, POINT pt)的代码如下:
if(pDoc2==NULL)return;
 CComPtr<IHTMLElement> pElement;
 HRESULT hr=pDoc2->elementFromPoint(pt.x,pt.y,&pElement);
 if(pElement==NULL)return;
 if(SUCCEEDED(hr)){
  CComPtr<IHTMLInputTextElement> pPwdElement;
  hr=pElement->QueryInterface(IID_IHTMLInputTextElement,
   (void**)&pPwdElement);
  if(SUCCEEDED(hr)){
   CComBSTR type;
   hr=pPwdElement->get_type(&type);
   if(SUCCEEDED(hr)){
    if(type==_T("password")){
     CComBSTR pwd;
     hr=pPwdElement->get_value(&pwd);
     if(SUCCEEDED(hr)){
      if(pwd.Length()!=0){
       CComBSTR msg=_T("");
       msg+=pwd;
       CString str(msg);
      SetDlgItemText(IDC_EDIT1, str);
      UpdateData(false);
      }
      else{
      SetDlgItemText(IDC_EDIT1, "密码为空");
      UpdateData(false);
      }
     }
    }
   }
  }
 }
 pDoc2->Release();
最后在stdafx.h中加入所用的头文件
#include <atlbase.h>
#include <oleacc.h>
#include <winuser.h>
#include <mshtml.h>
这样再编译链接我们的程序,把鼠标指向网页的密码框时就可以得到密码了。

VS2012/VS2013/VS2015编写的程序在XP中顺利运行

微软为了推销自家平台,默认配置下VS2012和VS2013编写的应用程序只能在Vista/Win7/Win8上运行。但幸好还保留了生成XP程序的设置项。XP和Win2003的用户还是大量存在的,我们程...
  • yangbingzhou
  • yangbingzhou
  • 2015年11月09日 11:05
  • 4562

Win 2000远程控制的3种安全解决方法

我们设想有一个远程控制方案:一个公司要安置这样一个IISWeb服务器,它被放在300里以外。服务器是宽带网络、有空调装置、电力控制装置三者结合的个服务器中心。这个网络服务中心既稳固又价钱合理,但要求客...
  • candy_578079476
  • candy_578079476
  • 2017年04月10日 00:44
  • 578

WinXPmini仅120MB极为纯净的XP迷你版

WinXPmini 纯净精简的迷你版Windows XP SP3,只有120MB(126412666字节,资源管理器显示123450KB)特别好识别,无修改主页,无OEM信息,无第三方标识。...
  • zyphio
  • zyphio
  • 2017年12月26日 22:26
  • 117

PHP安装包已更新至PHP5.58以及PHP5.4.24

PHP安装包已更新至PHP5.58以及PHP5.4.24
  • u012213585
  • u012213585
  • 2014年01月15日 13:51
  • 2633

如何编译支持在Windows2000下运行的Qt程序

一、历程 这周接到一个软件开发任务,需要写一个界面程序,在windows2000下运行。一开始,我想得很简单:window2000和XP应该是差不多的,只要在XP下能运行的,windows200...
  • stonylhy2011
  • stonylhy2011
  • 2016年11月20日 10:10
  • 604

虚拟机VMWare下安装winXP操作系统及安装VMWare Tools

在VMWare主页中选取新建虚拟机选项卡 2.在新建虚拟机向导中设置安装来源 取决于安装方式.如果是通过光盘安装,则选择第一项.这里我使用ISO映像安装,输入用户名密码和密钥一路下一步就可以安...
  • fitAllEnv
  • fitAllEnv
  • 2017年06月04日 11:30
  • 258

一步一图教你完成Windows XP(32位)+VS Express环境下CUDA开发环境配置

网上有很多方法教我们如何对CUDA进行安装配置,但大多数要求VS为正式版的,而Express版本的方法则比较少,两者在CUDA的配置上有很大不同,网上大多数资料都是直接将VS正式版本的配置方法抄了过来...
  • forthcriminson
  • forthcriminson
  • 2013年02月01日 23:39
  • 1256

图解WinXP局域网共享设置步骤

注:图解XP局域网共享设置步骤2013年01月03日星期四 第一章:共享的前提工作 1.更改不同的计算机名,设置相同的工作组! 2.我的电脑右键-管理-计算机管理-系统工具-本地用户和组-用...
  • jackinzhou
  • jackinzhou
  • 2013年01月05日 12:51
  • 4014

彻底删除Win2000中的游戏

公司几个大胆人物玩游戏让老板看到了,老板让俺把游戏删除了。一路下来,删,删,删,倒也痛快,可是再重新开,又有了。呵呵,请教GOOGLE大师解决如下:一,打开%systemroot%\winnt\inf...
  • u014461454
  • u014461454
  • 2014年03月31日 17:37
  • 213

XP系统离开模式如何设立

电视迷们都喜欢把要看的电视剧下载在自己的电脑上,以保障进度和速度,在下载电视剧的时候需要耗费很多的网速流量,这时候电脑的网速会变得很卡,所以大多数人会选择在晚上睡觉的时候让电脑开着下载。如果你的电脑是...
  • u014354207
  • u014354207
  • 2014年03月25日 17:04
  • 178
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在win2000、winXP下看 **********
举报原因:
原因补充:

(最多只允许输入30个字)