前段時間ADSL密碼忘記了
但幸好還保存在撥號連接裡面
於是到網上找了些星號密碼顯示工具
可惜不起作用
後來找到一種名為dialupass的工具
這家伙還真的把密碼給我還原出來了
(用的dialupass v
我的系統是windows xp)
看起來dialupass非普通的星號密碼顯示工具
那它的原理是什麼呢?上GOOGLE查了一翻
沒找到相關資料(可能是我用的關鍵字有問題)
一生氣便操起家伙(windbg)准備把它大卸八塊
郁悶的是
用windbg加載後
密碼就還原不出來了
顯示是星號
換替補ollydbg上場
情況依舊
莫非這小工具有Anti
Debug功能?當時只是一絲懷疑
因為實在不相信這樣的小工具作者會花心思來保護
後來在用s
ice跟蹤的過程中
發現有這麼一個調用
GetProcAddress(xx
IsDebugPresent
)
暈倒
原來真的有Anti
Debug功能
好在比較簡單
統計了一下
總共有
處進行了Anti
Debug檢查
情況查明了
便換回windbg來調試
在windbg裡面下這麼一個斷點便可繞過Anti
Debug檢測
bp KERNEL
!IsDebuggerPresent
g poi(esp);r eax=
;g
花了些時間跟蹤了一下
把dialupass恢復密碼的流程都搞清楚了
這小程序貓膩還挺多的
總結如下
關鍵函數不直接調用
而是用LoadLibraryA和GetProcAddress來獲取函數地址後再CALL
函數名是經過編碼的
反匯編後看字符串是看不到的
關鍵地方一概用花指令來迷惑你和反匯編軟件
其實原理很簡單
就是用rasapi
dll裡面的一些函數來獲取撥號連接的一些信息
再用 ADVAPI
!LsaRetrievePrivateData 函數來獲取密碼
根據dialupasss的原理
寫了個類似的工具
源代碼參見後面的x_dialupass
c
後來用
LsaRetrievePrivateData
和
RasDialParams
做關鍵字
重新在GOOGLE搜索了一遍
找到一些類似的代碼
參考資源[
]和[
]的是俄羅斯人公布的演示代碼
沒有對LsaRetrievePrivateData返回的數據進行拆分用戶名和密碼
參考資源[
]是日本人公布的完整的應用程序的代碼
可惜在對LsaRetrievePrivateData返回的數據進行拆分處理時存在BUG
導致有些情況下用戶名和密碼取的不正確
後來發現lsadump
DUMP出來的數據裡面包含了
LsaRetrievePrivateData
返回的數據
lsadump
的原理大致如下
)插入一線程到lsass
exe進程
)打開LSA Policy database
)從注冊表"HKLM\SECURITY\Policy\Secrets"中枚舉子鍵
)LsarOpenSecret
)LsarQuerySecret
進一步跟蹤後發現
其實ADVAPI
!LsaRetrievePrivateData是通過NdrClientCall
發送RPC調用到lsass
exe進程
lsass
exe裡面再調用LsarOpenSecret
LsarQuerySecret來完成獲取撥號連接信息過程的
(注
LsarOpenSecret裡面有權限判斷
非ADMIN組用戶是沒有權限來調用ADVAPI
!LsaRetrievePrivateData的)
跟蹤了一下LsarQuerySecret
發現它返回的數據其實是從注冊表中讀取
保存撥號連接信息的注冊表鍵值為
HKLM\SECURITY\Policy\Secrets\RasDialParams!SID#
\CurrVal
SID對應的是用戶的string SID
(
HKLM\SECURITY
這個鍵只有SYSTEM有權限讀寫
連admin都沒有權限)
LsarQuerySecret從注冊表中讀取出來數據後
接著調用LsapCrDecryptValue函數來解密
對於同一台機器來說
解密時用的KEY始終都是固定的
這個KEY在lsasrv
dll裡面
變量名為
_LsapDbSecretCipherKey
在windows
裡面
變量名不一樣
對應的有兩個
分別為
LsapDbSecretCipherKeyWrite
和
LsapDbSecretCipherKeyRead
但這兩個變量裡面的數據是一樣的
LsapCrDecryptValue用的似乎是標准DES算法
解密時主要流程如下
lsasrv!LsapCrDecryptValue
|_ advapi
!SystemFunction
|_ advapi
!DecryptDataLength
|_ advapi
!SystemFunction
|_ advapi
!DES_ECB_LM
|_ advapi
!des
解密後
在
<<"標示處還有一個判斷:
.text:785462F0 call_LsapCrDecryptValue@12
.text:785462F5 testeax, eax
.text:785462F7 mov [ebp+var_8], eax
.text:785462FA jl
loc_785838E1
.text:78546300
.text:78546300 loc_78546300:
.text:78546300 cmp byte ptr [esi+45h], 0
.text:78546304 jz short loc_7854632E
......
.text:7854632E loc_7854632E:
.text:7854632E lea eax, [ebp+var_10]
.text:78546331 pusheax
.text:78546332 push[ebp+arg_8]
.text:78546335 push[ebp+var_C]
.text:78546338 call_LsapCrEncryptValue@12
假如[esi+45h]為0的話(esi是LsarOpenSecret函數返回的HANDLE),它會把解密後的數據再進行一次加密,不管是2000還是2003,這時用的KEY始終都是固定為“SystemLibraryDTC”。TW.WInGWIT.cOMlsadump2裡面調用LsarOpenSecret得到的HANDLE,偏移0x45處值為1,所以LsarQuerySecret函數返回的就是解密後的數據了。而在調用ADVAPI32!LsaRetrievePrivateData時,LsarOpenSecret返回的HANDLE偏移。0x45處值為0x0,所以LsarQuerySecret返回的是解密後又加密的數據,所以在ADVAPI32!LsaRetrievePrivateData裡面還有一個對應的解密過程。相應的,LsapCrEncryptValue加密的主要流程如下:
lsasrv!LsapCrEncryptValue
|_ advapi32!SystemFunction004
|_ advapi32!EncryptDataLength
|_ advapi32!SystemFunction001
|_ advapi32!DES_ECB_LM
|_ advapi32!des
開始我以為在同一版本的windows裡面,_LsapDbSecretCipherKey是固定的,後來發現我錯了。那麼這個_LsapDbSecretCipherKey是如何產生的?流程如下:
(1)調用ntdll!NtConnectPort打開 L"\Security\WxApiPort"
(2)調用ntdll!NtRequestWaitReplyPort得到一些數據 。ebp-40處為NtRequestWaitReplyPort返回的LPCMESSAGE。
kd>; dd ebp-40
0006fcb8 00400028 00000002 000000dc 000000d8
0006fcc8 00000024 00000000 00000000 00000000
0006fcd8 00000001 00000010 00000010 fd317e3e
0006fce8 7e24e86d d12503d3 5f7d01a8 7665f528
kd>; db ebp
fce
e
e
fd
d e
e
d
d
a
d
f
(
)將上述
ebp
處的
x
字節數據COPY到lsasrv
dll裡面的
_LsapDbSysKey
變量
_LsapDbSysKey
在不同的機器上面(即使版本相同)都是不一樣的
它是怎麼產生的?有幸拜讀了flashsky的大作後(參考資源[
])
才明白這就是傳說中的
SYSKEY
用flashsk的代碼驗證一下
c:\>;getsyskey
e
e
fd
d e
e d
d
a
d
f
跟蹤系統啟動過程
可知道
\Security\WxApiPort
是由winlogon
exe進程創建的
然後lsass進程通過這個LPC PORT從winlogon進程獲取SYSKEY
隨後winlogon進程會關閉這個LPC PORT
所以在系統啟動完成之後
用
Process Explorer
等工具是看不到這個LPC PORT存在的
而且在winlogon和LSASS進程空間都搜索不到上述SYSKEY
(
)從注冊表
HKLM\SECURITY\Policy\PolSecretEncryptionKey
中讀取出來一段數據
調用函數_LsapDbDecryptKeyWithSyskey
把它用
_LsapDbSysKey
來解密
_LsapDbSecretCipherKey
就在解密完後的數據裡面
(
LsapDbDecryptKeyWithSyskey
函數做的其實就是MD
和RC
運算)了解原理後
我們就可以直接從注冊表裡面來獲取撥號連接中的密碼等數據了
但有幾個問題需要解決
(
)原料
Q:
HKLM\SECURITY
鍵只有SYSTEM有權限讀寫?
A:我們可以把代碼插入到SYSTEM進程裡面去運行
或者把這個鍵修改為ADMIN有權限讀
或者提升本進程權限
(
)催化劑:)
Q: 如何獲取
_LsapDbSysKey
?解密用的函數_LsapDbDecryptKeyWithSyskey為非導出函數
怎麼辦?
A
: 用flashsky的代碼來獲取SYSKEY
利用公開的MD
和RC
庫函數來解密
A
: 直接從lsass
exe進程裡面搜索
_LsapDbSecretCipherKey
它的結構如下:
typedef struct _LSA_BLOB {
DWORD cbData;
DWORD cbMaxData;
BYTE* pbData;
} LSA_BLOB;
pbData指向存儲KEY的地址
KEY長度固定為
x
字節
即cbData和cbMaxData都是固定為
x
所以從lsass進程的空間裡面搜索
\x
\x
\x
\x
\x
\x
\x
\x
即可找到正確的KEY
結果可能會有多個
可以把所有搜索到的KEY都試一下
總有一個正確的
(
)工具
Q: 解密函數LsapCrDecryptValue為非導出函數
怎麼辦?
A: 或許可以根據特征碼來搜索
但總覺得不太可靠
幸好
LsapCrDecryptValue 調用的advapi
!SystemFunction
是導出函數:)
或者直接利用公開的DES庫函數
自己來運算
x_dialupass
cpp 中的代碼演示了直接從注冊表中讀取數據並解密之的過程
沒有太多實際意義
From:http://tw.wingwit.com/Article/os/xtgl/201311/9385.html