初探CTF中特殊框架逆向
最近做題,逐漸遇到一些非 IAT32 ASR arm32,64(Linux)框架之外的 各種框架的re程序逆向分析。雖然題目難度不大,但著實令人耳目一新。而且這會不會是出題人釋放的信號,代表著未來re出題的新方向呢?本著認真嚴謹的態度,我想應該把它們做一個總結。
QT框架程序逆向
QT框架簡介
Qt 是一個1991年由Qt Company開發的跨平臺C++圖形用戶界面應用程序開發框架。它既可以開發GUI程序,也可用于開發非GUI程序,比如控制臺工具和服務器。Qt是面向對象的框架,使用特殊的代碼生成擴展(稱為元對象編譯器(Meta Object Compiler, moc))以及一些宏,Qt很容易擴展,并且允許真正地組件編程。另一方面,QT實現了全面支持iOS、Android、WP,它提供給應用程序開發者建立藝術級的圖形用戶界面所需的所有功能。
Qt框架應用還是很廣泛的,為了大家有一個直觀的概念,我用Everything搜索了下我電腦上的qt5core.dll,部分結果如下圖所示:
QT對象樹
Qt提供了一種機制,能夠自動、有效的組織和管理繼承自QObject的Qt對象,這種機制就是對象樹。
如圖所示,QObject 對象有且僅有一個父對象,但可以有很多個子對象。按照這種形式排列就會形成一個對象樹的結構,最上層是父對象,下面是子對象,在再下面是孫子對象,以此類推。當父對象析構的時候,這個子對象列表中的所有對象都會被析構,當析構子對象的時候,會自動從父對象的子對象列表中刪除。
那么Qt為什么要這樣設計呢?很簡單,方便內存管理我們在創建 QObject 對象時,提供一個父對象,那么我們創建的這個 QObject 對象會自動添加到其父對象的 children() 列表。這種機制在GUI程序開發過程中是相當實用的。值得注意的是,如果在構造時設置父對象為 NULL,那么當前實例不會有父對象存在,Qt 也不會自動析構該實例。
tips:QWidget的操作流程
QWidget 也是 QObject 的子類,所以在 parent 機制上是沒有區別的。然而實際使用時,對于 QWidget 和其派生類來說,在內存管理上要稍微復雜一些。例如QWidget的關閉流程,首先用戶點擊關閉按鈕觸發 close()槽,默認的 QCloseEvent 會將 widget隱藏起來,也就是觸發hide()槽。也就是說widget的關閉實際是將其隱藏,而沒有釋放內存,雖然我們有時會重寫 closeEvent 但也不會手動釋放 widget。
解決方案:需要設置 Qt::WA_DeleteOnClose 屬性,那么會在 close 之后接著調用 widget 的析構函數。
tips2:對象樹模型存在的問題
俗話說,百密終有一疏。對象樹模型的特殊析構規則,大概注定著它會爆出邏輯性漏洞。
來看下面這段程序:
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton btn("button");
QWidget widget;
btn.setParent(&widget);
widget.show();
return a.exec();
}
運行結果:
關閉 widget 后程序崩潰,沒有正常結束
為什么程序會崩潰呢?通過上面的學習我們知道,C++規定了析構順序應該按照其創建順序的相反過程。而當我們先創建子對象,再創建父對象時,根據自動析構原理,我們析構父對象的時候會自動析構父對象,此時,子對象已經被析構了,然而代碼繼續執行,按照順序還要再析構一次子對象,這時候已經是第二次調用 子對象的析構函數了。C++中不允許調用兩次析構函數,最終導致程序崩潰。
避免問題的方案:
先創建父對象再創建子類對象,并且在創建子對象時就指定父對象;
盡量在堆上創建子對象;
QT程序的特殊機制--信號/槽
先來看一下官方介紹:
信號/槽是 Qt 框架引以為豪的機制之一。所謂信號槽,實際就是觀察者模式。當某個事件發生之后,比如,按鈕檢測到自己被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,類似廣播。如果有對象對這個信號感興趣,它就會使用連接(connect)函數,意思是,將想要處理的信號和自己的一個函數(稱為槽(slot))綁定來處理這個信號。也就是說,當信號發出時,被連接的槽函數會自動被回調。這就類似觀察者模式:當發生了感興趣的事件,某一個操作就會被自動觸發。(這里提一句,Qt 的信號槽使用了額外的處理來實現,并不是 GoF 經典的觀察者模式的實現方式。)
Qt使用信號(Signal)和槽(Slot)機制用于對象間的通信??梢詫⑿盘柡筒弁ㄟ^QObject對象的connet函數關聯起來。我們可以使用emit(Qt定義的語句)發出某個信號,與該信號關聯的槽就會接受到信號進行處理。
信號槽編寫
QT5的書寫方式
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPushButton button("Quit");
QObject::connect(&button, &QPushButton::clicked,
&app, &QApplication::quit);
button.show();
return app.exec();
}
QT4的書寫方式
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton *button = new QPushButton("Quit");
connect(button, SIGNAL(clicked()), &a, SLOT(quit()));
button->show();
return a.exec();
}
關鍵函數 connect
connect()函數最常用的一般形式:
connect(sender, signal, receiver, slot);
參數:
sender:發出信號的對象
signal:發送對象發出的信號
receiver:接收信號的對象
slot:接收對象在接收到信號之后所需要調用的函數
信號/槽的特殊性質
1.一個信號可以和多個槽相連
如果是這種情況,這些槽會一個接一個的被調用,但是它們的調用順序是不確定的。
2.多個信號可以連接到一個槽
只要任意一個信號發出,這個槽就會被調用。
3.一個信號可以連接到另外的一個信號
當第一個信號發出時,第二個信號被發出。除此之外,這種信號-信號的形式和信號-槽的形式沒有什么區別。
4.槽可以被取消鏈接
這種情況并不經常出現,因為當一個對象delete之后,Qt自動取消所有連接到這個對象上面的槽。
5.使用Lambda 表達式
在使用 Qt 5 的時候,能夠支持 Qt 5 的編譯器都是支持 Lambda 表達式的。
我們的代碼可以寫成下面這樣:
QObject::connect(&newspaper, static_cast
(const QString &)>(&Newspaper::newPaper),
[=](const QString &name)
{ /* Your code here. */ }
);
在連接信號和槽的時候,槽函數可以使用Lambda表達式的方式進行處理。
6.信號槽要求信號和槽的參數一致
所謂一致,是參數類型一致。如果不一致,允許槽函數的參數可以比信號的少,即便如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是因為,你可以在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少),但是信號根本沒有這個數據,槽函數中肯定無法使用。
[GKCTF 2021]QQQQT
virtualbox打包的QT程序。
奇怪的main函數....奇怪的關鍵函數。正向引用分析不了,main函數代碼非常奇怪...找不到關鍵函數調用。只能曲線救國一波,通過字符串搜索搜索到密文,再通過交叉引用定位到關鍵函數。
一個base58加密,解密即可:
mfc框架逆向
mfc框架簡介
老規矩,先來看官方解釋:
MFC庫是開發Windows應用程序的C++接口。MFC提供了面向對象的框架,采用面向對象技術,將大部分的Windows API 封裝到C++類中,以類成員函數的形式提供給程序開發人員調用。
簡單來說,MFC是一種面向對象,用于開發windows應用程序的框架,突出特點是封裝了大部分windows API,便于開發人員使用。
MFC程序的運行過程分為以下四步:
- 利用全局應用程序對象theApp啟動應用程序。
- 調用全局應用程序對象的構造函數,從而調用基類(CWinApp)的構造函數,完成應用程序的一些初始化工作,并將應用程序對象的指針保存起來。
- 進入WinMain函數。在AfxWinMain函數中獲取子類的指針,利用指針實現上述的三個函數,從而完成窗口的創建注冊等工作。
- 進入消息循環,一直到WM_QUIT。
怎樣逆向mfc程序
怎樣逆向mfc程序?一個非常樸實無華的問題(大霧)。這里介紹常用的兩種方法。
尋找程序初始化函數下斷點
AfxOleInit (COM初始化)
AfxEnableControlContainer (Ole初始化)
AfxGetModuleState (獲取模塊狀態)
CoInitialize (COM初始化 API)
GdiplusStartup (GDI+初始化)
SetUnhandledExceptionFilter (截獲異常處理)
Enable3dControls()
CWinApp()
使用工具
針對mfc程序逆向分析,前輩們已經開發了一些非常好用的小工具,站在巨人肩膀上的我們,掌握了工具的使用方法,便可大大提高mfc程序的分析效率。
常用工具:
- 彗星小助手
- xspy
- ResourceHacker
[HDCTF2019]MFC
首先通過彗星小助手獲取窗口信息(關鍵是句柄)。
得到:
944c8d100f82f0c18b682f63e4dbaa207a2f1e72581c2f1b
一大串密文:
接著使用xspy掃描一下mfc窗口的各個框架。
掃到一個特殊的onMsg,0464,為什么說它特殊呢,因為他是唯一 一個沒有系統函數包裹的參數。
這里多提一嘴,xspy的使用方法是,拖拽小放大鏡到mfc窗口中(因為無知擱那雙擊了半天小放大鏡沒反應急得跳腳)。
接下來我們利用彗星小助手傳遞0464(記得轉換為10進制為1124)給mfc框。
這樣就得到了des key 找個des解密網站解密即可得到flag。
參考鏈接
??https://www.52pojie.cn/thread-497018-1-1.html??
??https://blog.csdn.net/liujiandu101/article/details/84390269??
??https://blog.csdn.net/baidu_41388533/article/details/111292441??
??https://blog.csdn.net/qq_34139994/article/details/105391611??