Friday, June 18, 2010

How to check top level unhandle exception filter by windbg

Many applications use SetUnhandledExceptionFilter to catch unexpeted exception. This API let application be able to hook top-level exception handler of a process. Through it app has a chance to dump debugging information or report abnormal status before process exit. This function also be used as an anti-debugging trick: If a debugger attach to a process, top-level exception handler won’t be invoked, so we can hide our logic inside the exception handler.

Sounds good, but there can be only one top-level exception handler for a process. If not only one module, could be legacy code or 3-party lib, uses SetUnhandledExceptionFilter, the result may be unwanted.

How to check top-level exception handler by windbg? Although this is a process-specific information, we need full memory dump or two machine live debugging to get the handler. First, set the process context to the process you want to check, search for the       kernel32!BasepCurrentTopLevelFilter, this is where the pointer to the top-level exception handler stored :

   1: kd> x kernel32!BasepCurrentTopLevelFilter 
   2: 76d0a5d0 kernel32!BasepCurrentTopLevelFilter = 
   3: kd> dd 76d0a5d0 L1 
   4: 76d0a5d0  d849453d 

So the address of the handler is 0xd849456d? No. Since WinXP SP2, Windows will encoding the addres. We have to decode it. On Vista SP2, basicly encoding is XOR with process cookie. Cookie is avaliable in EPROCESS structure. That is why we need full memory dump or two machine live debugging.

   1: kd> dt _EPROCESS 83625d90       
   2: ntdll!_EPROCESS 
   3:    +0x000 Pcb              : _KPROCESS 
   4:    +0x080 ProcessLock      : _EX_PUSH_LOCK 
   5:    +0x088 CreateTime       : _LARGE_INTEGER 0x1cb01ba`83f00f26 
   6:    … skipped
   7:    +0x234 PriorityClass    : 0x2 '' 
   8:    +0x238 VadRoot          : _MM_AVL_TABLE 
   9:    +0x258 Cookie           : 0x4905fc08 
  10:    +0x25c AlpcContext      : _ALPC_PROCESS_CONTEXT 

Cookie is 0x4905fc08. The encoding process also include magic number and shift operation. Let’s check the assembley of decoding :

   1: kd> uf ntdll!rtldecodepointer 
   2: ntdll!RtlDecodePointer: 
   3: 77170a18 8bff            mov     edi,edi 
   4: 77170a1a 55              push    ebp 
   5: 77170a1b 8bec            mov     ebp,esp 
   6: 77170a1d 51              push    ecx 
   7: 77170a1e 6a00            push    0 
   8: 77170a20 6a04            push    4 
   9: 77170a22 8d45fc          lea     eax,[ebp-4] 
  10: 77170a25 50              push    eax 
  11: 77170a26 6a24            push    24h 
  12: 77170a28 6aff            push    0FFFFFFFFh 
  13: 77170a2a e865f40200      call    ntdll!ZwQueryInformationProcess (7719fe94) 
  14: 77170a2f 85c0            test    eax,eax 
  15: 77170a31 0f8cf8660400    jl      ntdll!RtlDecodePointer+0x1b (771b712f) 
  16:  
  17: ntdll!RtlDecodePointer+0x21: 
  18: 77170a37 8a45fc          mov     al,byte ptr [ebp-4] 
  19: 77170a3a 241f            and     al,1Fh 
  20: 77170a3c b120            mov     cl,20h 
  21: 77170a3e 2ac8            sub     cl,al 
  22: 77170a40 8b4508          mov     eax,dword ptr [ebp+8] 
  23: 77170a43 d3c8            ror     eax,cl 
  24: 77170a45 3345fc          xor     eax,dword ptr [ebp-4] 
  25: 77170a48 c9              leave 
  26: 77170a49 c20400          ret     4 
It will be painful to use calculator to decode, so I made a small program :
   1: void main(){ 
   2:  DWORD Pointer = 0xd849456d ; 
   3:  DWORD Cookie = 0x4905fc08; 
   4:  DWORD result = 0; 
   5:  // 
   6:  //decoding process 
   7:  // 
   8:  __asm{ 
   9:   mov     al,byte ptr [Cookie] 
  10:   and     al,1Fh 
  11:   mov     cl,20h 
  12:   sub     cl,al 
  13:   mov     eax,dword ptr [Pointer] 
  14:   ror     eax,cl 
  15:   xor     eax,dword ptr [Cookie] 
  16:   mov     result,eax 
  17:  }; 
  18: } 
The result is 0x0040C1DO, it is the current top-level exception handler. Use “ln” to check if it is what we want.
   1: kd> ln 0040C1D0 
   2: d:\xxx\src\utility\util_crashhandler.cpp(xxx) 
   3: (0040c1d0)   xxx!CrashHandlerExceptionFilter   |  (0040c310)   xxx!SetCrashHandlerFilter 
   4: Exact matches: 
   5:     xxx!CrashHandlerExceptionFilter (struct _EXCEPTION_POINTERS *) 

Sunday, March 28, 2010

Understanding oplock and avoid sharing violation

Opportunistic locking (oplock) is a cache coherence protocol. General relations between Local FSD(file system driver), Server FSD, user and filter driver can be described in the picture below :
oplock
In this sharing we are going to disscus the problem that oplock wants to solve, FILE_COMPLETE_IF_OPLOCKED flag, and different types of oplock.

Filter oplock was introduced on Windows 2000, it was design to solve sharing violatoin issue. For example, we have a kernel driver that will access \systemroot\OplockTest with only share access FILE_SHARE_READ. Now if we use notepad to modify the file at the same time, a sharing violation will occure :
ShareViolation
With filter oplock, kernel driver will be notified if a sharing violation is happenning. After driver acknowledge oplock break, notepad will be able to modify the file without sharing violation. User is totally unware all of these events.
Acknowledge Oplock Break
Although we give a kernel mode example here, we can use filter oplock in user mode. Simply replace the function with Win32 API and use DeviceIoCtl to send FSCTL_REQUEST_FILTER_OPLOCK request.
status = ZwCreateEvent(&EventHandle,
EVENT_ALL_ACCESS,
0,
NotificationEvent,FALSE);
if (NT_SUCCESS(status))
{
InitializeObjectAttributes(&oa,
MagicFilePath,
OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
0,0);
//notice here, AP will get sharing violation 
//if they try to modify 
//"\\SystemRoot\\OplockTest", 
//with oplock we can avoid sharing violation.   
status = ZwCreateFile(&MagicFileHandle,
GENERIC_READ,
&oa,
&iosb,
0,
0,
FILE_SHARE_READ,  
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE,0,0);
 
if (NT_SUCCESS(status))
{
status = ZwFsControlFile(MagicFileHandle,
EventHandle,
NULL,
NULL,
&iosb,
FSCTL_REQUEST_FILTER_OPLOCK,
0,
0,
0,
0);
//
//STATUS_PENDING means we got oplock, 
//
if (status == STATUS_PENDING)
{
//
//Event will be signalled when sharing  
//violation happen. Polling the oplock event to 
//see if the oplock has broken. You can 
//wait for the event in a different thread.
//
LARGE_INTEGER  Timeout;
Timeout.QuadPart = (LONGLONG)-10000000;
while(TRUE)
{
 
status = ZwWaitForSingleObject(
EventHandle,
false,
&Timeout);
if (!NT_SUCCESS(status))
{
//
//error happened
//
goto CleanupAndExit;
} 
else if(status == STATUS_TIMEOUT)
{
//
//  Perform major task here.  
//
 
KdPrint(("access file...\n",
status));
continue;
}
else
{
//
//Some operation is waiting 
//quickly finish up and get out. 
//
KdPrint(("ackonwledge oplock break \n",
status));
goto CleanupAndExit;
}
}
}
}        
}
CleanupAndExit:
if (MagicFileHandle)
{
//
//close handle will relinquishes oplock (acknowledge 
//the oplock break) Until acknowledge oplock break 
//AP thread will <<<<<HANG>>>>> if AP doesn't specify 
//FILE_COMPLETE_IF_OPLOCKED in CreateFile
//
ZwClose(MagicFileHandle);
MagicFileHandle = 0;
}

Friday, March 19, 2010

How to develop a user mode debugger under Windows / x86 platform

 

Have you ever wonder how Visual Studio do debugging things like the picture below?

Picture1

I made a slide about how to implement a debugger on Windows / x86 platform. In this sharing, we will discuss the challenge for OS to support a ring 3 debugger, the overview of Windows Ring 3 debugging, and how to implement the basic features of a debugger.

Friday, September 4, 2009

[紀錄]送明焱

分開後,下次見面不知道是多久之後的事情

今晚在台北街頭的不是世界級駭客跟世界級書匠

只是兩個二十幾歲的年輕小夥子.

無話不聊,無話不聊

謝謝你,從你身上學到很多.

加油,相信你會發展的很好. :)

Thursday, May 7, 2009

布達佩斯忙裡偷閒

這個禮拜被派去匈牙利首都布達佩斯參加會議,第一次一個人跑到地球的另外一邊,出發前心情有點忐忑。台北沒有直達布達佩斯的班機,所以必須先飛香港、轉機到德國、再轉小飛機到布達佩斯。
在慕尼黑的時候小緊張了一下,被海關當做偷渡客 ,不過因為匈牙利簽證天衣無縫(廢話本來就是真的) 也有回程機票,就讓我走了。哈哈!
 P1020483
Budapest給我的感覺有點介於台南與花蓮市之間 ,建築挺漂亮,但是現代化的程度還ok而已。物
價在歐洲應該算偏低,比台北略高吧!一份麥當勞大約快兩百台幣。想要用少少的經費體驗歐洲風情,這裡算是自助不錯的選擇。

抵達之後,立刻到information center換福林以及買Budapest card。
我買的Budapest card是三日票,可以免費達乘大眾交通工具,多處景點也有折扣。
不過如果只需要免費坐捷運跟公車,推薦更划算的One-day travel card,每人1500福林。
如果算的更精一點,捷運及公車的單程票是290福林,制定好計畫是有可能把一天的車費降的更低一些。建議至少第一天買張One-day travel card,來回坐公車捷運熟悉一下街道以及方向。

隨後做200E公車前往捷運站Kobanya-Kispest,路上遇到馬來西亞華僑,閒聊了一下.。
到捷運站之後,坐了12站抵達旅館附近的站點Nyugati pu。
P1020447

說是捷運,其實只不過是我們的台鐵普通車在地底下跑,挺有歷史的。
出了捷運站找了一下路,最後順利抵達旅館check-in。
發了報平安的訊息之後,衣服也沒換澡也沒洗,立刻出門找market買水。
Budapest沒有看到國際連鎖知名的超商,為了找買水的地方,第一天就破了自助旅行的大忌,一個人在小巷子裡子來走去。最後眼尖看見一間店鋪有賣水,買了水之後出門想認 一下標誌,原來布達佩斯的超商外面掛的牌子是可口可樂的標誌,還會有一個0-24的牌子。

回旅館休息,洗了澡小憩片刻,安排了幾個景點之後又出門了。
第一站坐捷運來到Opera,這座Opera有超過百年的歷史,本來想買張票,但是5/1剛好公休。只好前往下一站位於Kossuth ter站的國會大廈。之前就聽說布達佩斯的國會大廈是歐洲最美,哈,就來見識一下有多美。
P1020457
結果一出站,映入眼簾的國會大廈果然美的讓我停止呼吸... 不過!!5/1似乎也沒有開放內部導覽,扼腕阿!! 好吧,那只好去國會對面的博物館繞繞,這間博物館應該是以前王宮貴族的家改造的。內部雖然只有三層,卻大到讓我迷路。不過展出的東西實在是沒什麼,有騙錢的嫌疑。(門票600福林)

參觀完以後,坐上國會門口的2路電車,沿著多瑙河欣賞一下風光.當電車開到Erzsebet橋
附近時,決定上橋走走.這一走就開啟了兩小時的走路旅程...
倒也不是橋太長走不完,而是走到另外一端時發現許多觀光客朝一個小丘的階梯拾級而上.
我也就跟上瞧瞧有什麼好玩的. 爬到一半竟然看到St.Gellert的雕像!
這是原本想要來的景點,但因為沒有大眾交通工具直達而放棄.想不到竟然莫名其妙的就到了...XDXD
P1020475

繼續向上爬,爬到飢腸轆轆氣喘如牛,但是沿途卻賞了不少配斯以及多瑙河的好風景.最後終於到了丘頂,看到了Liberation Monument,趕快買了支雪糕補充體力.XD
註:後來才知道在M2的Astoria站搭乘47,49路面電車過多瑙河在蓋雷特酒店前下車,那站是蓋雷特山比較正統的登高起點.還可以洗溫泉喔!山上看夜景也是很美的!

下了小丘又沿著橋走回配斯,途中順著人群到達一個戶外演唱會的地點,人很多很high,可惜聽不懂.看地圖決定去著名的Vaci大街瞧瞧.這條街是以餐館跟紀念品聞名,相當漂亮的歐洲大街.話說歐洲人好像很喜歡在戶外吃,就連漢堡王也要在店外面圍一圈讓客人坐. Vaci street的另外一端是Central Marcket,最大的傳統市場.但是今天竟然休市! 這時候我才發覺這城市怎麼了,沿街的商店幾乎都是休市,遊客似乎比居民還多XD 可能5/1是什麼重大節日吧.那只後之後有緣再來拜訪了.

走了一下午腳也酸了.乾脆坐上49路電車,來來回回的欣賞布達佩斯的城市風光.最後時差發作,竟然在電車上睡著了哈哈.買了麥當勞跟水之後就回飯店休息了.

(Day 2)
P1020487 
今天早上出門,特地先去參觀了旅館附近的火車站.整體感覺挺有歷史的,沒有剪票口,要上車是滿容易的,哈哈。 出了火車站搭上四路公車,前往Moszcva廣場.途中經過Margit橋,可以到達號稱多瑙河綠寶石的Margit island,如果星期日有時間的話再來參觀.(六路也可以到)

到了Moszcva廣場滿滿的都是人,這裡不只是布達城捷運與公車的交會點。也是前往城堡山的搭車起點.上坡之後搭上16路公車,行駛一小段之後我就後悔了.因為城堡山其實算個小丘.不陡路途也不長,其實讓公車開一站進入城堡山之後,就可以下車步行.當機立斷,馬上在城堡山城門口下車,開始了一整天的暴走 XDXD
P1020502

城門口附近是數間博物館,有的展覽兵器,也有的是歷史文物.布達佩斯身為一個遊客比居民多的城市,廣設博物館是很聰明的事情.整個城市博物館總數應該有五十座,不知道要逛哪邊的話,就逛逛博物館吧! 第二聰明的事情就是公共廁所要收錢.博物館沒興趣,廁所總是要上的吧XD 在門口收錢的可不是凶神惡煞的地頭蛇,是文質彬彬的政府公職,旁邊還擺一台收銀機可以找錢XD.

扯遠了,入了城堡山門口之後變開始步行,印入眼簾的是漂亮的建築物以及壯觀的教堂.參觀了漁夫堡,馬提亞斯教堂,最令我印象深刻的還是Royal Palace.匈牙利皇室似乎喜歡以威猛的雄獅為誌,到處可見栩栩如生的獅像.
P1020527

城堡山的景色實在是很美,不論是建築物的壯觀,或是向山下眺望多瑙河,都讓人流連忘返.
P1020537

中午在皇宮附近用餐之後,在附近看好了一條下山小徑,沿著小徑行走,不一會兒就抵達百年歷史的Szechenyi chain bridge.
P1020550
過了橋之後買了支雪糕在公園裝悠閒,這裡剛好位於 M1捷運的起點Vorosmarty,那就去昨天無緣的Oprea吧! 今天果然有開張!晚上歌劇最便宜有500福林的座位,不過要聽到九點半. 一個小時的參訪要價3000福林...好詭異的比例,讓我考慮一下吧...

買了一些紀念品之後,繼續沿著歐洲最古老的地鐵M1 前往Szechenyi furdo站.這一站可以去泡溫泉,聽說容易遇到同性戀 XDXD

一出站就是中央公園,許多匈牙利人在這裡遊玩,很熱鬧. 往Andrassy大道的方向走(可以感受到地鐵在腳下震動@"@),不一會兒就到達英雄廣場.這座廣場是百年前為了紀念匈牙利建國一千年而造,有許多匈牙利英雄的雕像,非常漂亮,還遇到新人來這裡拍婚紗,實在是很幸福呢  ^^Y
P1020567 
出了英雄廣場之後,又沿著Andrassy這條很舒服的大道走了一站,Bajza u.我遇到了11路公車的極限,一整天的行走讓我左腳膝關節不舒服.只好去超市買了水,牛奶跟麵包。然後回到旅館休息.

傍晚六點半,躺在床上還在想晚餐要吃什麼,疲倦感襲來,就這樣睡了11個小時. XDXD