WEB开发网
开发学院软件开发VC 使用Windows钩子获取丢失的密码 阅读

使用Windows钩子获取丢失的密码

 2010-05-27 20:37:33 来源:WEB开发网   
核心提示:包含钩子函数的DLL;钩子要作用的线程ID;现在假设进程A要在进程B中设置钩子,钩子注入进程B以后,使用Windows钩子获取丢失的密码(2),该钩子句柄被返回到进程A,同时DLL被映射到进程B的地址空间,但是,如果将密码控件中的信息显示成“**”便可以有效地保护密码,当进程B中某个钩子事件发生

包含钩子函数的DLL;

钩子要作用的线程ID;

现在假设进程A要在进程B中设置钩子。钩子注入进程B以后,该钩子句柄被返回到进程A,同时DLL被映射到进程B的地址空间。当进程B中某个钩子事件发生时,你的钩子代码便在进程B中被调用。(应该注意的一点是你的钩子代码是从远程进程空被调用的!钩子代码里,如果调用 GetCurrentProcessId 函数,那么获得的是钩子进程的ID,而不是设置钩子的进程ID)。你可以在钩子代码中做任何想做的事情,但是在钩子代码退出之前,你应该调用 CallNextHookEx。如果这个函数调用失败,其它任何已经安装的钩子无法获得消息。因为CallNextHookEx需要该钩子句柄,但我们当前是在进程B中,而句柄被返回到进程A,因此,此时需要进程间通讯来传输钩子句柄。

通常解决这个问题的方法是通过在DLL中创建一个“共享”内存区:

#pragma data_seg("Shared")
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:Shared,rws")

其实,此处创建了一个变量,所有已经被加载的DLL实例共享这个变量。但这个方法有几个问题,第一,有些编译器不支持这个选项,第二,如果微软要是在未来的Windows中改变“共享”内存区的工作模式该怎么办?这意味着这个技术不再适用。此外,这个方法不是线程同步的,由于有多个线程要访问这个变量,线程同步就变得很重要。为了解决这些问题,我在进程间通讯(IPC)过程中使用了内存映射文件,并利用互斥机制进程线程同步。我将这方面的代码全部封装在一个类中,这个类就是 CIPC。通过使用内存映射文件,我解决了特定编译器选项问题,不用再考虑编译器是否支持共享内存区;仅仅借助Win32 API调用以及用MMFs来提供多进程间共享数据的机制就可以解决问题,在未来的Windows版本中,这些东西是不太可能改变的。互斥保证了线程存取的同步: //***********************************************
// IPC.h
//***********************************************
#ifndef _IPC_H_
#define _IPC_H_

#define IPC_SHARED_MMF _T("{34F673E0-878F-11D5-B98A-00B0D07B8C7C}")
#define IPC_MUTEX    _T("{34F673E1-878F-11D5-B98A-00B0D07B8C7C}")

// 使用内存映射文件进行进程间通讯的封装类
class CIPC
{
public:
 CIPC();
 virtual ~CIPC();

 bool CreateIPCMMF(void);
 bool OpenIPCMMF(void);
 void CloseIPCMMF(void);

 bool IsOpen(void) const {return (m_hFileMap != NULL);}

 bool ReadIPCMMF(LPBYTE pBuf, DWORD &dwBufSize);
 bool WriteIPCMMF(const LPBYTE pBuf,
          const DWORD dwBufSize);

 bool Lock(void);
 void Unlock(void);

protected:
 HANDLE m_hFileMap;
 HANDLE m_hMutex;
};

#endif

//***********************************************
// IPC.cpp
//***********************************************
#include "IPC.h"

//***********************************************
CIPC::CIPC() : m_hFileMap(NULL), m_hMutex(NULL)
{
}

//***********************************************
CIPC::~CIPC()
{
  CloseIPCMMF();
  Unlock();
}

//***********************************************
bool CIPC::CreateIPCMMF(void)
{
 bool bCreated = false;

 try
 {
   if(m_hFileMap != NULL)
    return false;  // Already created

   // Create an in-memory 4KB memory mapped
   // file to share data
   m_hFileMap = CreateFileMapping((HANDLE)0xFFFFFFFF,
     NULL,
     PAGE_READWRITE,
     0,
     4096,
     IPC_SHARED_MMF);
   if(m_hFileMap != NULL)
    bCreated = true;
 }
 catch(...) {}

 return bCreated;
}

//***********************************************
bool CIPC::OpenIPCMMF(void)
{
  bool bOpened = false;

  try
  {
    if(m_hFileMap != NULL)
      return true;  // Already opened

    m_hFileMap =
     OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,
      FALSE,
      IPC_SHARED_MMF);
    if(m_hFileMap != NULL)
      bOpened = true;
  }
  catch(...) {}

  return bOpened;
}

//***********************************************
void CIPC::CloseIPCMMF(void)
{
  try
  {
    if(m_hFileMap != NULL)
      CloseHandle(m_hFileMap), m_hFileMap = NULL;
  }
  catch(...) {}
}

//***********************************************
bool CIPC::ReadIPCMMF(LPBYTE pBuf, DWORD &dwBufSize)
{
 _ASSERTE(pBuf);

 bool bSuccess = true;

 try
 {
   if(m_hFileMap == NULL)
     return false;

   DWORD dwBaseMMF = (DWORD)MapViewOfFile(m_hFileMap,
        FILE_MAP_READ | FILE_MAP_WRITE,
     0, 0, 0);
   _ASSERTE(dwBaseMMF);

   // The first DWORD in the MMF contains the size of the data
   DWORD dwSizeofInBuf = dwBufSize;
   CopyMemory(&dwBufSize, (LPVOID)dwBaseMMF, sizeof(DWORD));

   if(dwSizeofInBuf != 0)
   {
     if(dwBufSize > dwSizeofInBuf)
       bSuccess = false;
     else
       CopyMemory(pBuf,
         (LPVOID)(dwBaseMMF + sizeof(DWORD)),
         dwBufSize);
   }

   UnmapViewOfFile((LPVOID)dwBaseMMF);
 }
 catch(...) {}

 return bSuccess;
}

//***********************************************
bool CIPC::WriteIPCMMF(const LPBYTE pBuf, const DWORD dwBufSize)
{
  _ASSERTE(pBuf);

  bool bSuccess = true;

  try
  {
    if(m_hFileMap == NULL)
      return false;

    DWORD dwBaseMMF = (DWORD)MapViewOfFile(m_hFileMap,
      FILE_MAP_READ | FILE_MAP_WRITE,
      0, 0, 0);
    _ASSERTE(dwBaseMMF);

    // The first DWORD in the MMF contains the size of the data
    CopyMemory((LPVOID)dwBaseMMF, &dwBufSize, sizeof(DWORD));
    CopyMemory((LPVOID)(dwBaseMMF + sizeof(DWORD)),
              pBuf,
              dwBufSize);

    UnmapViewOfFile((LPVOID)dwBaseMMF);
  }
  catch(...) {}

  return bSuccess;
}

//***********************************************
bool CIPC::Lock(void)
{
  bool bLocked = false;

  try
  {
    // First get the handle to the mutex
    m_hMutex = CreateMutex(NULL, FALSE, IPC_MUTEX);
    if(m_hMutex != NULL)
    {
      // Wait to get the lock on the mutex
      if(WaitForSingleObject(m_hMutex, INFINITE) ==
                  WAIT_OBJECT_0)
        bLocked = true;
    }
  }
  catch(...) {}

  return bLocked;
}

//***********************************************
void CIPC::Unlock(void)
{
  try
  {
    if(m_hMutex != NULL)
    {
      ReleaseMutex(m_hMutex);
      CloseHandle(m_hMutex);
      m_hMutex = NULL;
    }
  }
  catch(...) {}
}

PasswordSpy的反向工程

上述内容是关于通过编程途径从其它程序“拷贝”密码,下面的内容我们将讨论:如何防止PasswordSpy这样的程序从你的程序中获取密码信息?如果你的应用程序存储并显示密码,你有特别关注安全问题,你可能会考虑让应用堤防类似PasswordSpy这样的程序。

因为PasswordSpy可以拷贝其它程序的密码,为了防范这样的程序,你首先就决不能将真正的密码信息显示出来。最佳办法是在密码框中显示假密码。这样一来,如果有人使用PasswordSpy 获取密码,那他们得到的是一个假密码。本文附带的程序AntiPwdSpy示范了如何保护密码框控件免遭“侦测”。AntiPwdSpy实际上类似于Windows NT服务对话框和Windows NT 用户管理程序。

防范诸如PasswordSpy这类程序的其它方法还可以通过截获WM_GETTEXT消息来实现。但使用虚假密码的方法有额外的好处,用假密码替代真密码,仅检查密码控件是无法确定密码的长度的。如果某个程序显示密码控件中的文本“***”,那么就可以知道密码是三位长度。这样的信息肯定危及密码的安全。但是,如果将密码控件中的信息显示成“**************”便可以有效地保护密码,微软的很多程序产品就是这么做的。

上一页  1 2 

Tags:使用 Windows 钩子

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接