tft每日頭條

 > 生活

 > 福昕閱讀器pdf删除一頁

福昕閱讀器pdf删除一頁

生活 更新时间:2024-12-02 17:45:57

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)1

0、引言

“讨伐”的背景是這樣的,福昕pdf閱讀器打開看着某某文檔,然後其中有一段文字我想複制下,大概四五十個字吧,然後就莫名其妙的Crash了。由于之前工作的原因,我的注冊表裡一直挂着JIT,所以,Windbg就跳出來,靜靜的等着我來幹點啥。分析之餘,想不到為什麼會有這樣的“怪異寫法”。

1、案發的第一現場

先來看下案發時,當時的上下文是什麼樣子的,如下圖所示,根據經驗,基本可判斷是個0xC0000005異常了。

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)2

出bug的模塊名為frdvpr_drv,出bug的函數據Windbg報告為DrvQueryDriverInfo,但這個肯定是不對的,函數内部偏移為0x2c681即181889,都快180K了,常規的函數不可能這麼大。造成Windbg出錯的原因是沒有合适的PDB。好了,先看下frdvpr_drv這個模塊的具體信息,如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)3

根據時間戳來看,還挺新,版本也不是特别老。官網的最新版如下;

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)4

好了,現在可以确認下具體觸發此次異常的原因了,執行如下指令:

0:007> .exr -1 ExceptionAddress: 00007ff87380cb21 (frdvpr_drv!DrvQueryDriverInfo 0x000000000002c681) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 00000000067e5044 Attempt to read from address 00000000067e5044

沒錯了,就是Access violation錯誤導緻的此次慘狀。看下00000000067e5044地址附近的數據:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)5

看來這個page的狀态是free或者reserved的。反正就是不可訪問的,至于到底是哪種狀态,下邊來詳談。再來看下堆棧,看看哪裡過來的。

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)6

貌似是新開的一個線程,剛開始幹點事情就挂了。但有一個數據引起了我的注意,就是紅框上邊的這個數據,看看與之前錯問題的Addr,貌似比較接近。你先不要着急,我知道x64下,函數的調用約定規定前四個參數是通過寄存器傳遞的,但不意味着就不能在home棧中備份一下某些數據,比如這裡的數據。我們來看下這個地址附近的數據:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)7

是個unicode串,也正是我複制的那一段話,原文如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)8

好了,案發第一現場到此結束,下邊開始溯源吧。

2、觸發此bug的罪魁禍首

溯源之前,我們先來看下當前這一幀函數在幹啥,根據異常地址,在Windbg的反彙編界面中往上稍微翻譯下,可以找到該函數的開頭,如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)9

其實,看到這個函數sig,我基本可以确認這是個memcpy或者memmove之類的函數,因為之前遇到過類似的問題,看過這兩個函數的源碼,印象深刻。不知道也沒關系,下邊用IDA來打開下,因為IDA可以根據sig識别出庫函數。

0:007> ?00007ff8`7380cb21-frdvpr_drv Evaluate expression: 314145 = 00000000`0004cb21

把0004cb21偏移加到Imagebase上即可跳轉到對應的位置,如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)10

顔色就已經出賣了這個函數,意味着他是一個庫函數,旁邊的注釋表明它是一個memmove函數。翻到函數開頭,如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)11

有兩個重要信息需要說明下:

1、r11中存儲的是原始的rcx的值,即r11—->Dst;

2、rdx中存儲的是rdx-rcx的值,可通過他找到Src的值;

另外,簡單分析下就可知道,在該函數的下邊,r11,rdx和r8三個寄存器都是作為隻讀寄存器存在的,沒有被修改過。現在還原這三個寄存器的值,如下:

0:007> r r11,rdx,r8 r11=00007ff873cdea80 rdx=ffff800792b063c0 r8=0000000000000206 rdx的最初值為ffff800792b063c0 00007ff873cdea80=00000000`067e4e40 可得三個參數如下: Dst:00007ff873cdea80 Src:00000000`067e4e40 Size:0000000000000206

下邊來看下,當前這兩個内存區的數據:

0:007> du 00007ff873cdea80 00007ff8`73cdea80 "所有的組合電路都是不..可信的。是的,往往有很多的毛刺啊,或者中" 00007ff8`73cdeac0 "間過程啊不可避免的出現,這" 0:007> du 00000000`067e4e40 00000000`067e4e40 "所有的組合電路都是不..可信的。是的,往往有很多的毛刺啊,或者中" 00000000`067e4e80 "間過程啊不可避免的出現,這"

當前已經複制的長度如下:

0:007> ?rcx-r11 Evaluate expression: 516 = 00000000`00000204

而觸發Crash的那個内存地址相對于Src的地址的偏移如下:

00007ff8`7380cb21 mov ax,word ptr [rdx rcx] ds:00000000`067e5044=???? 0:007> ?00000000`067e5044-00000000`067e4e40 Evaluate expression: 516 = 00000000`00000204

這兩個是吻合的上的,現在看來,導緻Crash的原因可能如下:

1、Size有問題,即傳入的Size超過了Src的那塊内存區的大小了,訪問了後邊不該訪問的虛拟内存;

2、Size沒問題,待訪問的那塊虛拟内存某些區間被釋放掉了;

要知道這個答案,就需要溯源到上一級,因為memmove這個庫函數出問題的幾率是在太低了。溯源到上一級有兩種方法,棧回溯或者IDA的交叉引用。我喜歡棧回溯,因為他“一錘定音”,不存在多個可能。根據上一小節的棧回溯可知,caller的返回地址為:00007ff8`737d1c83,其彙編代碼如下:

0:007> ub 00007ff8`737d1c83 frdvpr_drv 0x11c5d: 00007ff8`737d1c5d je frdvpr_drv 0x11c8c (00007ff8`737d1c8c) 00007ff8`737d1c5f call qword ptr [frdvpr_drv!DrvQueryDriverInfo 0x2dc158 (00007ff8`73abc5f8)] 00007ff8`737d1c65 mov rcx,rbx 00007ff8`737d1c68 call qword ptr [frdvpr_drv!DrvQueryDriverInfo 0x2dc130 (00007ff8`73abc5d0)] 00007ff8`737d1c6e lea rcx,[frdvpr_drv!DrvQueryDriverInfo 0x4fe5e0 (00007ff8`73cdea80)] 00007ff8`737d1c75 mov r8d,206h 00007ff8`737d1c7b mov rdx,rax 00007ff8`737d1c7e call frdvpr_drv!DrvQueryDriverInfo 0x2c4b0 (00007ff8`7380c950) ;memmove(0x00007ff8`73cdea80,rax,0x206)

上邊這段代碼翻譯完就是memmove(0x00007ff8`73cdea80,rax,0x206);我第一眼看到就感覺好奇怪,為啥把這個Size寫死了,為啥要硬編碼?帶着疑問我們在往上翻一下,看看這個rax的值哪來的。

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)12

1,2,3号函數分别如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)13

即:

1—->調用的是hClipboard = USER32!GetClipboardData(),而且傳入的 uFormat參數由圖可知是0x0D,即CF_UNICODETEXT;

2—->調用的是KERNEL32!GetLastErrorStub();

3—->調用的是lpMem = KERNEL32!GlobalLock(hClipboard);

4—–>memmove(0x00007ff8`73cdea80,lpMem,0x206)

都清楚了,原來是從剪貼闆中讀取UNICODE字符串,然後硬編碼的Size為0x206;下邊我們去IDA中看下,是不是這個邏輯,如下圖:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)14

完全一樣,好了,看一下unk_18051EA80這個全局變量,他的大小估計也是在0x206附近,确認下,如下圖:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)15

現在可以完全推導出當時這個源碼了,應該是這樣的:

unk_18051EA80[0x208]={0}; memmove(unk_18051EA80,lpMem,sizeof(unk_18051EA80)-sizeof(WCHAR));

3、定因

在第2節中提出來的兩個原因,基本可以确定為Size過大了,下邊簡單看下後邊的那塊内存的屬性。如下:

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)16

福昕閱讀器pdf删除一頁(對福昕pdf閱讀器的一次)17

到此,便結束了。實在是不該出現這樣的問題。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved