讀書筆記之《格蠹彙編-軟體除錯案例集錦》
阿新 • • 發佈:2019-01-25
17. MSN的死迴圈。CPU佔用100%有2種情況,第一種:病毒掃描程式或索引服務需要處理大量事務,第二種:程式BUG內部死迴圈。MSN屬於第二種,WinDbg附加程序。尋找死迴圈執行緒。方法有4種,方法1:如果是GUI程式,介面失去響應,一般是UI執行緒問題,通常0號執行緒就是UI執行緒。方法2:使用~*e.ttime
列出每個執行緒執行時間,根據執行時間來尋找可疑執行緒。方法3:如果執行緒不多可以用~*kv列出每個執行緒棧回溯,根據函式資訊判斷可疑執行緒。方法4:使用Process Explorer觀察工具,檢視程序各個執行緒CPU佔用率,優先檢查佔用率高的執行緒。這裡由於MSN介面失去響應所以使用方法1 ~0s 。
->熟悉現場的資訊,kn 100檢視棧回溯,缺少除錯符號顯示不全,只有00 0006fb045 5fc021e3 msvcr80!_vsnwprintf_s+0x19顯示正確,bp msvcr80!_vsnwprintf_s+0x19,g該恢復執行發現不斷中斷到此函式,說明此函式處於迴圈內部。顯示棧幀基地址附近資料dd 0006fb045,得到第一個引數地址01939ff5(EBP+8),dU 01939ff5出現除錯資訊,觀察更多資訊bp msvcr80!_vsnwprintf_s+0x19 "dU poi(@ebp+8);kv 3;gc"命令表示條件中斷到偵錯程式後執行列印引數1,顯示3個棧幀的棧回溯,然後恢復執行。執行後出現大量資訊,ctrl+break中斷到偵錯程式。
-> 定位死迴圈的函式,方法有2種,方法1:對棧回溯中每個棧幀返回點由上到下依次設定斷點,如果反覆命中說明此函式可以返回上一級,不是問題所在解除此斷點,對下一個棧幀返回地址設定斷點,如此重複直到設定斷點恢復執行後程序出現死迴圈,說明死迴圈放生在當前函式中。方法2:選取2次棧回溯,從下至上比較最後一列,最後一個相同的地址代表可能是死迴圈所在函式,對其設斷用方法1判斷,如果不是再次取樣比較。選用方法2,發現最後一個相同點是CreateObjectStoreService+0x14969
,設定斷點對其返回再設一個斷點,bp LiveTransport!CreateObjectStoreService+0x14969 ,bp LiveTransport!CreateObjectStoreService+0x14c24
發現始終命中0x14969返回點0x14c24不命中,說明死迴圈發生在0x14969所在的函式中,反向反彙編0x14c24, ub LiveTransport!CreateObjectStoreService+0x14c24得到 call LiveTransport!CreateObjectStoreService+0x145ad(5f342ff1),由於缺少除錯符號顯示的符號資訊是就近的,是不準確的,所以死迴圈函式是5f342ff1,不知道名稱。接下來就是分析程式碼。
->入口指令sub esp,2Ch推斷區域性變數區長度0x2c即44位元組,根據"EBP-n"索引區域性變數原則,發現指令中有ebp-4,ebp-14,ebp-2c共3種寫法,推斷第一變數長度是4位元組可能是整數或指標,後兩個分別是16位元組,24位元組可能是結構體。根據"EBP+n"索引引數的規律,找到ebp+8所以此函式只有一個引數,觀察ECX的使用,推測是C++類的方法,ECX中傳遞this指標。手動跟蹤可以發現死迴圈點
5f3430b5 call LiveTransport!CreateObjectStoreService+0x32e11(5f361555)
5f3430ba cmp dword ptr [ebp-4],0
5f3430be jne LiveTransport!CreateObjectStoreService+0x148e0(5f343024)
5f3430c4 push 0Ah
呼叫函式,比較區域性變數,條件跳轉,並沒有用到函式的返回結果,懷疑是否應該把返回值賦值給區域性變數再比較呢?漏洩了程式碼?追蹤區域性變數。
->從棧回溯中得到這個棧幀基地址是0006fc78 所以ebp-4是0006fc74,ba w4 0006fc74其中ba是記憶體斷點,當對0006fc74到(0006fc74+4)地址寫操作時斷下,bd禁止其它斷點然後恢復MSN執行,斷下後分析函式發現,死迴圈沒對EBP-4區域性變數賦值,它的子函式賦值的,解除了先前的疑問。模擬執行觀察下情況,執行recx=poi(ecx);r ecx;z(ecx!=0)迴圈命令,其含義是把ecx所在地址的值賦給ecx,顯示ecx,反覆操作直到ecx為0。執行後發現不停迴圈,ctrl+break停止。修復死迴圈,方法有2種,方法1:修正資料,讓迴圈自然結束,方法2:修改EIP跳出迴圈,這裡使用方法2,be命令恢復前面的斷點,恢復執行,斷下後單步來到jne修改EIP,R eip=5f3430c4,來到下一條指令跳出迴圈執行g,MSN繼續執行正常了。
->熟悉現場的資訊,kn 100檢視棧回溯,缺少除錯符號顯示不全,只有00 0006fb045 5fc021e3 msvcr80!_vsnwprintf_s+0x19顯示正確,bp msvcr80!_vsnwprintf_s+0x19,g該恢復執行發現不斷中斷到此函式,說明此函式處於迴圈內部。顯示棧幀基地址附近資料dd 0006fb045,得到第一個引數地址01939ff5(EBP+8),dU 01939ff5出現除錯資訊,觀察更多資訊bp msvcr80!_vsnwprintf_s+0x19 "dU poi(@ebp+8);kv 3;gc"命令表示條件中斷到偵錯程式後執行列印引數1,顯示3個棧幀的棧回溯,然後恢復執行。執行後出現大量資訊,ctrl+break中斷到偵錯程式。
->
,設定斷點對其返回再設一個斷點,bp LiveTransport!CreateObjectStoreService+0x14969
發現始終命中0x14969返回點0x14c24不命中,說明死迴圈發生在0x14969所在的函式中,反向反彙編0x14c24, ub LiveTransport!CreateObjectStoreService+0x14c24得到 call LiveTransport!CreateObjectStoreService+0x145ad(5f342ff1),由於缺少除錯符號顯示的符號資訊是就近的,是不準確的,所以死迴圈函式是5f342ff1,不知道名稱。接下來就是分析程式碼。
->入口指令sub esp,2Ch推斷區域性變數區長度0x2c即44位元組,根據"EBP-n"索引區域性變數原則,發現指令中有ebp-4,ebp-14,ebp-2c共3種寫法,推斷第一變數長度是4位元組可能是整數或指標,後兩個分別是16位元組,24位元組可能是結構體。根據"EBP+n"索引引數的規律,找到ebp+8所以此函式只有一個引數,觀察ECX的使用,推測是C++類的方法,ECX中傳遞this指標。手動跟蹤可以發現死迴圈點
5f3430b5 call LiveTransport!CreateObjectStoreService+0x32e11(5f361555)
5f3430ba cmp dword ptr [ebp-4],0
5f3430be jne LiveTransport!CreateObjectStoreService+0x148e0(5f343024)
5f3430c4 push 0Ah
呼叫函式,比較區域性變數,條件跳轉,並沒有用到函式的返回結果,懷疑是否應該把返回值賦值給區域性變數再比較呢?漏洩了程式碼?追蹤區域性變數。
->從棧回溯中得到這個棧幀基地址是0006fc78 所以ebp-4是0006fc74,ba w4 0006fc74其中ba是記憶體斷點,當對0006fc74到(0006fc74+4)地址寫操作時斷下,bd禁止其它斷點然後恢復MSN執行,斷下後分析函式發現,死迴圈沒對EBP-4區域性變數賦值,它的子函式賦值的,解除了先前的疑問。模擬執行觀察下情況,執行recx=poi(ecx);r ecx;z(ecx!=0)迴圈命令,其含義是把ecx所在地址的值賦給ecx,顯示ecx,反覆操作直到ecx為0。執行後發現不停迴圈,ctrl+break停止。修復死迴圈,方法有2種,方法1:修正資料,讓迴圈自然結束,方法2:修改EIP跳出迴圈,這裡使用方法2,be命令恢復前面的斷點,恢復執行,斷下後單步來到jne修改EIP,R eip=5f3430c4,來到下一條指令跳出迴圈執行g,MSN繼續執行正常了。