前些天分析了啟明公司的口語光盤,同時也用Delphi編寫了個補丁程序。以往的補丁程序原理是利用了資源釋放形式進行,因此,最終生成的補丁程序會奇大無比(=自身體積加上目標破解文件的體積),就拿啟明光盤的破解補丁說吧,生成出來並壓縮後仍然有800K左右。但考慮到補丁原理只是修改了一個偏移量的值,如此大動干戈地把破解後的文件制作成資源文件來進行覆蓋,實在是下策,有沒有更好的辦法呢。肯定有!!!於是就有了自己的偏移量補丁程序模塊啦
//******************** 以下是需要修改的常量或變量 ****************
(*主對話框界面*)
szMainCaption = '海浪輕風偏移量補丁程序V1.0';
szName = '啟明英語口語考試系統'; //目標破解文件名
szBy = '[email protected]'; //軟件開發者
szCracker = '海浪輕風'; //解密人
szCrackeremail = 'mailto:[email protected]'; //解密人email
szLink = 'http://hi.baidu.com/beyond0769'; //主頁地址
szTime = '2008-03-18'; //破解時間
szCopyright = '本程序只作研究學習用,禁止非法用途';
szKeyGenName = '海浪輕風偏移量補丁程序';
szScroll = '海浪輕風偏移量補丁程序' + #$0A + #$0A
+ '本模塊用純API函數編寫,界面構建'+ #$0A#$0A
+ '利用了資源文件形式,大大節省了'+ #$0A#$0A
+ '生成後的文件體積,壓縮後只有'+ #$0A#$0A
+ '41k左右。同時加入了uFMOD單元' + #$0A#$0A
+ '實現背景音樂循環播放。 ' + #$0A#$0A + #$0A
+ '特別鳴謝:' + #$0A + #$0A
+ 'you_know[FCG]'+ #$0A+ #$0A
+ '看雪學院的Delphi牛人們' + #$0A+ #$0A
+ '以及uFMOD的程序員'+ #$0A+ #$0A
+ '感謝一直在背後默默支持我的琴兒' + #$0A + #$0A
+ '補丁使用方法:'+ #$0A + #$0A
+ '把補丁復制到目標文件相同目錄下'+ #$0A + #$0A
+ '運行,點擊“應用補丁”即可。 '+ #$0A + #$0A
+ '本程序只作研究學習用' + #$0A#$0A
+ '禁止一切非法商業用途' + #$0A#$0A
+ '程序破解 by 海浪輕風(黃仁來)' + #$0A#$0A
+ '程序編程 by 海浪輕風(黃仁來) + #$0A#$0A
+ '[email protected]' + #$0A + #$0A
+ 'http://beyond-0769.blog.163.com/' + #$0A + #$0A
+ '2008-03-18';
var
FileName: PChar = 'SpokenEngMain.exe'; //破解目標文件完整名稱
IntFileSize: Cardinal = 2731008; //破解目標文件的大小字節
RBuffer: array[0..1] of Byte = ($75, $0C); //目標破解文件原有的偏移量
WBuffer: array[0..1] of Byte = ($EB, $0C); //修改後的偏移量
OffsetPos: TOVERLAPPED = (Internal: 0; InternalHigh: 0; Offset: $000EE089; OffsetHigh: 0; hEvent: 0);
CommandLine: PChar; // ↑↑以上是物理地址,通過W32DSM可以查到
hwndname: HWND;
hFile: THANDLE;
Numb: DWord;
Buffer: array[0..1] of Byte;
nType: DWord;
pMsg: string;
////////////////////
//全局變量數據聲明 ******************** 以下常量或變量基本上無需要修改 ******************8
////////////////////
h_Icon: HICON; //實例句柄
h_Inst: HMODULE;
h_Cur: hCursor;
h_Brush: HBRUSH;
sRectL, sRectM, sRectA: TRect;
//RegName,RegCode:Array[1..256] of Byte; //原版數據;下句是修改後的
RegName, RegCode: string;
h_ScrollParent, h_Scroll: HWND;
ScrollWidth, ScrollHeight: Word;
xCount: Integer;
LineCount: Word;
const
////////////////
//資源常量定義//
////////////////
MAINICON = 100;
LINKCURSOR = 112;
IDD_LICENSEDLG = 1000;
IDD_MAINDLG = 2000;
IDD_ABOUTDLG = 3000;
LICENSE_YES = 1001;
LICENSE_NO = 1002;
LICENSE_CLOSE = 1004;
MAIN_CALC = 2001; //計算按鈕控件ID(本實例已經去掉)
MAIN_EXIT = 2002; //退出按鈕控件ID
MAIN_ABOUT = 2003; //關於按鈕控件ID
MAIN_CLOSE = 2004; //關閉按鈕控件ID
ABOUT_OK = 3001;
ABOUT_CLOSE = 3002;
//++++++++++++++++++ 關鍵的爆破過程 ++++++++++++++++++++
procedure PatchFile;
var
Res:boolean;
begin
Setfileattributes(FileName, FILE_ATTRIBUTE_NORMAL + FILE_ATTRIBUTE_ARCHIVE); //設置文件的屬性為正常
hFile := CreateFile(FileName, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or
FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
try
if hFile <> INVALID_HANDLE_VALUE then
begin
if GetFileSize(hFile,nil)<>IntFileSize then
begin
nType := MB_OK or MB_ICONINFORMATION;
pMsg := '文件校驗出錯:'+#13+'文件大小不一致,目標文件(英語口語主程序:' + FileName + ')可能已經被修改,拒絕打補丁!';
exit;
end;
ReadFile(hFile, Buffer, 2, Numb, @OffsetPos); //如果讀出的偏移數據是已經打上補丁的數據,則提示已經打上補丁。
if Word(Buffer[0]) = Word(WBuffer[0]) then begin
nType := MB_OK or MB_ICONINFORMATION;
pMsg := '錯誤提示:'+#13+'目標程序(' + FileName + ')已經打過補丁了,還想怎樣? ^_^';
Res:=True;
exit;
end;
if Word(Buffer[0]) = Word(RBuffer[0]) then {// 讀取偏移是否正確;} begin
CopyFile(FileName, PChar('備份' + FileName), False); //備份破解目標文件;
if WriteFile(hFile, WBuffer, 2, Numb, @OffsetPos) then
begin
nType := MB_OK or MB_ICONINFORMATION;
pMsg := '成功打上補丁! Enjoy it^_^' + #13 +#13+
'Cracked & Coded by 海浪輕風(黃仁來)'; ; //成功補丁;
Res:=True;
end else
begin // 寫入出錯。
nType := MB_OK or MB_ICONERROR;
pMsg := '錯誤提示:'+#13+':請檢查目標文件(' + FileName + ')是否已經被打開,請先將其關閉再嘗試。';
end;
end else {//偏移不正確則提示出錯;}
begin
nType := MB_OK or MB_ICONWARNING;
pMsg := '錯誤提示:'+#13+'目標文件(' + FileName + ')偏移量不符,拒絕打補丁!'+#13+'更多問題請到個人主頁反映。';
ShellExecute(0, nil, szLink, nil, nil, 0);
end;
end else {//文件被打開或文件找不到}
begin
nType := MB_OK or MB_ICONERROR;
pMsg := '補丁出錯 :-( 可能原因如下:' + #13 +
' 1.目標文件找不到:(英語口語主程序:' + FileName + '),請把本程序復制到同一個目錄下再運行。' + #13 +
' 2.目標文件已經被打開,請先將其關閉再嘗試。';
end;
finally
CloseHandle(hFile);
MessageBox(0, PChar(pMsg), PChar('海浪輕風溫馨提示:'), nType);
if Res then ShellExecute(0, nil, szLink, nil, nil, 0);
end;
end;
//+++++++++++++++++ 以下為構造程序主窗口所需的函數過程 ++++++++++++++
Function CountCRLF(Str:String):Word;
Var
Count:Word;
i:Word;
Begin
Count:=1;
For i:=1 to Length(Str) Do
Begin
If Str[i]=#$0A Then Inc(Count);
End;
CountCRLF:=Count;
End;
Procedure DialogInit(hDlg:HWND);
Var
RECT:TRect;
X,Y:Word;
i:Word;
Rgn:HRGN;
Begin
ShowWindow(hDlg,SW_HIDE);
GetWindowRect(hDlg,RECT);
X:=(RECT.Right-RECT.Left) DIV 2;
Y:=(RECT.Bottom-RECT.Top) DIV 2;
For i:=1 to RECT.Right DIV 2 do
Begin
Rgn:=CreateRectRgn(X-i,Y-i,X+i,Y+i);
SetWindowRgn(hDlg,Rgn,True);
ShowWindow(hDlg,SW_SHOW);
DeleteObject(Rgn);
End;
End;
Procedure ItemDraw(lpDIS:PDrawItemStruct);
Var
Str:Array[1..11] of Byte;
Begin
FillRect(lpDIS^.hDC,lpDIS^.rcItem,h_Brush);
SetTextColor(lpDIS^.hDC,$A0A0A0);
//SetTextColor(lpDIS^.hDC,$03FF09); //綠色
SetBkMode(lpDIS^.hDC,TRANSPARENT);
DrawEdge(lpDIS^.hDC,lpDIS^.rcItem,BDR_RAISEDOUTER,BF_RECT);
GetWindowText(lpDIS^.hwndItem,@Str,10);
DrawText(lpDIS^.hDC,@Str,-1,lpDIS^.rcItem,DT_SINGLELINE OR DT_VCENTER OR DT_CENTER);
If lpDIS^.itemState MOD 2=1 Then
Begin
SetTextColor(lpDIS^.hDC,$03FF09); //按下 綠色
DrawText(lpDIS^.hDC,@Str,-1,lpDIS^.rcItem,DT_SINGLELINE OR DT_VCENTER OR DT_CENTER);
DrawEdge(lpDIS^.hDC,lpDIS^.rcItem,BDR_SUNKENOUTER,BF_RECT);
End;
End;
Procedure Paint(dc:HDC;Icon:hIcon;Caption:PChar;BeginRGB:DWORD;EndRGB:DWord;Rect:TRect);
Var
LogBrush:TLogBrush;
LRect,rc:TRect;
LhBR:HBRUSH;
R,G,B,Ri,Gi,Bi,Rt,Gt,Bt:Word;
LFont:HFONT;
Width:Word;
i:Word;
Begin
LRect:=Rect;
B:=EndRGB AND $FF;
G:=(EndRGB SHR 8) AND $FF;
R:=(EndRGB SHR 16) AND $FF;
Bi:=BeginRGB AND $FF;
Gi:=(BeginRGB SHR 8) AND $FF;
Ri:=(BeginRGB SHR 16) AND $FF;
Width:=(LRect.right-LRect.left) DIV 2;
rc.top:=0;
rc.bottom:=LRect.bottom-LRect.top;
LogBrush.lbStyle:=0;
LogBrush.lbHatch:=0;
If Width>=0 Then
Begin
For i:=0 To (Width AND $FF) Do
Begin
rc.left:=1;
rc.right:=i+1;
Bt:=MulDiv(i,Bi,Width)+B;
Gt:=MulDiv(i,Gi,Width)+G;
Rt:=MulDiv(i,Ri,Width)+R;
If Bt>$FF Then Bt:=$FF;
If Gt>$FF Then Gt:=$FF;
If Rt>$FF Then Rt:=$FF;
LogBrush.lbColor:=(Rt SHL 16) OR (Gt SHL 8) OR (Bt);
LhBR:=CreateBrushIndirect(LogBrush);
FillRect(dc,rc,LhBR);
rc.left:=Rect.right-Rect.left-i;
rc.right:=Rect.right-Rect.left-i-1;
FillRect(dc,rc,LhBR);
DeleteObject(LhBR);
End;
End;
LogBrush.lbColor:=$9E6A54; //標題欄顏色
LhBR:=CreateBrushIndirect(LogBrush);
FrameRect(dc,Rect,LhBR);
DeleteObject(LhBR);
SetTextColor(dc,$05E8FC);
SetBkMode(dc,TRANSPARENT);
Rect.left:=2;
Rect.top:=2;
Dec(Rect.bottom,2);
LFont:=CreateFont(-$C,0,0,0,$2BC,0,0,0,1,0,0,0,0,'宋體');
SelectObject(dc,LFont);
If Icon<>0 Then
Begin
DrawIconEx(dc,2,2,Icon,$10,$10,0,0,3);
Rect.left:=$14;
End;
DrawText(dc,Caption,-1,Rect,$24);
DeleteObject(LFont);
End;
//////////////////////////////////////////////////////////////////
//滾動文本函數
Function ScrollProc(hDlg:HWND;Msg,wParam,lParam:DWord):LRESULT;stdcall;
Var
sRect:TRect;
sPaint:PAINTSTRUCT;
DC:HDC;
LFont:HFONT;
Begin
If Msg=WM_PAINT Then
Begin
DC:=BeginPaint(hDlg,sPaint);
GetClIEntRect(hDlg,sRect);
//SetTextColor(DC,$A0A0A0);
SetTextColor(DC,$03FF09); //滾動字幕呈 綠色
SetBkMode(DC,TRANSPARENT);
LFont:=CreateFont(-$C,0,0,0,0,0,0,0,1,0,0,0,0,'宋體');
SelectObject(DC,LFont);
DrawText(DC,szScroll,-1,sRect,DT_CENTER);
EndPaint(hDlg,sPaint);
DeleteObject(LFont);
End
Else
Begin
CallWindowProc(Pointer(GetWindowLong(hDlg,GWL_USERDATA)),hDlg,Msg,wParam,lParam);
End;
Result:=1;
End;
//////////////////////////////////////////////////////////////////
//關於對話框過程函數
Function AboutProc(hDlg:HWND;Msg,wParam,lParam:DWord):LRESULT;stdcall;
Var
sRect:TRect;
sPaint:PAINTSTRUCT;
sPoint:TPoint;
Begin
Result:=0;
Case Msg of
WM_COMMAND:
Begin
Case wParam of
ABOUT_OK:
Begin
KillTimer(hDlg,$A8);
EndDialog(hDlg,0);
End;
ABOUT_CLOSE:
Begin
KillTimer(hDlg,$A8);
EndDialog(hDlg,0);
End;
End;
End;
WM_PAINT:
Begin
Paint(BeginPaint(hDlg,sPaint),h_Icon,szMainCaption,$767676,0,sRectA);
EndPaint(hDlg,sPaint);
End;
WM_DRAWITEM:
Begin
ItemDraw(PDrawItemStruct(lParam));
Result:=0;
End;
WM_INITDIALOG:
Begin
GetClIEntRect(hDlg,sRectA);
sRectA.Bottom:=sRectA.Top+$14;
h_ScrollParent:=GetDlgItem(hDlg,$BBD);
SendMessage(GetDlgItem(hDlg,$BBB),WM_SETFONT,CreateFont(-$C,0,0,0,$2BC,0,0,0,1,0,0,0,0,'宋體'),0);
SetDlgItemText(hDlg,$BBB,szKeyGenName);
SetDlgItemText(hDlg,$BBC,szCracker);
SetWindowText(hDlg,'關於');
GetClIEntRect(h_ScrollParent,sRect);
ScrollWidth:=sRect.right-sRect.left;
ScrollHeight:=sRect.bottom-sRect.top;
xCount:=ScrollHeight;
LineCount:=CountCRLF(szScroll);
h_Scroll:=CreateWindowEx(WS_EX_LEFT,'Static','',WS_CHILD OR WS_VISIBLE OR SS_CENTER,0,ScrollHeight,ScrollWidth,LineCount*12,h_ScrollParent,0,h_Inst,nil);
SetWindowLong(h_Scroll,GWL_USERDATA,SetWindowLong(h_Scroll,GWL_WNDPROC,LongWord(@ScrollProc)));
DialogInit(hDlg);
SetTimer(hDlg,$A8,60,NIL);
Result:=1;
End;
WM_CTLCOLORDLG:
Begin
SetTextColor(wParam,$A0A0A0);
SetBkMode(wParam,TRANSPARENT);
Result:=h_Brush;
End;
WM_CTLCOLORSTATIC:
Begin
//SetTextColor(wParam,$FE248B); //關於對話框 題目 顏色
SetTextColor(wParam,$FC77B5);
SetBkMode(wParam,TRANSPARENT);
Result:=h_Brush;
End;
WM_LBUTTONDOWN:
Begin
sPoint.x:=lParam AND $FFFF;
sPoint.y:=lParam SHR 16;
If PtInRect(sRectA,sPoint) Then
Begin
PostMessage(hDlg,WM_NCLBUTTONDOWN,2,0);
End;
End;
WM_TIMER:
Begin
Sleep(20);
Dec(xCount);
SetWindowPos(h_Scroll,HWND_TOP,0,xCount,ScrollWidth,LineCount*12,0);
If xCount<(0-LineCount*12) Then
Begin
xCount:=ScrollHeight;
End;
End;
End;
End;
//////////////////////////////////////////////////////////////////
//超連接函數
Function LinkProc(hDlg:HWND;Msg,wParam,lParam:DWord):LRESULT;stdcall;
Begin
Result:=1;
Case Msg of
WM_SETCURSOR:
Begin
SetCursor(h_Cur);
End;
WM_NCHITTEST:
Begin
Result:=1;
End;
WM_LBUTTONUP:
Begin
ShellExecute(0,nil,'http://17339836.qzone.QQ.com',nil,nil,0);//偷了點懶
End;
Else
Begin
CallWindowProc(Pointer(GetWindowLong(hDlg,GWL_USERDATA)),hDlg,Msg,wParam,lParam);
End;
End;
End;
//_____________________________________________________________
//主窗口過程函數
Function MainProc(hDlg:HWND;Msg,wParam,lParam:DWord):LRESULT;stdcall;
Var
sPaint:PAINTSTRUCT;
sPoint:TPoint;
LFont:HFONT;
LinkHWND:HWND;
SetLongRet:Longint;
Begin
Result:=0;
Case Msg of
WM_CTLCOLOREDIT:
Begin
SetTextColor(wParam,$A0A0A0);
SetBkMode(wParam,TRANSPARENT);
Result:=h_Brush;
End;
WM_COMMAND:
Begin
Case wParam AND $FFFF of
MAIN_CALC:
Begin
GetDlgItemText(hDlg,$7DA,@RegName,255);
//GetRegCode; // 計算注冊碼過程
PatchFile; //打補丁過程
SetDlgItemText(hDlg,$7D9,@RegCode);
End;
MAIN_EXIT:
Begin
EndDialog(hDlg,0);
End;
MAIN_ABOUT:
Begin
MessageBeep(0);
DialogBoxParam(h_Inst,LPCTSTR(IDD_ABOUTDLG),hDlg,@AboutProc,0);
End;
MAIN_CLOSE:
Begin
EndDialog(hDlg,0);
End;
$7DA://就是RegName的ID
Begin
Case wParam SHR 16 of
EN_CHANGE: // 在用戶名中輸入數據時,捕獲消息,立即進行計算。過程相當於按下“計算”按鍵過程。
Begin
GetDlgItemText(hDlg,$7DA,@RegName,255);
//GetRegCode;
PatchFile; //打補丁過程;;
SetDlgItemText(hDlg,$7D9,@RegCode);
End;
End;
End;
End;
End;
WM_PAINT:
Begin
Paint(BeginPaint(hDlg,sPaint),h_Icon,szMainCaption,$767676,0,sRectM);
EndPaint(hDlg,sPaint);
End;
WM_DRAWITEM:
Begin
ItemDraw(PDrawItemStruct(lParam));
Result:=0;
End;
WM_INITDIALOG:
Begin
GetClIEntRect(hDlg,sRectM);
sRectM.Bottom:=sRectM.Top+$14;
SetDlgItemText(hDlg,2011,szLink);
SetDlgItemText(hDlg,2008,szTime);
SetDlgItemText(hDlg,2005,szName);
SetDlgItemText(hDlg,2006,szCracker);
SetDlgItemText(hDlg,2007,szBy);
SetDlgItemText(hDlg,2012,szCopyright);
SetWindowText(hDlg,szMainCaption); //任務欄顯示名稱;
LFont:=CreateFont(-$C,0,0,0,$2BC,0,1,0,1,0,0,0,0,'宋體');
LinkHWND:=GetDlgItem(hDlg,2011);
SendMessage(LinkHWND,WM_SETFONT,LFont,0);//設置字體
SetLongRet:=SetWindowLong(LinkHWND,GWL_WNDPROC,LongWord(@LinkProc));
SetWindowLong(LinkHWND,GWL_USERDATA,SetLongRet);
DialogInit(hDlg);
End;
WM_CTLCOLORDLG:
Begin
SetTextColor(wParam,$A0A0A0);
SetBkMode(wParam,TRANSPARENT);
Result:=h_Brush;
End;
WM_CTLCOLORSTATIC:
Begin
SetTextColor(wParam,$A0A0A0);
SetBkMode(wParam,TRANSPARENT);
Result:=h_Brush;
End;
WM_LBUTTONDOWN:
Begin
sPoint.x:=lParam AND $FFFF;
sPoint.y:=lParam SHR 16;
If PtInRect(sRectM,sPoint) Then
Begin
PostMessage(hDlg,WM_NCLBUTTONDOWN,2,0);
End;
End;
End;
End;
//程序運行時從這裡開始執行代碼;
begin
h_Inst:=GetModuleHandle(nil);
h_Brush:=CreateSolidBrush($1F1F1F);
h_Cur:=LoadCursor(h_Inst,MAKEINTRESOURCE(LINKCURSOR));
h_Icon:=LoadIcon(h_Inst,MAKEINTRESOURCE(MAINICON));
DialogBox(h_Inst,LPCTSTR(IDD_MAINDLG),0,@MainProc); //顯示主窗口
DeleteObject(h_Brush); // 刪除窗體
ExitProcess(0); //退出程序
end.