【黑客免殺攻防】讀書筆記14 - 面向對象逆向-虛函數、MFC逆向

虛函數存在是為了克服類型域解決方案的缺陷,以使程序員可以在基類里聲明一些能夠在各個派生類里重新定義的函數。

1 識別簡單的虛函數

代碼示例:

#include "stdafx.h"
#include <Windows.h>class CObj
{
public:CObj():m_Obj_1(0xAAAAAAAA),m_Obj_2(0xBBBB){printf("CObj() Constructor...\r\n");}~CObj(){printf("CObj() Destructor...\r\n");}virtual void Show(int nID)     // 注意這里{m_Obj_1 = 1;printf("ID:%d Who is your God? I am!\r\n",nID);}
private:int  m_Obj_1;WORD m_Obj_2;
};class CPeople : public CObj
{
public:CPeople():m_People_1(0xCCCCCCCC),m_People_2(0xDDDD){printf("CPeople() Constructor...\r\n");}~CPeople(){printf("CPeople() Destructor...\r\n");}void Show(int nID){printf("ID:%d People!\r\n",nID);}
private:int  m_People_1;WORD m_People_2;
};int _tmain(int argc, _TCHAR* argv[])
{CObj obj;CPeople people;CObj *pobj;pobj = &obj;pobj->Show(0);pobj = &people;pobj->Show(1);return 0;
}
// ---------- 輸出結果 ----------
// CObj() Constructor...
// CObj() Constructor...
// CPeople() Constructor...
// ID:0 Who is your God? I am!
// ID:1 People!
// CPeople() Destructor...
// CObj() Destructor...
// CObj() Destructor...
// ----------------------------

反匯編代碼:

int _tmain(int argc, _TCHAR* argv[])
{
001273B0  push        ebp  
001273B1  mov         ebp,esp  
001273B3  push        0FFFFFFFFh  
001273B5  push        1B3730h  
001273BA  mov         eax,dword ptr fs:[00000000h]    
001273C0  push        eax  
001273C1  sub         esp,108h  
001273C7  push        ebx  
001273C8  push        esi  
001273C9  push        edi  
001273CA  lea         edi,[ebp+FFFFFEECh]  
001273D0  mov         ecx,42h  
001273D5  mov         eax,0CCCCCCCCh  
001273DA  rep stos    dword ptr es:[edi]  
001273DC  mov         eax,dword ptr ds:[001D9004h]
001273E1  xor         eax,ebp  
001273E3  push        eax  
001273E4  lea         eax,[ebp-0Ch]  
001273E7  mov         dword ptr fs:[00000000h],eax              ; 棧保護基址相關代碼CObj obj;
001273ED  lea         ecx,[ebp-1Ch]                             ; this 指針
001273F0  call        00123D87                                  ; CObj::CObj (0123D87h)  
001273F5  mov         dword ptr [ebp-4],0                       ; 異常處理的輔助標志,以-1為結尾CPeople people;
001273FC  lea         ecx,[ebp-38h]                             ; this指針
001273FF  call        001211DB                                  ; CPeople::CPeople (01211DBh)  
00127404  mov         byte ptr [ebp-4],1  CObj *pobj;pobj = &obj;
00127408  lea         eax,[ebp-1Ch]                             ; 將obj的this指針給eax
0012740B  mov         dword ptr [ebp-44h],eax                   ; 將this指針給pobj的指針pobj->Show(0);
0012740E  mov         esi,esp  
00127410  push        0                                         ; 參數壓棧
00127412  mov         eax,dword ptr [ebp-44h]  
00127415  mov         edx,dword ptr [eax]  
00127417  mov         ecx,dword ptr [ebp-44h]                   ; 將Obj的指針(指向的是   Obj的this指針)給ecx
0012741A  mov         eax,dword ptr [edx]                       ; 將Obj的this指針所指向的第一項的內容(即Vtbl的第一個元素)給eax 
0012741C  call        eax  
0012741C  ; 在調用完CPeople的構造后,程序采用如下步驟實現
0012741C  ; pobj = &obj;
0012741C  ; pobj ->Show(0);
0012741C  ; 
0012741C  ; 1、將創建完的Obj對象的this指針傳遞給pobj
0012741C  ; 2、將指this指針給eax
0012741C  ; 3、將this指針第一項(即虛函數表指針)傳遞給edx
0012741C  ; 4、將pobj的值傳遞給ecx(注意此步)
0012741C  ; 5、將既虛函數表數組的地址傳遞給eax
0012741C  ; 6、調用eax
0012741E  cmp         esi,esp  
00127420  call        00122329  pobj = &people;
00127425  lea         eax,[ebp-38h]            ; 將People的this指針傳給eax
00127428  mov         dword ptr [ebp-44h],eax  ; 將People的this指針給Objpobj->Show(1);
0012742B  mov         esi,esp       
0012742D  push        1                        ; 參數壓棧
0012742F  mov         eax,dword ptr [ebp-44h]  ; 將People的this指針給eax
00127432  mov         edx,dword ptr [eax]      ; 將this指針中的第一項,即Vptr給edx
00127434  mov         ecx,dword ptr [ebp-44h]  ; 將People的this指針給ecx
00127437  mov         eax,dword ptr [edx]      ; 將Vptr指向的Vtbl給eax
00127439  call        eax                      ; 調用eax
0012743B  cmp         esi,esp  
0012743D  call        00122329                 ; __RTC_CheckEspreturn 0;
00127442  mov         dword ptr [ebp+FFFFFEF0h],0  
0012744C  mov         byte ptr [ebp-4],0  
00127450  lea         ecx,[ebp-38h]  
00127453  call        00121E10  
00127458  mov         dword ptr [ebp-4],0FFFFFFFFh  
0012745F  lea         ecx,[ebp-1Ch]  
00127462  call        00123BC0  
00127467  mov         eax,dword ptr [ebp+FFFFFEF0h]  
}

如果沒有Debug的符號文件,或者逆向過程中代碼不是我們自己寫的,那就要先判斷它是否是一個類的應用。

跟進函數內部情況:

class CObj
{
00126FD0  push        ebp  
00126FD1  mov         ebp,esp  
00126FD3  sub         esp,0CCh  
00126FD9  push        ebx  
00126FDA  push        esi  
00126FDB  push        edi  
00126FDC  push        ecx  
00126FDD  lea         edi,[ebp-0CCh]  
00126FE3  mov         ecx,33h  
00126FE8  mov         eax,0CCCCCCCCh  
00126FED  rep stos    dword ptr es:[edi]  
00126FEF  pop         ecx  
00126FF0  mov         dword ptr [this],ecx        ; 取this指針 this == [ebp-8] 
00126FF3  mov         eax,dword ptr [this]        ; 取this指針
00126FF6  mov         dword ptr [eax],offset CObj::`vftable' (01B5E54h)  
public:CObj():m_Obj_1(0xAAAAAAAA),m_Obj_2(0xBBBB)
00126FFC  mov         eax,dword ptr [this]  
00126FFF  mov         dword ptr [eax+4],0AAAAAAAAh  ; 初始化m_Obj_1為0xAAAAAAAA
00127006  mov         eax,0BBBBh                    ; 初始化m_Obj_2為0xBBBB
0012700B  mov         ecx,dword ptr [this]          ; this指針 this == ecx-8
0012700E  mov         word ptr [ecx+8],ax  printf("CObj() Constructor...\r\n");
00127012  push        offset string "CObj() Constructor...\r\n" (01B5E5Ch)  printf("CObj() Constructor...\r\n");
00127017  call        _printf (0123D00h)  
0012701C  add         esp,4  }
0012701F  mov         eax,dword ptr [this]         ; 將this指針作為返回值 this == ebp-8
00127022  pop         edi  
00127023  pop         esi  
00127024  pop         ebx  
00127025  add         esp,0CCh  
0012702B  cmp         ebp,esp  
0012702D  call        __RTC_CheckEsp (0122329h)  
00127032  mov         esp,ebp  
00127034  pop         ebp  
00127035  ret  

通過閱讀以上代碼可以得出以下過程:

1)找出虛表位置,以及操作的流程

  • 代碼里的例子操作了虛表 00126FF6 mov dword ptr [eax],offset CObj::`vftable' (01B5E54h)

這是一個保存函數地址的指針,再通過匯編上下文的猜測,則可大致確定這就是一個虛表,且將值傳到了寄存器參數ecx記錄地址的第一項。

  • 以寄存器參數ecx為首地址,分別給其4偏移與8偏移處賦值

  • 寄存器參數ecx又作為返回值傳了回去。

  • 通過調用函數的分析,ecx里保存的是this指針,并且根據類的內存結構可知,this里的第一項是Vptr。

2)識別構造函數

  • 由于此成員函數是第一個被調用的,通過代碼看出匯編函數中的第二件事是初始化數據成員。最后一件事是將this指針當做返回值返回,所以推測該函數為構造函數。

3)逐步分析函數

  • 構造函數與析構函數會對Vptr操作。
  • 在VS默認設置下,構造與析構前都會有相應的異常處理標記置位操作。
  • 虛函數的調用一般采用eax。

2 識別較復雜的虛函數

經驗小結:

  • new出來的對象會以其在堆中申請空間的指針作為this指針傳入參與構造。
  • new出來的對象其虛函數調用的尋址方式與普通構造出來的不同。
  • delete對象時會先析構自己,再析構父類,最后再執行delete。
  • new出來的對象如果其成員函數派生于純虛函數,在delete時只調用父類的析構。
  • 如果此類為抽象類(包含純虛函數),那么其虛表的對應項會填充指向庫函數__purecall的函數指針。

虛函數調用的固定模式,緊盯對各個虛表的操作。從而根據上下文即可大致確定虛函數的調用與類的析構與構造。

3 識別類的繼承關系

  • 根據構造函數內的構造順序分辨此函數所屬類的繼承情況
  • 總結并記錄分析結果
  • VS的release版中存在同時使用ecx、esi寄存器傳遞this指針的情況。

4 逆向MFC程序

MFC程序關鍵特征點

版本對應動態庫靜態庫中使用MFC時的特征動態庫中使用MFC的特征
4.0mfc40.dllcall [ebp+0x14]call [ebp+0x14]
6.0mfc42.dllcall [ebp+0x14]call [ebp+0x14]
7.1mfc71.dllcall [ebp+0x14]call [ebp+0x14]
10.0mfc100.dllcall [ebp+0x14]mov edx,[ebp+0x14]

分析核心重點

1)判斷目標程序是不是MFC程序,如果是,判斷其MFC版本

OD快捷鍵:Ctrl+E 打開模塊窗口,并在模塊窗口尋找類似于mfc*.dll這樣的模塊。

如果找到了就可以根據DLL的名稱判定程序所用的MFC版本,如果找不到則證明這是一個在靜態庫中使用MFC的程序。

2)根據目標程序調用MFC方式的不同而采取不同的方式搜索特征

OD快捷鍵:Ctrl+F 搜索特征 call [ebp+0x14]

由于搜索的特征位于消息分發函數里,因此特征指令所在的位置應該是一個非常大的switch-case。

3)在合適的地方下斷點,并跟進到相應消息的函數中。

設置按鈕點擊事件下斷點,即可跟進到達相應消息的函數中。

這里可以參考:

看雪《MFC程序逆向》
https://bbs.pediy.com/thread-54150.htm

轉載于:https://www.cnblogs.com/17bdw/p/8851049.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389837.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389837.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389837.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

怎么看另一個電腦端口是否通_誰一個人睡覺另一個看看夫妻的睡眠習慣

怎么看另一個電腦端口是否通In 2014, FiveThirtyEight took a survey of about 1057 respondents to get a look at the (literal) sleeping habits of the American public beyond media portrayal. Some interesting notices: first, that about 45% of all couples sleep to…

495. 提莫攻擊

495. 提莫攻擊 在《英雄聯盟》的世界中&#xff0c;有一個叫 “提莫” 的英雄。他的攻擊可以讓敵方英雄艾希&#xff08;編者注&#xff1a;寒冰射手&#xff09;進入中毒狀態。 當提莫攻擊艾希&#xff0c;艾希的中毒狀態正好持續 duration 秒。 正式地講&#xff0c;提莫在…

Java基礎之Collection和Map

List&#xff1a;實現了collection接口&#xff0c;list可以重復&#xff0c;有順序 實現方式&#xff1a;3種&#xff0c;分別為&#xff1a;ArrayList&#xff0c;LinkedList&#xff0c;Vector。 三者的比較&#xff1a; ArrayList底層是一個動態數組&#xff0c;數組是使用…

20155320《網絡對抗》Exp4 惡意代碼分析

20155320《網絡對抗》Exp4 惡意代碼分析 【系統運行監控】 使用schtasks指令監控系統運行 首先在C盤目錄下建立一個netstatlog.bat文件&#xff08;由于是系統盤&#xff0c;所以從別的盤建一個然后拷過去&#xff09;&#xff0c;用來將記錄的聯網結果格式化輸出到netstatlog.…

tableau 自定義省份_在Tableau中使用自定義圖像映射

tableau 自定義省份We have been reading about all the ways to make our vizzes in Tableau with more creativity and appeal. During my weekly practice for creating viz as part of makeovermonday2020 community, I came across geographical data which in way requir…

2055. 蠟燭之間的盤子

2055. 蠟燭之間的盤子 給你一個長桌子&#xff0c;桌子上盤子和蠟燭排成一列。給你一個下標從 0 開始的字符串 s &#xff0c;它只包含字符 ‘’ 和 ‘|’ &#xff0c;其中 ’ 表示一個 盤子 &#xff0c;’|’ 表示一支 蠟燭 。 同時給你一個下標從 0 開始的二維整數數組 q…

Template、ItemsPanel、ItemContainerStyle、ItemTemplate

原文:Template、ItemsPanel、ItemContainerStyle、ItemTemplate先來看一張圖(網上下的圖&#xff0c;加了幾個字) 實在是有夠“亂”的&#xff0c;慢慢來理一下&#xff1b; 1、Template是指控件的樣式 在WPF中所有繼承自contentcontrol類的控件都含有此屬性&#xff0c;&#…

熊貓燒香分析報告_熊貓分析進行最佳探索性數據分析

熊貓燒香分析報告目錄 (Table of Contents) Introduction 介紹 Overview 總覽 Variables 變數 Interactions 互動互動 Correlations 相關性 Missing Values 缺失值 Sample 樣品 Summary 摘要 介紹 (Introduction) There are countless ways to perform exploratory data analys…

2060. 同源字符串檢測

2060. 同源字符串檢測 原字符串由小寫字母組成&#xff0c;可以按下述步驟編碼&#xff1a; 任意將其 分割 為由若干 非空 子字符串組成的一個 序列 。 任意選擇序列中的一些元素&#xff08;也可能不選擇&#xff09;&#xff0c;然后將這些元素替換為元素各自的長度&#x…

vue中的data用return返回

為什么在大型項目中data需要使用return返回數據呢&#xff1f;答&#xff1a;不使用return包裹的數據會在項目的全局可見&#xff0c;會造成變量污染&#xff1b;使用return包裹后數據中變量只在當前組件中生效&#xff0c;不會影響其他組件。 1、在簡單的vue實例中看到的Vue實…

白褲子變粉褲子怎么辦_使用褲子構建構建數據科學的monorepo

白褲子變粉褲子怎么辦At HousingAnywhere, one of the first major obstacles we had to face when scaling the Data team was building a centralised repository that contains our ever-growing machine learning applications. Between these projects, many of them shar…

ubuntu+anaconda+tensorflow 及相關問題

配置tensorflow部分參考&#xff1a;https://blog.csdn.net/XUTIAN1129/article/details/78997633 裝完anaconda, source ~/.bashrc后, 可以直接 pip install tensorflow-gpu , 珍愛生命&#xff0c;遠離bazel。但想要c/c調用tf的時候遠離不了&#xff0c;還是得bazel編譯安裝t…

2022. 將一維數組轉變成二維數組

2022. 將一維數組轉變成二維數組 給你一個下標從 0 開始的一維整數數組 original 和兩個整數 m 和 n 。你需要使用 original 中 所有 元素創建一個 m 行 n 列的二維數組。 original 中下標從 0 到 n - 1 &#xff08;都 包含 &#xff09;的元素構成二維數組的第一行&#xf…

支持向量機SVM算法原理及應用(R)

支持向量機SVM算法原理及應用&#xff08;R&#xff09; 2016年08月17日 16:37:25 閱讀數&#xff1a;22292更多 個人分類&#xff1a; 數據挖掘實戰應用版權聲明&#xff1a;本文為博主原創文章&#xff0c;轉載請注明來源。 https://blog.csdn.net/csqazwsxedc/article/detai…

mad離群值_全部關于離群值

mad離群值An outlier is a data point in a data set that is distant from all other observations. A data point that lies outside the overall distribution of the dataset. Or in a layman term, we can say, an outlier is something that behaves differently from th…

2057. 值相等的最小索引

2057. 值相等的最小索引 給你一個下標從 0 開始的整數數組 nums &#xff0c;返回 nums 中滿足 i mod 10 nums[i] 的最小下標 i &#xff1b;如果不存在這樣的下標&#xff0c;返回 -1 。 x mod y 表示 x 除以 y 的 余數 。 示例 1&#xff1a;輸入&#xff1a;nums [0,1,2…

SpringBoot中各配置文件的優先級及加載順序

我們在寫程序的時候會碰到各種環境(開發、測試、生產)&#xff0c;因而&#xff0c;在我們切換環境的時候&#xff0c;我們需要手工切換配置文件的內容。這大大的加大了運維人員的負擔&#xff0c;同時會帶來一定的安全隱患。 為此&#xff0c;為了能更合理地重寫各屬性的值&am…

青年報告_了解青年的情緒

青年報告Youth-led media is any effort created, planned, implemented, and reflected upon by young people in the form of media, including websites, newspapers, television shows, and publications. Such platforms connect writers, artists, and photographers in …

post提交參數過多時,取消Tomcat對 post長度限制

1.Tomcat 默認的post參數的最大大小為2M&#xff0c; 當超過時將會出錯&#xff0c;可以配置maxPostSize參數來改變大小。 從 apache-tomcat-7.0.63 開始&#xff0c;參數 maxPostSize 的含義就變了&#xff1a; 如果將值設置為 0&#xff0c;表示 POST 最大值為 0&#xff0c;…

2048. 下一個更大的數值平衡數

2048. 下一個更大的數值平衡數 如果整數 x 滿足&#xff1a;對于每個數位 d &#xff0c;這個數位 恰好 在 x 中出現 d 次。那么整數 x 就是一個 數值平衡數 。 給你一個整數 n &#xff0c;請你返回 嚴格大于 n 的 最小數值平衡數 。 示例 1&#xff1a;輸入&#xff1a;n …