您好,登錄后才能下訂單哦!
(1)序列號保護機制
數學算法一項都是密碼加密的核心,但在一般的軟件加密中,它似乎并不太為人們關心,因為大多數時候軟件加密本身實現的都是一種編程的技巧。但近幾年來隨著序列號加密程序的普及,數學算法在軟件加密中的比重似乎是越來越大了。
我們先來看看在網絡上大行其道的序列號加密的工作原理。當用戶從網絡上下載某個shareware——共享軟件后,一般都有使用時間上的限制,當過了共享軟件的試用期后,你必須到這個軟件的公司去注冊后方能繼續使用。注冊過程一般是用戶把自己的私人信息(一般主要指名字)連同信用卡號碼告訴給軟件公司,軟件公司會根據用戶的信息計算出一個序列碼,在用戶得到這個序列碼后,按照注冊需要的步驟在軟件中輸入注冊信息和注冊碼,其注冊信息的合法性由軟件驗證通過后,軟件就會取消掉本身的各種限制,這種加密實現起來比較簡單,不需要額外的成本,用戶購買也非常方便,在互聯網上的軟件80%都是以這種方式來保護的。
我們注意到軟件驗證序列號的合法性過程,其實就是驗證用戶名和序列號之間的換算關系是否正確的過程。其驗證最基本的有兩種,一種是按用戶輸入的姓名來生成注冊碼,再同用戶輸入的注冊碼比較,公式表示如下:
序列號 = F(用戶名)
但這種方法等于在用戶軟件中再現了軟件公司生成注冊碼的過程,實際上是非常不安全的,不論其換算過程多么復雜,解密者只需把你的換算過程從程序中提取出來就可以編制一個通用的注冊程序。
另外一種是通過注冊碼來驗證用戶名的正確性,公式表示如下:
用戶名稱 = F逆(序列號) (如ACDSEE,小樓注)
這其實是軟件公司注冊碼計算過程的反算法,如果正向算法與反向算法不是對稱算法的話,對于解密者來說,的確有些困難,但這種算法相當不好設計。
于是有人考慮到一下的算法:
F1(用戶名稱) = F2(序列號)
F1、F2是兩種完全不同的的算法,但用戶名通過F1算法的計算出的特征字等于序列號通過F2算法計算出的特征字,這種算法在設計上比較簡單,保密性相對以上兩種算法也要好的多。如果能夠把F1、F2算法設計成不可逆算法的話,保密性相當的好;可一旦解密者找到其中之一的反算法的話,這種算法就不安全了。一元算法的設計看來再如何努力也很難有太大的突破,那么二元呢?
特定值 = F(用戶名,序列號)
這個算法看上去相當不錯,用戶名稱與序列號之間的關系不再那么清晰了,但同時也失去了用戶名于序列號的一一對應關系,軟件開發者必須自己維護用戶名稱與序列號之間的唯一性,但這似乎不是難以辦到的事,建個數據庫就好了。當然你也可以根據這一思路把用戶名稱和序列號分為幾個部分來構造多元的算法。
特定值 = F(用戶名1,用戶名2,...序列號1,序列號2...)
現有的序列號加密算法大多是軟件開發者自行設計的,大部分相當簡單。而且有些算法作者雖然下了很大的功夫,效果卻往往得不到它所希望的結果。其實現在有很多現成的加密算法可以用,如RSADES,MD4,MD5,只不過這些算法是為了加密密文或密碼用的,于序列號加密多少有些不同。我在這里試舉一例,希望有拋磚引玉的作用:
1、在軟件程序中有一段加密過的密文S
2、密鑰 = F(用戶名、序列號) 用上面的二元算法得到密鑰
3、明文D = F-DES(密文S、密鑰) 用得到的密鑰來解密密文得到明文D
4、CRC = F-CRC(明文D) 對得到的明文應用各種CRC統計
5、檢查CRC是否正確。最好多設計幾種CRC算法,檢查多個CRC結果是否都正確
用這種方法,在沒有一個已知正確的序列號情況下是永遠推算不出正確的序列號的。
(2)如何***序列號保護
要找到序列號,或者修改掉判斷序列號之后的跳轉指令,最重要的是要利用各種工具定位判斷序列號的代碼段。這些常用的API包括GetDlgItemInt, GetDlgItemTextA, GetTabbedTextExtentA, GetWindowTextA, Hmemcpy (僅僅Windows 9x), lstrcmp, lstrlen, memcpy (限于NT/2000)。
1)數據約束性的秘訣
這個概念是+ORC提出的,只限于用明文比較注冊碼的那種保護方式。在大多數序列號保護的程序中,那個真正的、正確的注冊碼或密碼(Password)會于某個時刻出現在內存中,當然它出現的位置是不定的,但多數情況下它會在一個范圍之內,即存放用戶輸入序列號的內存地址±0X90字節的地方。這是由于加密者所用工具內部的一個Windows數據傳輸的約束條件決定的。
2)Hmemcpy函數(俗稱萬能斷點)
函數Hmemcpy是Windows9x系統的內部函數,位于KERNEL32.DLL中,它的作用是將內存中的一塊數據拷貝到另一個地方。由于Windows9x系統頻繁使用該函數處理各種字串,因此用它作為斷點很實用,它是Windows9x平臺最常用的斷點。在Windows NT/2K中沒有這個斷點,因為其內核和Windows9x完全不同。
3)S命令
由于S命令忽略不在內存中的頁面,因此你可以使用32位平面地址數據段描述符30h在整個4GB(0~FFFFFFFFh )空間查找,一般用在Windows9x下面。具體步驟為:先輸入姓名或假的序列號(如: 78787878),按Ctrl+D切換到SoftICE下,下搜索命令:
s 30:0 L ffffffff '78787878'
會搜索出地址:ss:ssssssss(這些地址可能不止一個),然后用bpm斷點監視搜索到的假注冊碼,跟蹤一下程序如何處理輸入的序列號,就有可能找到正確的序列號。
4)利用消息斷點
在處理字串方面可以利用消息斷點WM_GETTEXT和WM_COMMAND。前者用來讀取某個控件中的文本,比如拷貝編輯窗口中的序列號到程序提供的一個緩沖區里;后者則是用來通知某個控件的父窗口的,比如當輸入序列號之后點擊OK按鈕,則該按鈕的父窗口將收到一個WM_COMMAND消息,以表明該按鈕被點擊。
BMSG xxxx WM_GETTEXT (攔截序列號)
BMSG xxxx WM_COMMAND (攔截OK按鈕)
可以用SoftICE提供的HWND命令獲得窗口句柄的信息,也可以利用Visual Studio中的Spy++實用工具得到相應窗口的句柄值,然后用BMSG設斷點攔截。例:
BMSG 0129 WM_COMMAND
2、Nag窗口
Nag的本義是煩人的意思。Nag窗口是軟件設計者用來不時提醒用戶購買正式版本的窗口。軟件設計者可能認為當用戶受不了試用版中的這些煩人的窗口時就會考慮購買正式版本。它可能會在程序啟動或退出時彈出來,或者在軟件運行的某個時刻隨機或定時地彈出來,確實比較煩人。
去除警告窗口常用的三種方法是:修改程序的資源、靜態分析,動態分析。
去除警告窗口用資源修改工具是個不錯的方法,可以將可執行文件中的警告窗口的屬性改成透明、不可見,這樣就變相去除了警告窗口。
如果是動態跟蹤調試,只需找到創建此窗口的代碼,跳過即可。常用的顯示窗口的函數有MessageBoxA、MessageBoxExA、MessageBeep 、DialogBoxParamA 、ShowWindow、CreateWindowExA等。然而某些警告窗口用這些斷點不管用,就可試試利用消息設斷點,一般都應能攔截下來。
例:利用消息斷點攔截警告窗口:
切換到SOFTICE下命令: HWND
應看到如下的類似信息:
Window-Handle | hQueue | SZ | QOwner | Class-Name | Window-Procedure |
0080 (0) | 2057 | 32 | MSGSVR32 | #32711 (switch_win) | 17EF:00004B6E |
0084 (1) | 2057 | 32 | EXPLORER | shell_trayWnd | 1487:0000016C |
... | ... | ... | ... | ... | ... |
在這些列表中查找相關應用程序的窗口句柄。如果NAG窗口上有OK按鈕,在class name查找“button”。如果NAG窗口上什么都沒有,那可試驗找出正確的句柄。句柄列表可能非常長,但通常NAG窗口的句柄一般在列表的前面。
注:在這里推薦用SMU Winspector工具協助破解NAG.它能顯示你所需要的信息:Window-Handle, Window-Class Name, Window-Text, Parent Window-Handle, Parent-Window Class Name, Parent Window-Text, Module ...
一但找到NAG窗口的句柄,應用BMSG命令在Windows的消息上下斷點。現在假設NAG窗口有OK按鈕,你己找到正確的句柄(handle),這時下命令:
BMSG 0084 WM_DESTROY
0084是NAG窗口的句柄(handle)。這條命令是NAG窗口從屏幕上消失時,SoftICE將中斷。此時將深入到一些不認識的API函數,可按F12返回程序。需要指出,跟蹤的目的是發現NAG窗口在何處初始化(在返回的CALL用設斷)。NAG窗口大多用Created/Destroyed類似的CALL,因此如發現這些,就可按需要跟蹤下去。
3、時間限制
(1) 定時器
有些程序的試用版每次運行都有時間限制,例如運行10分鐘或20分鐘就停止工作,必須重新運行該程序才能正常工作。這些程序里面自然有個定時器來統計程序運行的時間。
1)使用Settimer()
常用的計數器是函數Settimer(),調用這個函數創建的定時器可以發出消息VM_TIMER,或者在定時期滿時調用一個回調函數。 使用這個函數會使時間延時,精度不高。
2)使用timeSetEvent()
給Windows驅動程序最精確的周期性通知是由Windows的多媒體服務timeSetEvent()提供的。它的時間可以精確到1毫秒。
3)使用VXD
可以使用VMM的Set_Global_time_Out()服務來迫使回調函數的幾個毫秒再執行,這就創造了一個“只有一次”的定時器。VXD可以在回調中再次調用Set_Global_time_Out()來開始下一個定時器,這樣提供了一個連續運行的定時器了。
4)其它
GetTickCount():精度不高;
timeGetTime(): 可以以毫秒級返回windows開始后的時間。
(2)時間限制
一般這類保護的軟件都有時間上的限制,如試用30天等,當過了共享軟件的試用期后,就不予運行,只有向軟件作者付費注冊之后才能得到一個無時間限制的注冊版本。
這種類型程序很多,讓你有10天、20天、30天等,它們在安裝時,在你的系統某處做上時間標記,每次運行時用當前系統時間和安裝時的時間比較,判斷你還否能使用。
如最典型的30天限制的一種情況:
mov ecx,1E ; 把1E (30天 十進制) 放入 ecx
mov eax,[esp+10] ; 把用過天數放到eax
cmp eax,ecx ; 在此比較
jl ...
如碰到這種情況,只需把"mov eax,[esp+10]"改成"mov eax,1" 。
要記住當前年份、月份的十六進制的一些表示方法,如:2000年的十六進制是07D0,然后用W32DASM反匯編你的程序,用查找字符串的方法找D007(在機器碼中位置顛倒了一下)或其它類似時間的數字,有可能會找到有價值的線索。你別小看這種方法,對那些沒怎么防范的程序,此招很有效。
如:一程序限定在2000年使用,可能有如下一代碼:
:00037805 817C2404D0070000 cmp dword ptr [esp+04], 000007D0 比較是否在2000年。
(3)與時間相關函數
1、GetSystemTime 得當前系統時間
說明: 在一個SYSTEMTIME中載入當前系統時間,這個時間采用的是“協同世界時間”(即UTC,也叫做GMT)格式。 VOID GetSystemTime( LPSYSTEMTIME lpSystemTime // SYSTEMTIME,隨同當前時間載入的結構 |
2、GetLocalTime 得當前本地時間
VOID GetLocalTime( LPSYSTEMTIME lpSystemTime // SYSTEMTIME,用于裝載本地時間的結構 |
3、SystemTimeToFileTime 根據一個FILETIME結構的內容,載入一個SYSTEMTIME結構
BOOL SystemTimeToFileTime( CONST SYSTEMTIME * lpst, // SYSTEMTIME,包含了系統時間信息的一個結構 |
4、SetTimer 創建一定時器,在指定時間內暫停
UINT SetTimer( HWND hwnd, // 時間信息句柄 UINT idtimer, // 定時器ID 標識符 UINT uTimeout, // 暫停時間 TIMERPROC tmprc // 處理定時過程的程序入口地址 ); |
4、Key File保護 【習題】
Key File(注冊文件)是一種利用文件來注冊軟件的保護方式。Key File一般是一個小文件,可以是純文本文件,也可以是包含不可顯示字符的二進制文件,其內容是一些加密過或未加密的數據,其中可能有用戶名、注冊碼等信息。文件格式則由軟件作者自己定義。試用版軟件沒有注冊文件,當用戶向作者付費注冊之后,會收到作者寄來的注冊文件,其中可能包含用戶的個人信息。用戶只要將該文件放入指定的目錄,就可以讓軟件成為正式版。該文件一般是放在軟件的安裝目錄中或系統目錄下。軟件每次啟動時,從該文件中讀取數據,然后利用某種算法進行處理,根據處理的結果判斷是否為正確的注冊文件,如果正確則以注冊版模式來運行。
(1)破解Key File一般思路
1. 最好分析Key File的工具是十六進制工具,普通的文本編輯工具不太適合。
2. 對付這類程序,你首先建立一假的Key File文件。一般的軟件容許Key File有不同的大小和文件名,你建立的文件內容必須易讀,跟據情況調整Key File的大小和文件名。為什么要易讀呢?因為目標程序從Key File中讀取數據,然后進行處理,易讀有利于你分析其運算過程。
3. Key File文件在大多數情況下,是以'*.key'形式存在的。
4. Key File文件名可用W32DASM或十六進制工具打開程序用查找字符串方式確定;
5. 讀用戶手冊(有時作者可能會提到);
6. 用Filemon 這一工具,它能實時監視系統各文件的狀態,因此運行程序時,如它去讀指定文件名的Key File時,會在Filemon顯示Key File文件名。一但你發現Key File文件名,就建立一假的Key File到要被crack軟件目錄下,然后去crack。
(2)Windows下破解Key File幾個常用的函數:
函數ReadFile BOOL ReadFile( |
函數CreateFileA HANDLE CreateFileA( LPCTSTR lpFileName, // String,要打開的文件的名字 |
函數_lopen( ) HFILE _lopen( LPCSTR lpPathName, // 欲打開文件的名字 |
函數FindFirstFileA( ) HANDLE FindFirstFile( LPCTSTR lpFileName, // 欲搜索的文件名。可包含通配符,并可包含一個路徑或相對路徑名 |
5、功能限制的程序
這種程序一般是DEMO版或菜單中部分選項是灰色。有些DEMO版本的部分功能里面根本就沒有。而有些程序功能全有,只要注冊后就正常了。
你使用這些DEMO程序部分被禁止的功能時,會跳出提示框,說這是DEMO版等話,它們一般都是調用MessageBox[A] 或 DialogBox[A]等函數。你可在W32DASM反匯編它,一般能找到如下字符串:"Function Not Avaible in Demo" 或 "Command Not Avaible" 或 "Can't save in Shareware/Demo"等,這些CALL會被相應的調用,可作為你破解的一指示器。
另外,就是菜單中部分選項是灰色的不能用,一般它們是通過如下兩種函數實現的:
(1)EnableMenuItem
允許、禁止或變灰指定的菜單條目 |
BOOL EnableMenuItem( HMENU hMenu, // 菜單句柄 UINT uIDEnableItem, // 菜單ID,形式為:充許,禁止,或灰 UINT uEnable //菜單項目旗幟 ); Returns |
在ASM代碼形式如下: PUSH uEnable //uEnable=0 則菜單選項允許 PUSH uIDEnableItem PUSH hWnd CALL [KERNEL32!EnableMenuItem] |
(2)EnableWindow
允許或禁止鼠標和鍵盤控制指定窗口和條目(禁止時菜單變灰) |
BOOL EnableWindow( HWND hWnd, // 窗口句柄 BOOL bEnable // 允許/禁止輸入 ); Returns 如窗口以前被禁止則返回一TRUE,否則返回 FALSE。 |
6、cd 檢測
簡單也最常見的光盤保護就是程序在啟動時判斷光驅中的光盤上是否存在特定的文件,如果不存在則認為用戶沒有正版光盤,拒絕運行。在程序運行的過程當中一般不再檢查光盤的存在與否。Windows下的具體實現一般是這樣的:先用GetLogicalDriveStrings( )或GetLogicalDrives( )得到系統中安裝的所有驅動器的列表,然后再用GetDriveType( )檢查每一個驅動器,如果是光驅則用CreateFileA( )或FindFirstFileA( )等函數檢查特定的文件存在與否,并可能進一步地檢查文件的屬性、大小、內容等。 這種光盤檢查是比較容易被破解的,解密者只要利用上述函數設斷點找到程序啟動時檢查光驅的地方,修改判斷指令就可以跳過光盤檢查。
(1)可將游戲(或其它程序)的光盤拿出,運行游戲,將出現一些錯誤提示,如: Please insert the - CD, or: You need the CD to play the - . 利用這提示可在W32DASM中利用串式數據參考功能查找相應的代碼進行分析。
(2)相關函數
1、GetDrivetype(a) 判斷一個磁盤驅動器的類型
UINT GetDriveType( LPCTSTR lpRootPathName // String,包含了驅動器根目錄路徑的一個字串 | |
返回值 | |
0 | 驅動器不能識別 |
1 | 指定的目錄不存在 |
2 | DriveRemoveable |
3 | A Fixed Disk (HardDrive) |
4 | Remote Drive(Network) |
5 | Cd-Rom驅動器 |
6 | RamDisk |
如果是普通的程序,你可將EAX由5改成3即可。
注意:有些程序可能檢測光盤根目錄相關文件,CD的卷標也可能被檢測。
2、GetLogicalDrives 判斷系統中存在哪些邏輯驅動器字母
這函數沒有參數 |
返回值 |
這個結構中的二進制位標志著存在哪些驅動器。其中,位0設為1表示驅動器A:存在于系統中;位1設為1表示存在B:驅動器;以次類推 |
3、GetLogicalDriveStrings 獲取一個字串,其中包含了當前所有邏輯驅動器的根驅動器路徑
DWORD GetLogicalDriveStrings( DWORD nBufferLength, // 字串的長度 |
返回值 |
裝載到lpBuffer的字符數量(排除空中止字符)。如緩沖區的長度不夠,不能容下路徑,則返回值就變成要求的緩沖區大小。零表示失敗。會設置GetLastError |
4、GetFileAttributesA 判斷指定文件的屬性
DWORD GetFileAttributes( LPCTSTR lpFileName //指定欲獲取屬性的一個文件的名字 |
5、GetFileSize 判斷文件長度
DWORD GetFileSize( HANDLE hFile, // 文件的句柄 |
返回值 |
返回文件長度。&HFFFFFFFF表示出錯。注意如lpFileSizeHigh不為NULL,且結果為&HFFFFFFFF,那么必須調用GetLastError,判斷是否實際發生了一個錯誤,因為這是一個有效的結果 |
6、GetLastError 針對之前調用的api函數,用這個函數取得擴展錯誤信息
返回值 | |
由api函數決定。請參考api32.txt文件,其中列出了一系列錯誤常數;都以ERROR_前綴起頭。常用的錯誤代碼見下表 | |
ERROR_INVALID_HANDLE | 無效的句柄作為一個參數傳遞 |
ERROR_CALL_NOT_IMPLEMENTED | 在win 95下調用專為win nt設計的win32 api函數 |
ERROR_INVALID_PARAMETER | 函數中有個參數不正確 |
7、ReadFile 從文件中讀出數據
具體參考KEYFILE一節。
8、其它一些CDROM信息
中斷2F是mscdex中斷,可用bpint 2f, al=0 ah=15檢測Mmscdex是否安裝。
也可試著用文件存取設斷
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。