2015年1月7日 星期三

以Debugger原理拆解LINE的Anti-Debug Attach

在Windows版上的LINE開啟後,如果使用Cheat Engine做進程掛接上去,會看到LINE直接崩潰掉.

先單看Windows提供的一組WinAPI怎麼建立Debugger機制:

Win32 Debug API 原理

使用VS调试时,被调试进程如何被断下来的。

【原创】反OD调试的一些想法与实践


看完之後會知道Debugger的核心機制是:

1.創建進程(CreateProcess)使用DEBUG_PROCESS這個Flag,此時該進程內的PEB中的BeingDebugged Flag會被設為True,呼叫完後,進成被創建完就會先是被凍結主線程(UI Thread)的進程了.

2.接著激活主線程後,WinNT消息機制發現了BeingDebugged為True,就會主動調用
DbgBreakPoint API,在組語上遇到了int 3(0xCC)線程又會被凍結,然後會反彈一個Create_PROCESS_DEBUG_EVENT訊息回去給父進程,給Debugger做事情.

3.如果Debugger想下新的Ring3層斷點,會先用CreateThread在指定進程中創線程,使此線程Call DbgUiRemoteBreakin,那麼指定進程內所有線程就會被Debugger掛起.那麼Debugger便可以對需要的指定記憶體段下int 3異常點.DbgUiRemoteBreakin內可以看到所有線程主動去Call DbgBreakPoint來把當前線程控制權交給Debugger.

4.如果是進程已經被運行,Debugger才去Attach,則用到DebugActiveProcess去Attach指定進程,接著BeingDebugged又會被設為True,然後做異常機制的掛起線程.

最後我比較好奇的是
DbgUserBreakPoint函數內寫法跟DbgBreakPoint其實一模一樣,我不太懂微軟幹嘛把同個功能寫成兩個不同的API?

接著總結一下
所以一般Ring3層需要防Debugger可能會防止
1.自身DbgBreakPoint被呼叫.(只要此函數呼叫了便把控制權交出去了)
2.自身DbgUserBreakPoint被呼叫.
3.自身DbgUiRemoteBreakin被呼叫.(此函數會導致所有線程去呼叫上述其一API)

先看一下LINE的資料夾:
可以看得出來資料夾內沒有任何驅動文件,確定了LINE本身走純Ring3的Anti-Debugger.

我們可以用CE檢查一下LINE對上述三個API做了什麼事情
先是前兩條API:
可以看到的是,LINE的工程師蠻瞧不起DbgUserBreakPoint的,根本不去處理它.

不過DbgBreakPoint這條API原本是int 3的OP Code卻被改成了ret,意味著就算DbgBreakPoint被呼叫了,該進程就會直接無視這函數原本要做的int 3然後繼續做接下來的事情.
所以我們要做的事情就是幫int 3恢復回來

接著看到DbgUiRemoteBreakin API的記憶體內容:
它在API入口就下了jmp NtDll.LdrShutdownProcess,如果這個DbgUiRemoteBreakin被呼叫就直接跳轉到LdrShutdownProcess這個API做自我進程關閉的動作.
而且蠻有趣的地方是,它jmp完底下還有2個Byte沒有做清除乾淨的動作XD,看來LINE工程師也想說能用就好惹,不講求看起來記憶體乾淨整潔啊~~
一樣,幫它把API入口做恢復:
OK,三個API都做完修正了. 把CE Attach上去LINE身上看看:
大功告成,成功Attach上去了,LINE不會崩潰了.


...是說,Hook這三個API的做法...好像跟Garena競時通做法完全一模一樣呢,不知道是誰抄誰XD