MFC 程式的跟蹤 (一) (6千字)

看雪資料發表於2001-05-01

MFC  程式的跟蹤 (一)

工具(選用最新版本)
1    Win32Dasm
2    IDA Pro
3    HexEditor
4    SICE

目標
http://soft.269.net/SoftWareView.asp?SoftWareID=21721
這東西如何用還未知道,只知道是做圖表的,但一些工能被停用了,會跳出Demo版無此工能的對活框

目的
去除Demo對活框,恢復原有工能

小知識
MFC程式有兩種,一是所謂靜態庫(static library),另一種是分享動態連線庫(shared dll)
第一種程式比較完整,所有工能碼都附在程式內,另一種工能碼跟別人分享,所以
會有很多轉跳,上面程式應是第二種,而分享動態連線庫是MFC42.DLL,又MS把這連線庫
的名字都用序號,Ordinal:09CE之類,令人混淆不清.

正題
開啟程式,隋意做些圖表,開啟File選單,可看到存檔(Save/Save AS子選單沒有喪失工能),按Save As一下,Demo 指示跳出.那麼把Demo框去除,跳回Save As子程式,那不是很容易嗎?正是!整個過程就是做這個事情.但到底什樣做?
Demo框是目標之一,就拿它下手,用W32Dasm把主程式反匯一下(這是我一貫做法),分析後發現這Demo框字串出現有二十三處之多,也弄不清是那一個對應Save As選單,就把每個對應地址記下,開啟ICE  Loader載入主程式,當停在程式入口處的時候,把記下的地址一一 bpx XXXXXXXX 加入斷點,F5執行程式,再選Save AS, 程式中斷在4C2940,返回W32Dasm,逆流而上,看看源頭是什麼樣,結果令人失望.
:0040187A E941A61100              jmp 0051BEC0
:0040187F E94CE91700              jmp 005801D0
:00401884 E977D20400              jmp 0044EB00 ß--其中一起始點

這起始點就是Save As子程式的入口點,很明顯是沒有被任何直接呼叫.

小知識
在x86彙編的定址模式中,有直接定址和間接定址, 直接定址易明不用多說了, 間接定址也經常在PE程式中出現如 Call dword ptr [edx+000000A0],這種定址模式反彙編是無法反的.在這例子中,edx是這表的最底部,而00A0是偏移量,注意這模式,後面會用到.

靜態分析碰釘,改動態分析, 開啟ICE  Loader載入主程式,當停在程式入口處的時候,下bpx 4C2940,當經過一輪鼠工之後,程式斷在4C2940處,

:004C2940 6AFF                    push FFFFFFFF
:004C2942 6A00                    push 00000000

* Possible Reference to String Resource ID=00144: "This function is not available in the demo."
                                  |
:004C2944 6890000000              push 00000090

* Reference To: MFC42.Ordinal:04AF, Ord:04AFh
                                  |
:004C2949 E874981200        Call 005EC1C2 ß- MessageBox ???
:004C294E 33C0                    xor eax, eax
:004C2950 C20800                ret 0008

這時在4C2950處又下一斷點,F5執行程式,Demo框字串出現,按OK,又中斷在4C2950處,這時按一下F8,程式轉到下面6C3D0A64的MFC42.DLL裡

Exported fn(): Ordinal:1209 - Ord:1209h
:6C3D0A58     8B01                      mov eax, dword ptr [ecx]
:6C3D0A5A     6A01                      push 00000001
:6C3D0A5C     6A00                    push 00000000
:6C3D0A5E     FF90A0000000  call dword ptr [eax+000000A0]
:6C3D0A64     C3                        ret

好了,那就是說6C3D0A5E這個Call產生Demo框了,跟蹤一下這個Call [eax+000000A0]=Call [62D5BC+A0]àCall [62D65C]==Call 402F7C.

:00402F7C E9BFF90B00              jmp 004C2940

從MFC42.DLL反回主程式,又碰釘了,但是奇怪的為什麼要從MFC42.DLL反回主程式?看看
這62D65C(RVA)== 22D65C(File)的位置


0022D640  3B 9D 40 00 10 C8 5E     00  0A C8 5E 00 04 C8 5E 00 
0022D650  57 72 40 00 E2 CB 5E      00  F2 C7 5E 00 7C 2F 40 00 
0022D660  E6 C7 5E 00 E0 C7 5E       00  DC CB 5E 00 D6 CB 5E 00 

就是地址列表(Relocation table),但都是從005EXXXX 開始,只有00402F7C有點奇怪,看看
005EC804 是什麼樣


* Reference To: MFC42.Ordinal:15C9, Ord:15C9h
                                  |
:005EC804 FF25FC736800            Jmp dword ptr [006873FC]

又看看006873FC是什麼樣

:00620FF6 00000000000000000000    BYTE 10 DUP(0)

oops W32Dasm 最多到00621000 ,沒有選擇,用IDA Pro 反一下


06873E8 ; public: virtual int __thiscall CDocument::DoFileSave(void)
006873E8                extrn ?DoFileSave@CDocument@@UAEHXZ:dword
006873E8                ; DATA XREF:CDocument::DoFileSave(void) r
006873EC ; public: virtual int __thiscall CDocument::DoSave(char const *,int)
006873EC                extrn ?DoSave@CDocument@@UAEHPBDH@Z:dword
006873EC                ; DATA XREF: CDocument::DoSave(char const *,int) r
006873F0 ; public: virtual void __thiscall COleDocument::PreCloseFrame(class CFrameWnd *)
006873F0                extrn ?PreCloseFrame@COleDocument@@UAEXPAVCFrameWnd@@@Z:dword
006873F0                ; DATA XREF: COleDocument::PreCloseFrame(CFrameWnd *) r
006873F4 ; public: virtual int __thiscall COleDocument::SaveModified(void)
006873F4                extrn ?SaveModified@COleDocument@@UAEHXZ:dword
006873F4                ; DATA XREF: COleDocument::SaveModified(void) r
006873F8 ; public: virtual int __thiscall CDocument::CanCloseFrame(class CFrameWnd *)
006873F8                extrn ?CanCloseFrame@CDocument@@UAEHPAVCFrameWnd@@@Z:dword
006873F8                ; DATA XREF: CDocument::CanCloseFrame(CFrameWnd *) r
006873FC ; public: virtual void __thiscall CDocument::ReleaseFile(class CFile *,int)
006873FC                extrn ?ReleaseFile@CDocument@@UAEXPAVCFile@@H@Z:dword



看到這些字是不是很有意思,DoFileSave,DoSave等等,都是跟儲存檔案有密切關係。

小知識
在「深入淺出 MFC」,Dissecting MFC  第四部分 第八章. Document View 深入探討 裡,對於程式的讀寫都講解得很詳細,這是MFC四大天王其中之一是本很好的書. http://www.csdn.net/expert/jjhou/


既然MFC42.DLL裡別有洞天,我們便把這DLL反一下, 詳細的看一看.

Exported fn(): Ordinal:1208 - Ord:1208h
:6C3D0A50 8B01                    mov eax, dword ptr [ecx]
:6C3D0A52 FFA0A4000000            jmp dword ptr [eax+000000A4]

Exported fn(): Ordinal:1209 - Ord:1209h
:6C3D0A58 8B01                    mov eax, dword ptr [ecx]
:6C3D0A5A 6A01                    push 00000001
:6C3D0A5C 6A00                    push 00000000
:6C3D0A5E FF90A0000000            call dword ptr [eax+000000A0]
:6C3D0A64 C3                      ret

在上面Ord:1208h及Ord:1209h便是MFC OnFileSave( )及OnFileSaveAs( )的入口點,最後會轉到DoSave( ) Ord:09EEh上,詳細情況可看 深入淺出 MFC一書.

Exported fn(): Ordinal:09EE - Ord:09EEh
:6C3D0AA0 B86F3F406C              mov eax, 6C403F6F

* Reference To: MSVCRT._EH_prolog, Ord:0042h
                                  |
:6C3D0AA5 E8D305FAFF              Call 6C37107D

你會問為什麼我會知道這些入口點的名稱,答案==IDA Pro+學作+練習

現在程式的來龍去脈都清楚了,只要把call [eax+000000A0]從顯現Demo框改到DoSave( )上便可存檔,什麼樣改就不用說了,最後列印是用OnFilePrint( ).

結語
主要修改為下
存檔    在22D65C改402F7C為5EC7EC
列印    在22E6C4改40A961為5ECC8A
只要把MFC42.DLL跟主程式作一體化,MFC程式還是可跟蹤的.
還有其它工能有機會再寫.

相關文章