前言
Oracle 客戶端與服務端采用TNS作為其資料交換協議,TNS全稱Transparent Network Substrate,是與Oracle資料庫服務器通訊的專有協議,該協議為Oracle內部協議,不向外界公開,在此之前,已經有一些反向工程的實踐對各個版本的TNS進行決議,比如wireshark就有專門的TNS分析工具,中文的協議決議可參見《ORACLE協議分析》本系列基礎介紹中關于TNS包基礎格式,及連接包等均沿用wireshark提供的格式,本系列重點分析TNS 314下的客戶端與服務端之間的通訊,通過抓包分析,查看在不同客戶端,不同服務端情況下傳輸方式的不同,嘗試還原其協議細節,實作對協議中一些關鍵內容的決議,如登錄用戶名,協議版本,oracle版本,sql命令,同時給出示例LUA代碼,為了分析不同客戶端架構,本系列使用了兩類客戶端32位與64位客戶端進行測驗,同時重點使用了多個廠商的不同客戶端(Navicat、PLSQL、SQLPlus)同時也兼顧分析了OJDBC Thin Client的情況,服務端采用11g和12c兩個版本,本文主要分析連接建立,身份驗證、命令傳輸和回傳、以及錯誤資訊回傳的程序,
方法及工具
主要采用wireshark對客戶端與Oracle間的通訊進行抓包分析,
|
客戶端: |
服務端 |
|
Navicat Premium 15 64bit |
Oracle 11g 64bit Linux |
|
Navicat Premius 12 32bit |
Oracle 12c 64bit windows |
|
PLSQL 11.2 64bit |
|
|
SQLPlus 11.2 64bit |
|
|
OJDBC8(Thin Client) |
|
分析程序中關于包型別定義等參考wireshark的tns 決議器代碼,
代碼示例說明
代碼示例用lua寫成,可以在openresty15 64bit window或linux版本下運行
其中從socket流中解碼用到了string.unpack 和pack 方法是純lua開源實作,是對c語言 lua 擴展lpack 的純lua模擬
系列目錄
一、方法論與基礎知識
二、基礎包結構
三、連接認證流程與包分析
四、SQL執行流程與包分析
五、錯誤回傳
協議介紹
Transparent Network Substrate顧名思義是對傳輸層協議無關,根據Oracle的介紹:TNS底層支持TCP,SSL TP,SDP,named pipeline等協議,在OSI七層協議體系中,TNS屬于會話層協議
詳細的介紹可參考
https://docs.oracle.com/cd/B28359_01/network.111/b28316/architecture.htm#NETAG004
Oracle版本與TNS協議版本對應關系
|
Oracle 版本 |
TNS版本 |
|
11gr2 12c |
tns314 |
|
10g |
313 |
|
9i |
312 |
|
X |
311 |
|
8i |
310 |
不同driver的差異
Oracle Client呼叫服務端,最終實作模式主要是 OCI和ThinDriver,
- OCI是C 語言的lib,和平臺相關,有linux和windows 版本;
- ThinDriver是純Java的包,與平臺無關;
很多人反映反編譯Java代碼看到的情況和用plsql等工具呼叫實作不同,大概率是此原因,但無論Navicat,SQLPlus,PLSQL都走的OCI,相應JDBC有兩種
- JDBC OCI Driver 走OCI呼叫,
- JDBC Thin Driver走 純Java實作
ThinDriver的實作與OCI的實作從抓包上看,在連接建立和認證程序差距不大,但Data包差距很大,無論Endian模式,還是具體資料型別封裝格式都有較大差異,在ThinDriver的實作中,很少未見出現Piggy Command的情況,所有非0或大于一位的byte或者int變數都會嚴格前序長度欄位,
不同客戶端實作的差異
相同位數(都是64位或者都是32位)的不同客戶端的實作在抓包分析時也不太相同,大概表現有兩個方面,一個是流程上的不同,一個是資料上的不同,我們以執行select陳述句為例,PLSQL和Navicat在流程上稍有差別,下圖是Navicat Premium15 執行的流程
|
1 |
------- |
Data Piggyback(11) Cursor Close All(69) 注意此處也有可能是 03 5e |
-----> |
具體陳述句 |
|
2 |
<----- |
Data DescribeInfo(10) 17 |
------- |
回傳列 |
|
3 |
------- |
Data UOCIFun(03) ExecuteARow(04) |
-----> |
|
|
4 |
<----- |
Data ReturnStatus(04) |
------- |
|
|
5 |
------- |
Data UOCIFun(03) FetchARow(05) |
-----> |
獲取其他值 |
|
6 |
<----- |
Data RowTransferHeader(06) 01 |
------- |
回傳值 |
而PLSQL中沒有中間3和4的部分,
資料上的不同有的時候是一些資料長度,有的時候是一些設定位上的差異,比如對于select 的Piggycommand(pagekage type 0x6 DataId=0x11 CallID=0x69)
這個包內容在Sqlplus,plsql,navicat上不僅內容,長度也就有差異
|
陳述句 |
Plsql |
Sqlplus |
Navicat |
|
Select |
fe ff ff ff ff ff ff ff 01 00 00 00 04 00 00 00 |
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 05 00 00 00 當沒有輸入;05會變03 |
fe ff ff ff ff ff ff ff 01 00 00 00 05 00 00 00 |
不同客戶端位數間差異
32位客戶端和64位客戶端也有不同,比如32位客戶端中所有0xfe ff ff ff ff ff ff ff 全部以其補碼01代替,但64bit 的ThinClient也有此情況,所以很難說這些現象是否完全由位數造成,這會導致許多協議中許多部分的長度根據位數不同有一定區別,文中凡協議均會標注出不同客戶端位數下的長度,若未單獨標注,則說明二者無不同,例如Buddle execute Command命令格式:
|
|
32bit |
64bit |
|
|
序列號 |
1 |
1 |
|
|
Piggy command |
9 or 13 |
16 or 20 |
|
|
Buddle execute command 035e |
變長 |
變長 |
|
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/2487.html
標籤:Oracle
