——本人僅是一名初學者,如有疏漏之處,還請列位前輩們指教,謝謝![email protected]
共享軟件是軟件業目前世界上比較熱門的話題,國內更是如此。成千上萬的中國程序員以極大的熱情投入到這個領域來,都憧憬著用辛勤的勞動來獲得豐厚的回報;但,實際並非如此,絕大多數的人都弑羽而歸。值得注意的是:除了選題和技術上的原因外,最大的原因就是共享軟件被破解(Crack)了。 { 利用RSA進行注冊碼的數字簽名驗證 }
if RSAVerify(MD5(Key), MD5(Code), e, n) then
ShowMessage('注冊成功!')
else
ShowMessage('注冊失敗!');
{ 這裡Key是用戶輸入的注冊碼,是由你發送給注冊用戶的 }
{ Code是根據用戶輸入的用戶名自動計算出來的注冊碼 }
{ e是RSA算法的公匙,而n是RSA算法的模數。 }
這個注冊函數即使使用了強勁的RSA算法進行注冊碼驗證,可是依然很容易被破解,我們只要把這裡修改為: { 將邏輯判斷改為否 }
if not RSAVerify(MD5(Key), MD5(Code), e, n) then
ShowMessage('注冊成功!')
else
ShowMessage('注冊失敗!');
就可以了。這時戲劇性的結果會產生:隨便輸入任何注冊碼都可以注冊通過,相反輸入正確的注冊碼卻無法通過注冊。:) 其具體操作是先反匯編或者跟蹤你的程序,找到判斷注冊碼的cmp、test等匯編指令後的關鍵跳轉指令處,通常是je、jz之類的匯編指令,把它們修改為jne或jnz即可,這樣常常只需要修改一個字節就可以完美破解之。:) { 探測FileMon }
function DetectFileMon: Boolean;
begin
if CreateFile(PChar('.FILEVXD'),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0) <> INVALID_HANDLE_VALUE then
Result := True //如果有,就Down機!
else
Result := False;
end;
當然,你可以保護得更好一些:可以不采用臨時Dll,而把解密後的關鍵代碼用WriteProcessMemory這個API函數寫入到主可執行文件自己進程被提交(Committed)的內存頁面的指定位置去。這樣由於磁盤上沒有解密後的臨時文件,破解更加困難。事實上,目前世界上最強勁的專業保護軟件Armadillo就是用的這種方法。而且這種方法可以充分防止被調試器Dump。但實現起來比較困難,尤其是在WinNT 5以後的操作系統中。 EncryptedCode = Blowfish(MD5(UserName), MD5(Key));
//你的加密算法,使用了Blowfish(對稱算法)和MD5(Hash算法)
雖然我不了解Blowfish和MD5算法的原理,也不會逆向它們,但我了解你的效驗算法的流程和算法名,我馬上就可以從網上找到類似的Blowfish和MD5算法包,從而模擬你的軟件仿造出注冊機,啊?!真是……$&*&($#%@! 0167:005B9F70 MOV EAX,[EBP-10]
0167:005B9F73 CALL 00404000
0167:005B9F78 PUSH EAX
0167:005B9F79 MOV EAX,[EBP-10]
0167:005B9F7C CALL 004041C4
0167:005B9F81 LEA ECX,[EBP-14]
0167:005B9F84 POP EDX
0167:005B9F85 CALL 004B860C
當然,最好把Hash算法也全部改名,給會給他們制造更多的困難。但注意,MD5和SHA之類的Hash的初始值會被Cracker從內存中找到,這樣他就知道了你用的Hash了。所有建議同時使用MD5的變形算法Ripe-MD(RMD)128或160和其它的Hash,如Tiger, Haval等算法。 { 檢查自己的進程的父進程是否為Explorer.exe,否則是被調試器加載了 }
{ 不過注意,控制台程序的父進程在WinNT下是Cmd.exe哦!}
{ 注意加載TlHelp32.pas單元 }
procedure CheckParentProc;
var //檢查自己的進程的父進程
Pn: TProcesseNtry32;
sHandle: THandle;
H, ExplProc, ParentProc: Hwnd;
Found: Boolean;
Buffer: array[0..1023] of Char;
Path: string;
begin
H := 0;
ExplProc := 0;
ParentProc := 0;
//得到Windows的目錄
SetString(Path,
Buffer,
GetWindowsDirectory(Buffer, Sizeof(Buffer) - 1));
Path := UpperCase(Path) + 'EXPLORER.EXE'; //得到Explorer的路徑
//得到所有進程的列表快照
sHandle := CreateToolHelp32SnapShot(TH32CS_SNAPALL, 0);
Found := Process32First(sHandle, Pn); //查找進程
while Found do //遍歷所有進程
begin
if Pn.szExeFile = ParamStr(0) then //自己的進程
begin
ParentProc := Pn.th32ParentProcessID; //得到父進程的進程ID
//父進程的句柄
H := OpenProcess(PROCESS_ALL_Access, True, Pn.th32ParentProcessID);
end
else if UpperCase(Pn.szExeFile) = Path then
ExplProc := Pn.th32ProcessID; //Explorer的PID
Found := Process32Next(sHandle, Pn); //查找下一個
end;
//嗯,父進程不是Explorer,是調試器……
if ParentProc <> ExplProc then
begin
TerminateProcess(H, 0); //殺之!除之而後快耶! :)
//你還可以加上其它什麼死機代碼來消遣消遣這位可愛的Cracker :)
end;
end;
你可以在Delphi或者VC中試試,呵呵,是不是把Delphi和VC殺掉了,因為你現在用的是Delphi和VC的內置調試器來運行你的程序的,當然它會六親不認了,呵呵!調試的時候你還是把它注釋掉吧,發布時別忘記激活喲!