能力值:
( LV13,RANK:1250 )
2 楼
不错的文章,鄙人原来一直搞不清SDK跟VC++两种编程方式有什么区别,老有个问题:你用VC++难道就不用写API调用语句了吗?难道就不用写WindowProcedure()了吗?所以一直没弄清VC++究竟是怎么编程的,比起SDK优越性何在――要知道SDK编程实在太琐碎了……
能力值:
(RANK:570 )
3 楼
1?看来还有2,3,4,5,6咯。。。
期待后续。。。
MFC逆向一直很头痛。。
能力值:
( LV13,RANK:530 )
4 楼
偶觉得MFC还是太复杂了
还是NET好点。。。真的比较喜欢NET了~现在
能力值:
( LV6,RANK:90 )
5 楼
潜力股,关注
能力值:
(RANK:330 )
6 楼
关注...
能力值:
( LV4,RANK:50 )
7 楼
强贴留个名。
能力值:
( LV12,RANK:210 )
8 楼
最初由 笨笨雄 发布 1?看来还有2,3,4,5,6咯。。。 期待后续。。。 MFC逆向一直很头痛。。
ida5 大部分MFC类的sig都有标识。
跟看原代码没什么区别。。。
能力值:
( LV4,RANK:50 )
9 楼
【文章标题】: MFC逆向初级研究(2)
【文章作者】: 北斗之摇光
【作者邮箱】: hardlywhen@hotmail.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
在《MFC逆向初级研究(1)》中我们初步证明了我们的假设,在经过对几个文件的反汇编以后,现在我们可以总结出一条经过证明的推断:
"MFC中的类信息的存储可能是按照如下的顺序来存储的:
1.该类的MessageMap
2.该类的MessageEntry
3.该类的RTTI Complete Object Locator(如果该类有RTTI信息)
4.该类的虚函数表"
按照这样的顺序看下来,我们在.rdata区域开始一点一点往下,会得到几个类的信息。下面是通过IDA对我们的例子程序反编译以后我整理
好的.rdata的内容,仔细查看虚函数表,你会发现有部分虚函数没有像其他的虚函数那样指向其父类的相关函数,这是因为在我们的例子程序
中对这些函数进行了重载。那么到底重载的是哪些函数呢?你可以根据虚函数在其父类中的顺序确定,在注释中我已经标出。
.rdata:004021C0 ; 屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯?
.rdata:004021C0
.rdata:004021C0 ; Segment type: Pure data
.rdata:004021C0 ; Segment permissions: Read
.rdata:004021C0 _rdata segment para public 'DATA' use32
.rdata:004021C0 assume cs:_rdata
.rdata:004021C0 ;org 4021C0h
.rdata:004021C0 off_4021C0 dd offset sub_401000 ; DATA XREF: sub_401010o
.rdata:004021C4 dd offset dword_4021C8
.rdata:004021C8 dword_4021C8 dd 111h ; DATA XREF: .rdata:004021C4o
.rdata:004021CC dd 0
.rdata:004021D0 dd 0E146h
.rdata:004021D4 dd 0E146h
.rdata:004021D8 dd 0Ch
.rdata:004021DC dd offset CWinApp::OnHelp(void)
.rdata:004021E0 dd 0
.rdata:004021E4 dd 0
.rdata:004021E8 dd 0
.rdata:004021EC dd 0
.rdata:004021F0 dd 0
.rdata:004021F4 dd 0
.rdata:004021F8 off_4021F8 dd offset CWinApp::GetRuntimeClass(void) \\虚函数表的开始
.rdata:004021F8 ; DATA XREF: unknown_libname_1-56 \\这个引用可能在类构造函数中
.rdata:004021FC dd offset sub_401040 \\类析构函数
.rdata:00402200 dd offset nullsub_2
.rdata:00402204 dd offset nullsub_3
.rdata:00402208 dd offset nullsub_2
.rdata:0040220C dd offset CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
.rdata:00402210 dd offset CCmdTarget::OnFinalRelease(void)
.rdata:00402214 dd offset CCmdTarget::IsInvokeAllowed(long)
.rdata:00402218 dd offset CCmdTarget::GetDispatchIID(_GUID *)
.rdata:0040221C dd offset CCmdTarget::GetTypeInfoCount(void)
.rdata:00402220 dd offset CCmdTarget::GetTypeLibCache(void)
.rdata:00402224 dd offset CCmdTarget::GetTypeLib(ulong,ITypeLib * *)
.rdata:00402228 dd offset sub_401010 \\GetMessageMap
.rdata:0040222C dd offset CCmdTarget::GetCommandMap(void)
.rdata:00402230 dd offset CCmdTarget::GetDispatchMap(void)
.rdata:00402234 dd offset CCmdTarget::GetConnectionMap(void)
.rdata:00402238 dd offset CCmdTarget::GetInterfaceMap(void)
.rdata:0040223C dd offset CCmdTarget::GetEventSinkMap(void)
.rdata:00402240 dd offset CCmdTarget::OnCreateAggregates(void)
.rdata:00402244 dd offset CCmdTarget::GetInterfaceHook(void const *)
.rdata:00402248 dd offset CCmdTarget::GetExtraConnectionPoints(CPtrArray *)
.rdata:0040224C dd offset CCmdTarget::GetConnectionHook(_GUID const &)
.rdata:00402250 dd offset sub_4010B0 \\InitInstance
.rdata:00402254 dd offset CWinApp::Run(void)
.rdata:00402258 dd offset CWinThread::PreTranslateMessage(tagMSG *)
.rdata:0040225C dd offset CWinThread::PumpMessage(void)
.rdata:00402260 dd offset CWinApp::OnIdle(long)
.rdata:00402264 dd offset CWinThread::IsIdleMessage(tagMSG *)
.rdata:00402268 dd offset CWinApp::ExitInstance(void)
.rdata:0040226C dd offset CWinApp::ProcessWndProcException(CException *,tagMSG const *)
.rdata:00402270 dd offset CWinThread::ProcessMessageFilter(int,tagMSG *)
.rdata:00402274 dd offset CWinThread::GetMainWnd(void)
.rdata:00402278 dd offset CWinThread::Delete(void)
.rdata:0040227C dd offset CWinApp::OpenDocumentFile(char const *)
.rdata:00402280 dd offset CWinApp::AddToRecentFileList(char const *)
.rdata:00402284 dd offset CWinApp::InitApplication(void)
.rdata:00402288 dd offset CWinApp::SaveAllModified(void)
.rdata:0040228C dd offset CWinApp::DoMessageBox(char const *,uint,uint)
.rdata:00402290 dd offset CWinApp::DoWaitCursor(int)
.rdata:00402294 dd offset CWinApp::OnDDECommand(char *)
.rdata:00402298 dd offset CWinApp::WinHelpA(ulong,uint)
.rdata:0040229C align 10h
.rdata:004022A0 off_4022A0 dd offset sub_4011F0 ; DATA XREF: sub_401200o
.rdata:004022A4 dd offset dword_4022A8
.rdata:004022A8 dword_4022A8 dd 0Fh ; DATA XREF: .rdata:004022A4o
.rdata:004022AC dd 0
.rdata:004022B0 dd 0
.rdata:004022B4 dd 0
.rdata:004022B8 dd 0Ch
.rdata:004022BC dd offset sub_401250
.rdata:004022C0 dd 37h
.rdata:004022C4 dd 0
.rdata:004022C8 dd 0
.rdata:004022CC dd 0
.rdata:004022D0 dd 23h
.rdata:004022D4 dd offset sub_401310
.rdata:004022D8 dd 111h
.rdata:004022DC dd 0
.rdata:004022E0 dd 3E8h
.rdata:004022E4 dd 3E8h
.rdata:004022E8 dd 0Ch
.rdata:004022EC dd offset sub_401320
.rdata:004022F0 dd 0
.rdata:004022F4 dd 0
.rdata:004022F8 dd 0
.rdata:004022FC dd 0
.rdata:00402300 dd 0
.rdata:00402304 dd 0
.rdata:00402308 off_402308 dd offset CDialog::GetRuntimeClass(void)
.rdata:00402308 ; DATA XREF: sub_401150+31o
.rdata:0040230C dd offset sub_4011C0 \\类析构函数
.rdata:00402310 dd offset nullsub_2
.rdata:00402314 dd offset nullsub_3
.rdata:00402318 dd offset nullsub_2
.rdata:0040231C dd offset CDialog::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
.rdata:00402320 dd offset CWnd::OnFinalRelease(void)
.rdata:00402324 dd offset CCmdTarget::IsInvokeAllowed(long)
.rdata:00402328 dd offset CCmdTarget::GetDispatchIID(_GUID *)
.rdata:0040232C dd offset CCmdTarget::GetTypeInfoCount(void)
.rdata:00402330 dd offset CCmdTarget::GetTypeLibCache(void)
.rdata:00402334 dd offset CCmdTarget::GetTypeLib(ulong,ITypeLib * *)
.rdata:00402338 dd offset sub_401200 \\GetMessageMap
.rdata:0040233C dd offset CCmdTarget::GetCommandMap(void)
.rdata:00402340 dd offset CCmdTarget::GetDispatchMap(void)
.rdata:00402344 dd offset CCmdTarget::GetConnectionMap(void)
.rdata:00402348 dd offset CCmdTarget::GetInterfaceMap(void)
.rdata:0040234C dd offset CCmdTarget::GetEventSinkMap(void)
.rdata:00402350 dd offset CCmdTarget::OnCreateAggregates(void)
.rdata:00402354 dd offset CCmdTarget::GetInterfaceHook(void const *)
.rdata:00402358 dd offset CCmdTarget::GetExtraConnectionPoints(CPtrArray *)
.rdata:0040235C dd offset CCmdTarget::GetConnectionHook(_GUID const &)
.rdata:00402360 dd offset CWnd::PreSubclassWindow(void)
.rdata:00402364 dd offset CWnd::Create(char const *,char const *,ulong,tagRECT const &,CWnd *,uint,CCreateContext *)
.rdata:00402368 dd offset CWnd::DestroyWindow(void)
.rdata:0040236C dd offset CWnd::PreCreateWindow(tagCREATESTRUCTA &)
.rdata:00402370 dd offset CWnd::CalcWindowRect(tagRECT *,uint)
.rdata:00402374 dd offset CWnd::OnToolHitTest(CPoint,tagTOOLINFOA *)
.rdata:00402378 dd offset CWnd::GetScrollBarCtrl(int)
.rdata:0040237C dd offset CWnd::WinHelpA(ulong,uint)
.rdata:00402380 dd offset CWnd::ContinueModal(void)
.rdata:00402384 dd offset CWnd::EndModalLoop(int)
.rdata:00402388 dd offset CWnd::OnCommand(uint,long)
.rdata:0040238C dd offset CWnd::OnNotify(uint,long,long *)
.rdata:00402390 dd offset CWnd::GetSuperWndProcAddr(void)
.rdata:00402394 dd offset nullsub_4 \\DoDataExchange
.rdata:00402398 dd offset sub_401330 \\BeginModalState
.rdata:0040239C dd offset sub_401340 \\EndModalState
.rdata:004023A0 dd offset CDialog::PreTranslateMessage(tagMSG *)
.rdata:004023A4 dd offset CWnd::OnAmbientProperty(COleControlSite *,long,tagVARIANT *)
.rdata:004023A8 dd offset CWnd::WindowProc(uint,uint,long)
.rdata:004023AC dd offset CWnd::OnWndMsg(uint,uint,long,long *)
.rdata:004023B0 dd offset CWnd::DefWindowProcA(uint,uint,long)
.rdata:004023B4 dd offset CWnd::PostNcDestroy(void)
.rdata:004023B8 dd offset CWnd::OnChildNotify(uint,uint,long,long *)
.rdata:004023BC dd offset CDialog::CheckAutoCenter(void)
.rdata:004023C0 dd offset CWnd::IsFrameWnd(void)
.rdata:004023C4 dd offset CDialog::SetOccDialogInfo(_AFX_OCC_DIALOG_INFO *)
.rdata:004023C8 dd offset CDialog::DoModal(void)
.rdata:004023CC dd offset sub_401210 \\OnInitDialog
.rdata:004023D0 dd offset CDialog::OnSetFont(CFont *)
.rdata:004023D4 dd offset CDialog::OnOK(void)
.rdata:004023D8 dd offset CDialog::OnCancel(void)
.rdata:004023DC dd offset CDialog::PreInitDialog(void)
.rdata:004023E0 dword_4023E0 dd 0FFFFFFFFh ; DATA XREF: start+5o \\再以下就是其他数据
.rdata:004023E4 dd offset sub_4016AE
.rdata:004023E8 dd offset sub_4016C2
.rdata:004023EC dd 0
.rdata:004023F0 stru_4023F0 dd 19930520h ; Magic
.rdata:004023F0 ; DATA XREF: .text:loc_401768o
.rdata:004023F0 dd 1 ; Count
.rdata:004023F0 dd offset stru_4023F0.Info; InfoPtr
.rdata:004023F0 dd 0 ; CountDtr
.rdata:004023F0 dd 0 ; DtrPtr
.rdata:004023F0 dd 3 dup(0) ; _unk
.rdata:004023F0 dd -1 ; Info.Id
.rdata:004023F0 dd offset sub_401760 ; Info.Proc
.rdata:00402418 stru_402418 dd 19930520h ; Magic
经过以上步骤以后我们对于MessageMap、MessageEntry、虚函数表三部分的处理已经完成,接下来的任务就是确定我们已经找好相关数据的类
到底是哪个类?根据MFC的了解,我们知道MFC在建立之处会让你选择建立哪个类型的工程,其中有:多文档、单文档、对话框三种可以选择。
对于我们这个工程中选择的Dialog类型,其建立之初就有2个类(如果选择包含About Dialog的话则有3个类):CReverseMFC和CReverseMFCDlg类。
对于这几个类的作用在《深入浅出MFC》中有过介绍,我们现在需要确定的是我们刚才找到的数据具体是那个类呢?
我们可以根据虚函数表的继承关系来找,CReverseMFCDlg类继承自CDialog<-CWnd<-CCmdtarget;
CReverseMFC类继承自CWinApp<-CWinthread<-CCmdtarget
这样基本确定了两个类以及他们的MeeeageMap。在确定MessageMap后,我们就可以根据这个消息处理流程来寻找我们需要的算法和软件处理过程了。
那么如何来完成在本文之初我们所设立的目标呢-"找到按钮的相关处理过程"?
首先我们要知道按钮的资源代码是多少,这一点我们可以通过相关的资源处理软件来处理(我用的是ResHacker)可以查到按钮的的资源ID为1000,
也就是0X3E8。MFC消息处理中将Button消息作为Command类消息,在windows.h头文件中对WM_COMMAND消息的定义为0X111。回顾对MessageEntry
的数据定义,第一个为windows消息代码,第3个为控件ID。而按钮类的处理过程一般是放在对话框类中实现,因此查看类CReverseMFCDlg类的
MessageEntry可以找到了如下的代码:
.rdata:004022D8 dd 111h \\windows message id
.rdata:004022DC dd 0 \\nCode
.rdata:004022E0 dd 3E8h \\nID
.rdata:004022E4 dd 3E8h \\nLastID
.rdata:004022E8 dd 0Ch \\nSig
.rdata:004022EC dd offset sub_401320 \\pfn
跟入sub_401320:
.text:00401320 ; *************** S U B R O U T I N E ***************************************
.text:00401320
.text:00401320
.text:00401320 sub_401320 proc near ; DATA XREF: .rdata:004022ECo
.text:00401320 push 0
.text:00401322 push 0
.text:00401324 push offset s_IFindIt ; "I find it!"
.text:00401329 call AfxMessageBox(char const *,uint,uint)
.text:00401329
.text:0040132E retn
.text:0040132E
.text:0040132E sub_401320 endp
恰恰是我们所定义的按钮行为!如此,我们便跟随着EXE文件给我们留下的“藤”摸到了我们需要的“瓜”,这些藤为我们编织了一张软件架构的
大网,需要我们仔细的分析才能达成目的。
总结以上,对于VC++6.0 MFC产生的EXE文件的逆向我们可以归结以下几个要点(当然,这个文件必须是没加壳同时确定是VC++6.0产生的):
1.IDA反汇编后直接跳到.rdata段,此段必然是相关的用于存储相关的虚函数表、MessageMap、MessageEntry等信息;
2.查找虚函数表时可以直接搜索GetRunTimeClass函数,该函数必然时各个虚函数表的开始;
3.通过完善虚函数表,我们可以找到重载的函数地址,在完善函数表时要注意确定正确的函数顺序;
结语
在此,这篇文章只是简单的对MFC逆向做了一个肤浅的分析,希望能起到抛砖引玉的作用的同时也能让刚刚接触MFC逆向的兄弟们有点头绪,知道
该如何去找到自己需要的函数处理过程。毕竟本文的例子只是一个非常简单的工程,在正式的商业软件中,往往有着十几个基本类以及自定义类,
还有大量的自定义消息和数据结构,类的成员变量和成员函数等等。这些都需要经验和时间的积累,小菜由于也是初次接触MFC的逆向,还没有
经验,等俺逆向过几个软件后再发吧,免的贻笑大方。
另:
让笨笨熊版主失望了,俺只写了2,没写3、4、5、6那么多,嘿嘿,经验不足
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年03月16日 11:14:49
能力值:
( LV2,RANK:10 )
10 楼
向孜孜不倦的兄弟们表示敬意,支持~~~
能力值:
(RANK:330 )
11 楼
支持 北斗之摇光 写了 MFC逆向初级研究 再写 MFC逆向中级研究 再写 MFC逆向高级研究 再写 MFC浅入浅出 然后写 MFC深入浅出 然后写 MFC完全逆向.
能力值:
( LV12,RANK:770 )
12 楼
跟进这个RIIT链表指针
virtual CRuntimeClass* GetRuntimeClass() const;
可以快速定位到它的类名和父类名称.从而判断它是VMT表.
否则就是消息影射表.
以往偶都是这么跟踪滴...
能力值:
(RANK:350 )
13 楼
文章不错。
由于(1)(2)篇幅不是太长,我将2个主题合并了,还望理解。
能力值:
(RANK:570 )
14 楼
最初由 jjnet 发布 ida5 大部分MFC类的sig都有标识。 跟看原代码没什么区别。。。
也许是我对MFC没什么认识吧
能力值:
( LV12,RANK:370 )
15 楼
最初由 jjnet 发布 ida5 大部分MFC类的sig都有标识。 跟看原代码没什么区别。。。
如果你用MFC编程,那么逆向MFC跟看源代码差距不大。
能力值:
( LV12,RANK:370 )
16 楼
呵呵,我想过段时间写一篇MFC逆向的文章,跟你的思路差不多,你写了我就不献丑了!!
支持!!!!!
能力值:
( LV2,RANK:10 )
17 楼
好文!受益非浅
能力值:
( LV2,RANK:10 )
18 楼
好文章啊 ,谁能发给邀请码啊
能力值:
( LV2,RANK:10 )
19 楼
参考了,读了你的文章再去研究一个MFC的CRACKME
哈,谢谢LZ,入门的好材料
能力值:
( LV2,RANK:10 )
20 楼
MFC逆向是很麻烦的事情
能力值:
( LV6,RANK:90 )
21 楼
现在的人都用IDA
可惜我都不会用~~
能力值:
( LV2,RANK:10 )
22 楼
非常感谢,十分需要MFC方面的资料