原文:http://www.blogcn.com/User8/flier_lu/index.html?id=3300158


tomekeeper昨天在水木上贴了一个通过 DPAPI 获取保存的 MSN 密码的代码。其核心思想是从 MSN 加密保存在注册表中的键里,把加密后字符串抠出来,然后使用 DPAPI 的函数 CryptUnprotectData 解密之。关键代码如下:
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码//通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
ret = RegOpenKeyEx
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码(
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码HKEY_CURRENT_USER,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
"Software\Microsoft\MSNMessenger",
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
0,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码KEY_READ,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
&hKey
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码);
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
//通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
ret = RegQueryValueEx
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码(
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码hKey,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
"Password.NET Messenger Service",
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
//通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
);
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码DataIn.pbData 
= Data + 2//口令密文从第二位开始
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
DataIn.cbData = dwSize-2;
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码CryptUnprotectData
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码(
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
&DataIn,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码NULL,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码NULL,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码NULL,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码NULL,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
1,
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
&DataOut
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码);
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码base64_decode (DataOut.pbData, Data, strlen(DataOut.pbData));
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码printf ( 
"MSN PassWord: %s ", Data);
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码

不过这种方法针对 XP/2003 环境下的新版本 MSN 没有效果,因为现在已经不再直接保存在注册表键里。于是我安装类似思路,使用 Windbg 和 IDA Pro 大概分析了一下新版本的保存密码方法。得出结论是 MSN 使用了 XP/2003 新增的对当前用户凭据集 (credential set) 管理的函数,将加密后密码放到这个里面统一管理。
可以使用新增的 CredReadDomainCredentials 函数,给定读取目标来获得加密凭据,如:

这里的 CREDENTIAL_TARGET_INFORMATIONW 结构指定要获取凭据的来源和包名称;CredReadDomainCredentialsW 则根据此信息,通过 NdrClientCall2 函数发送 RPC 调用,完成实际功能。
读取出来的凭据包括此凭据的用户名 (UserName) 和凭据内容 (CredentialBlob):
];

对 MSN Messenger 来说,CREDENTIALW::UserName 中就是登陆帐号了。MSN Messenger 每次显示文件菜单时,都会从凭据集中获取当前帐号名称用于显示。而每次登陆时,则进一步将凭据集的内容使用 CryptUnprotectData 函数进行解密,代码如下:

这里 entropyData 保存着通过 WinDbg 直接从 MSN Messenger 代码中抠取出来的内部使用固定加密密钥,以后有可能根据版本不同发生变化。因为新版 MSN Messenger 不在直接加密密码,而是使用此密钥加密,因此与 tomekeeper 那种处理稍有不同。解密后的 pass中保存的就是明文的当前 MSN Messenger 帐号的密码了,呵呵。
通过 DPAPI 获取当前帐号保存的 MSN Messenger 密码static const std::string toString(LPCWSTR lpStr, DWORD cbStr)

看起来好像很不安全,其实也还好了,呵呵。因为 CredReadDomainCredentials 和 CryptUnprotectData 等系列函数,缺省都是使用的当前帐号的安全上下文进行加密解密,哪怕换了台机器这些加密后的数据都不再有意义。因此除非你机器被人搞到当前帐号或者 Administrator 帐号权限,否则密码都还是安全的;反过来说,如果这两个帐号被别人搞到,随便装个键盘记录程序也能够达到类似的效果。因此总体上来说还是比较安全的,这个代码也只能作为忘记自动记录的 MSN 密码时的恢复工具 :P 其实这个才是我们俩研究此问题的主要目的,呵呵

Just for fun! :P

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-12-25
  • 2021-06-05
  • 2022-12-23
  • 2022-03-10
  • 2022-01-01
  • 2021-12-15
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-06-11
  • 2021-10-24
相关资源
相似解决方案