前段时间ADSL密码忘记了但幸好还保存在拨号连接里面于是到网上找了些星号密码显示工具可惜不起作用后来找到一种名为dialupass的工具这家伙还真的把密码给我还原出来了(用的dialupass v我的系统是windows xp) 看起来dialupass非普通的星号密码显示工具那它的原理是什么呢?上GOOGLE查了一翻没找到相关资料(可能是我用的关键字有问题) 一生气便操起家伙(windbg)准备把它大卸八块郁闷的是用windbg加载后密码就还原不出来了显示是星号换替补ollydbg上场情况依旧莫非这小工具有AntiDebug功能?当时只是一丝怀疑因为实在不相信这样的小工具作者会花心思来保护 后来在用sice跟蹤的过程中发现有这么一个调用 GetProcAddress(xx IsDebugPresent) 晕倒原来真的有AntiDebug功能好在比较简单统计了一下总共有处进行了AntiDebug检查情况查明了便换回windbg来调试在windbg里面下这么一个断点便可绕过AntiDebug检测 bp KERNEL!IsDebuggerPresent g poi(esp);r eax=;g 花了些时间跟蹤了一下把dialupass恢复密码的流程都搞清楚了这小程序猫腻还挺多的总结如下 关键函数不直接调用而是用LoadLibraryA和GetProcAddress来获取函数地址后再CALL 函数名是经过编码的反汇编后看字符串是看不到的 关键地方一概用花指令来迷惑你和反汇编软件 其实原理很简单就是用rasapidll里面的一些函数来获取拨号连接的一些信息再用 ADVAPI!LsaRetrievePrivateData 函数来获取密码根据dialupasss的原理写了个类似的工具源代码参见后面的x_dialupassc后来用LsaRetrievePrivateData和RasDialParams做关键字重新在GOOGLE搜索了一遍找到一些类似的代码 参考资源[]和[]的是俄罗斯人公布的演示代码没有对LsaRetrievePrivateData返回的数据进行拆分用户名和密码参考资源[]是日本人公布的完整的应用程序的代码可惜在对LsaRetrievePrivateData返回的数据进行拆分处理时存在BUG导致有些情况下用户名和密码取的不正确后来发现lsadump DUMP出来的数据里面包含了LsaRetrievePrivateData返回的数据lsadump的原理大致如下 )插入一线程到lsassexe进程 )打开LSA Policy database )从注册表"HKLM\SECURITY\Policy\Secrets"中枚举子键 )LsarOpenSecret )LsarQuerySecret 进一步跟蹤后发现其实ADVAPI!LsaRetrievePrivateData是通过NdrClientCall 发送RPC调用到lsassexe进程lsassexe里面再调用LsarOpenSecretLsarQuerySecret来完成获取拨号连接信息过程的(注LsarOpenSecret里面有权限判断非ADMIN组用户是没有权限来调用ADVAPI!LsaRetrievePrivateData的)跟蹤了一下LsarQuerySecret发现它返回的数据其实是从注册表中读取保存拨号连接信息的注册表键值为 HKLM\SECURITY\Policy\Secrets\RasDialParams!SID#\CurrVal SID对应的是用户的string SID(HKLM\SECURITY这个键只有SYSTEM有权限读写连admin都没有权限) LsarQuerySecret从注册表中读取出来数据后接着调用LsapCrDecryptValue函数来解密对于同一台机器来说解密时用的KEY始终都是固定的这个KEY在lsasrvdll里面变量名为_LsapDbSecretCipherKey在windows 里面变量名不一样对应的有两个分别为LsapDbSecretCipherKeyWrite和LsapDbSecretCipherKeyRead但这两个变量里面的数据是一样的LsapCrDecryptValue用的似乎是标准DES算法解密时主要流程如下 lsasrv!LsapCrDecryptValue |_ advapi!SystemFunction |_ advapi!DecryptDataLength |_ advapi!SystemFunction |_ advapi!DES_ECB_LM |_ advapi!des 解密后在<<"标示处还有一个判断: .text:785462F0 call_LsapCrDecryptValue@12 .text:785462F5 testeax, eax .text:785462F7 mov [ebp+var_8], eax .text:785462FA jl loc_785838E1 .text:78546300 .text:78546300 loc_78546300: .text:78546300 cmp byte ptr [esi+45h], 0 .text:78546304 jzshort loc_7854632E ...... .text:7854632E loc_7854632E: .text:7854632E lea eax, [ebp+var_10] .text:78546331 pusheax .text:78546332 push[ebp+arg_8] .text:78546335 push[ebp+var_C] .text:78546338 call_LsapCrEncryptValue@12 假如[esi+45h]为0的话(esi是LsarOpenSecret函数返回的HANDLE),它会把解密后的数据再进行一次加密,不管是2000还是2003,这时用的KEY始终都是固定为“SystemLibraryDTC”。TW.WInGWIT.cOMlsadump2里面调用LsarOpenSecret得到的HANDLE,偏移0x45处值为1,所以LsarQuerySecret函数返回的就是解密后的数据了。而在调用ADVAPI32!LsaRetrievePrivateData时,LsarOpenSecret返回的HANDLE偏移。0x45处值为0x0,所以LsarQuerySecret返回的是解密后又加密的数据,所以在ADVAPI32!LsaRetrievePrivateData里面还有一个对应的解密过程。相应的,LsapCrEncryptValue加密的主要流程如下: lsasrv!LsapCrEncryptValue |_ advapi32!SystemFunction004 |_ advapi32!EncryptDataLength |_ advapi32!SystemFunction001 |_ advapi32!DES_ECB_LM |_ advapi32!des 开始我以为在同一版本的windows里面,_LsapDbSecretCipherKey是固定的,后来发现我错了。那么这个_LsapDbSecretCipherKey是如何产生的?流程如下: (1)调用ntdll!NtConnectPort打开 L"\Security\WxApiPort" (2)调用ntdll!NtRequestWaitReplyPort得到一些数据 。ebp-40处为NtRequestWaitReplyPort返回的LPCMESSAGE。 kd>; dd ebp-40 0006fcb8 00400028 00000002 000000dc 000000d8 0006fcc8 00000024 00000000 00000000 00000000 0006fcd8 00000001 00000010 00000010 fd317e3e 0006fce8 7e24e86d d12503d3 5f7d01a8 7665f528 kd>; db ebp fce e e fd d e ed d a d f ()将上述ebp处的x字节数据COPY到lsasrvdll里面的_LsapDbSysKey变量 _LsapDbSysKey在不同的机器上面(即使版本相同)都是不一样的它是怎么产生的?有幸拜读了flashsky的大作后(参考资源[])才明白这就是传说中的SYSKEY用flashsk的代码验证一下 c:\>;getsyskey e e fd d e e d d a d f 跟蹤系统启动过程可知道\Security\WxApiPort是由winlogonexe进程创建的然后lsass进程通过这个LPC PORT从winlogon进程获取SYSKEY随后winlogon进程会关闭这个LPC PORT所以在系统启动完成之后用Process Explorer等工具是看不到这个LPC PORT存在的而且在winlogon和LSASS进程空间都搜索不到上述SYSKEY ()从注册表HKLM\SECURITY\Policy\PolSecretEncryptionKey中读取出来一段数据调用函数_LsapDbDecryptKeyWithSyskey把它用_LsapDbSysKey来解密 _LsapDbSecretCipherKey就在解密完后的数据里面(LsapDbDecryptKeyWithSyskey函数做的其实就是MD和RC运算)了解原理后我们就可以直接从注册表里面来获取拨号连接中的密码等数据了但有几个问题需要解决 ()原料 Q:HKLM\SECURITY键只有SYSTEM有权限读写? A:我们可以把代码插入到SYSTEM进程里面去运行或者把这个键修改为ADMIN有权限读或者提升本进程权限 ()催化剂:) Q: 如何获取_LsapDbSysKey?解密用的函数_LsapDbDecryptKeyWithSyskey为非导出函数怎么办? A: 用flashsky的代码来获取SYSKEY利用公开的MD和RC库函数来解密 A: 直接从lsassexe进程里面搜索_LsapDbSecretCipherKey它的结构如下: typedef struct _LSA_BLOB { DWORD cbData; DWORD cbMaxData; BYTE* pbData; } LSA_BLOB; pbData指向存储KEY的地址KEY长度固定为x字节即cbData和cbMaxData都是固定为x所以从lsass进程的空间里面搜索\x\x\x\x\x\x\x\x即可找到正确的KEY结果可能会有多个可以把所有搜索到的KEY都试一下总有一个正确的 ()工具 Q: 解密函数LsapCrDecryptValue为非导出函数怎么办? A: 或许可以根据特征码来搜索但总觉得不太可靠 幸好LsapCrDecryptValue 调用的advapi!SystemFunction是导出函数:)或者直接利用公开的DES库函数自己来运算x_dialupasscpp 中的代码演示了直接从注册表中读取数据并解密之的过程没有太多实际意义 |