另類序號產生器
本文主要說明序號產生器編寫的另一種方式,實現將一個MFC程式授權程式改造成一個標準的序號產生器,這樣我們就可以繞過不必分析繁雜的加密過程了。
參考資料:《看雪學院精華三》中關於MFC程式分析文章;
目標簡介:一個MFC做的授權程式,註冊碼保護,介面有一個序列號視窗(只讀屬性),一註冊碼輸入視窗,一個註冊按鈕。
經過反編譯分析得到程式大致流程:
1) 程式啟動時讀取網路卡資訊後運算後顯示於只讀視窗中;
2) 取得使用者輸入的註冊碼;
3) 判斷輸入的註冊碼是否合要求;
4) 讀取本機網路卡資訊並進行運算,返回運算後的結果;
5)
將運算後的網路卡資訊與輸入的註冊碼一起進行運算比較,產生正確註冊碼,判斷後返回判斷結果;
6) 正確則將註冊碼寫入登錄檔中,錯誤則提示;
7) 程式中各種功能都是獨立的過程呼叫。
根據以上的分析我們就有了大致改造思路以達到我們的目的,具體思路如下:
1. )使程式能接受我們的輸入;
2. )替換步驟4)中得到的網路卡資訊運算後的返回結果換成我們的輸入;
3. )將步驟5)後得到的註冊碼透過一個對話方塊顯示出來。
根據我們思路經過具體分析總結出下面幾個待解決問題:
1:如何使程式能接受我們的輸入?
我的如法為用eXeScope將只讀視窗的屬性修改為可寫,用於我們輸入資訊;
2:如何得到我們的資訊替代運算後的資訊?
一般的做法就是在程式中加入自己的程式碼,在步驟4)中返回運算後的資訊時轉到我們程式碼中,在我們的程式碼中實現輸入資訊的獲取,並替換原來的運算結果,最終實現返回我們輸入的資訊到步驟5)。
這裡需要解決兩個問題:如何加入我們的程式碼、如何獲得輸入的資訊。
問題一用SMC方法就可以很好解決,具體做法參見《看雪的精華三》中SMC部分。
在解決問題二時我遇到一些問題:原來我打算用GETWINDOWTEXT函式獲取我們輸入資訊的視窗的字串,但似乎用MFC寫成的程式在建立視窗時是動態分配視窗控制程式碼,即每次執行時輸入視窗的控制程式碼是不固定的,這就造成沒法使用GETWINDOWTEXT來取得我們想要的資訊,可能是我對MFC程式的不瞭解,有那位高人知道就指點一二。
現在似乎山窮水盡了,再用IDA分析一下程式,發現程式中在在步驟5)有一個地方是呼叫了UpdateData(BOOL)函式,如下所示:
004024FF
push esi
00402500 push 1
00402502
call j_?UpdateData@CWnd@@QAEHH@Z ; CWnd::UpdateData(int)
00402507
mov edx, [esi+64h]
這個有什麼用呢?用MFC寫過程式的人都知道,MFC封裝了視窗中的訊息傳遞,在增加一個視窗後可以增加一個成員對應視窗的文字,而UpdateData(BOOL)就是用來完成將視窗的資訊更新到成員的功能,它的引數就是更新的方向,為1時就是將視窗中的資訊,也就是我們輸入的註冊碼更新到它自定義的成員中,那00402507的語句應該就是將得到的註冊碼寫入成員變數中,那我們輸入的資訊應該也是從這裡可得到。
根據上面的猜測我們做一下試驗:修改了只讀視窗的屬性,使它可寫。用ICEL載入程式,將中斷下於00402502處,等待程式出現主視窗後修改原只讀視窗中的資訊以及按正確格式輸入錯誤的註冊碼,點選註冊按鈕,程式中斷在我們00402502,再用F10執行一步,到達00402507
,我們檢視ESI+64 處的記憶體,果然看到了我們輸入的註冊碼以及我們在原只讀視窗中修改後的資訊,那麼我們就找到辦法解決問題2)了。如此我們要插入的程式碼基本流程就可以形成了,如下:
1).儲存步驟4)返回前的狀態;
2).呼叫UpdateData功能,取得我們需要的資訊
3).將得到的資訊換步驟4)中運算後的結果
4).正常返回步驟4)
3 如何顯示正確的註冊碼?
我採用的方法是將步驟5)中運算後的正確註冊碼的記憶體地址替換步驟6)中出錯提示時的字串呼叫的地址。這樣程式就可以自己顯示正確的註冊碼了。
經過上面3 步後我們就已經能實現的我們的目標了。
最後整理一下,我們改動後的程式流程:
1) 遮蔽程式啟動時讀取網路卡資訊後運算後顯示於只讀視窗中的過程,因為它要用到步驟4)的呼叫;
2) 取得我們輸入的資訊和符合要求的錯誤註冊碼;
3) 判斷輸入的註冊碼是否合要求;
4) 讀取本機網路卡資訊並進行運算,返回前轉到我們插入的程式碼中,將取得的視窗資訊替換經過運算後的返回值後返回原來4)中下一條指令處;
5) 將我們的資訊與輸入的註冊碼一起進行運算比較,產生正確註冊碼,判斷後返回判斷結果;
6) 將5)中得到的正確註冊碼地址替換原錯誤提示的字串地址,彈出正確註冊碼。
經過如上改造我們就可以將一個原來程式改造成一個序號產生器,但在實際測試中發現在同一種作業系統中程式才能正確執行。