歡迎來到 黑吧安全網 聚焦網絡安全前沿資訊,精華內容,交流技術心得!

《Dive into Windbg系列》AudioSrv音頻服務故障

來源:本站整理 作者:佚名 時間:2019-04-15 TAG: 我要投稿

起因
最近換了HDMI顯示器后,提示正在尋找音頻設備,隨后系統沒聲音了。右下角喇叭出現紅叉,自動修復提示音頻服務未響應,重裝音頻驅動也沒用,系統是Windows 10 1803 64位。

多次嘗試修復無果,于是打開調試器一探究竟。
 
尋找突破口
從何處入手?這不由得讓我想起《How to solve it》一書:問題是什么?之間的關聯?有哪些已知線索?
系統的音頻面板中列出了本機所有接口,操作一番發現設置為默認的功能不生效。

我意識到這可能跟音頻服務無響應有關,于是決定從這個點入手。
可以看到設置默認選項是一個PopMenu,因此打算先找到該菜單的響應函數,進而分析后續的代碼實現。打開procexp,查找該窗口對應的進程,發現是rundll32,如下:
  "C:windowssystem32rundll32.exe" Shell32.dll,Control_RunDLL mmsys.cpl,,sounds
mmsys.cpl是一個控制面板程序,CPL是PE文件,導出了CPlApplet函數,該函數是程序的邏輯入口,原型如下:
__declspec(dllexport) long __stdcall CPlApplet(HWND hwndCPL,UINT uMsg,LPARAM lParam1,LPARAM lParam2);
為了找到PopMenu窗口的消息處理過程(WndProc),首先通過spy++找到菜單所屬窗口的句柄wnd,接著寫一段代碼注入到rundll32進程中獲取:
LONG_PTR ptr = NULL;
HWND wnd = ***;
//https://blogs.msdn.microsoft.com/oldnewthing/20031201-00/?p=41673
if (IsWindowUnicode(wnd))
  ptr = GetWindowLongPtrW((HWND)wnd, GWLP_WNDPROC);
else
  ptr = GetWindowLongPtrA((HWND)wnd, GWLP_WNDPROC);
找到WndProc是ntdll!NtdllDialogWndProc_W,接著就需要條件斷點,PopMenu的菜單響應是WM_COMMAND(0x0111)消息,WndProc原型如下:
LRESULT CALLBACK WindowProc(HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
);
可知rcx是窗口句柄,rdx是消息ID,因此設置條件斷點如下:
bp ntdll!NtdllDialogWndProc_W ".if(@rcx==句柄 and @rdx==0x0111){.printf "%x %xn",@rcx,@rdx;.echo}.else{gc}"

中斷下來之后使用pc命令找到對應的調用,根據符號名能大致知道函數的功能,最后找到PolicyConfigHelper::SetDefaultEndpoint函數,調用棧如下所示:
00 audioses!PolicyConfigHelper::SetDefaultEndpoint
01 audioses!CPolicyConfigClient::SetDefaultEndpointForPolicy
02 mmsys!CEndpoint::MakeDefault
03 mmsys!CPageDevices::ProcessWindowMessage
04 mmsys!CDevicesPageRender::ProcessWindowMessage
05 mmsys!ATL::CDialogImplBaseTATL::CWindow>::DialogProc
06 atlthunk!AtlThunk_0x01
07 USER32!UserCallDlgProcCheckWow
08 USER32!DefDlgProcWorker
09 USER32!DefDlgProcW
10 ntdll!NtdllDialogWndProc_W
uf /c 查看audioses!PolicyConfigHelper::SetDefaultEndpoint調用函數如下:
0:000> uf /c audioses!PolicyConfigHelper::SetDefaultEndpoint
audioses!PolicyConfigHelper::SetDefaultEndpoint (00007ffc`6c3adc7c)
    call to audioses!GetAudioServerBindingHandle (00007ffc`6c387be4)
    call to RPCRT4!NdrClientCall3 (00007ffc`94e706f0)
    call to audioses!FreeAudioServerBindingHandle (00007ffc`6c387b78)
    call to audioses!WPP_SF_D (00007ffc`6c3643d4)
 
RPC調試方法
查看GetAudioServerBindingHandle函數:
audioses!GetAudioServerBindingHandle (00007fff`d2c07be4)
    call to RPCRT4!RpcStringBindingComposeW (00007ff8`07882e60)
    call to RPCRT4!RpcBindingFromStringBindingW (00007ff8`0788d8b0)
    call to RPCRT4!RpcStringFreeW (00007ff8`0787ab40)
可知在連接RPC服務端,得到端口句柄。接下來的NdrClientCall3便是執行RPC客戶端調用。
RPC全稱Remote Procedure Call(遠程過程調用),主要是實現客戶端的函數在服務端上下文調用,對客戶端來說像在調用本地函數一樣,為此這里會涉及幾個點:
函數原型一致
序列化/反序列化
同步異步
數據交換
內存分配
異常處理
注冊發現
傳輸方式
...
關于RPC,可以講很多東西,因篇幅有限,我將重心放在Windows的RPC,同時講一些調試技巧。對RPC感興趣的可以去看看gRPC、brpc(有很多研究資料)、Thrift,以及一些序列化協議(pb、json、mp)等。
Windows對RPC使用無處不在,COM的跨進程通信便是用的RPC,還有許多服務都提供了RPC調用接口,例如LSA、NetLogon等等。
讀者需要理清COM、RPC、LPC/ALPC之間的關聯,這里可以分三個層次:
COM -- ole*.dll、combase.dll
RPC -- rpcrt4.dll
LPC/ALPC -- ntdll!Zw*Port/ntdll!ZwAlpc*
COM在垮進程通信時會調用到RPC,RPC在本地調用時會用到LPC(本地過程調用Local Procedure Call)(也有可能是Socket/NamedPipe,大部分應該都是LPC,因為效率最高),LPC是NT舊時代的產物,Vista之后LPC升級成了ALPC,A是Advanced高級的意思,ALPC通信速度、安全性、代碼規范,可伸縮性都有提升,這些概念可以參考Windows Internals。

[1] [2] [3]  下一頁

【聲明】:黑吧安全網(http://www.zjtpzs.live)登載此文出于傳遞更多信息之目的,并不代表本站贊同其觀點和對其真實性負責,僅適于網絡安全技術愛好者學習研究使用,學習中請遵循國家相關法律法規。如有問題請聯系我們,聯系郵箱[email protected],我們會在最短的時間內進行處理。
  • 最新更新
    • 相關閱讀
      • 本類熱門
        • 最近下載
        神秘东方电子游艺