今天是列宁格勒保卫战中,伟大的“生命之路”开通的日子。纪念一下。
本以为About没有什么的,但分析下来才发现丝毫不亚于那个标题栏渐变。还好,
长长的路就要到尽头了……
================================================================================
下面就是最后的AboutProc。
0000:004045F0 DialogFunc proc near
0000:004045F0
0000:004045F0 Rect = tagRECT ptr -58h
0000:004045F0 Paint = PAINTSTRUCT ptr -48h
0000:004045F0 pt = POINT ptr -8
0000:004045F0 hWnd = dword ptr 8
0000:004045F0 arg_4 = dword ptr 0Ch
0000:004045F0 arg_8 = dword ptr 10h
0000:004045F0 arg_C = word ptr 14h
0000:004045F0
0000:004045F0 push ebp
0000:004045F1 mov ebp, esp
0000:004045F3 add esp, 0FFFFFFA8h
//100h-A8h=58h
0000:004045F6 push ebx
0000:004045F7 push esi
0000:004045F8 mov esi, [ebp+hWnd]
0000:004045FB xor ebx, ebx
0000:004045FD mov eax, [ebp+arg_4]
0000:00404600 cmp eax, 113h ; WM_TIMER
0000:00404605 jg short loc_404632
0000:00404607 jz loc_4047B8
0000:0040460D sub eax, 0Fh ; WM_PAINT
0000:00404610 jz loc_404867
0000:00404616 sub eax, 1Ch ; WM_DRAWITEM
0000:00404619 jz loc_4048D7
0000:0040461F sub eax, 0E5h ; WM_INITDIALOG
0000:00404624 jz short loc_404656
0000:00404626 dec eax ; WM_COMMAND
0000:00404627 jz loc_40489C
0000:0040462D jmp loc_404925
0000:00404632 loc_404632:
0000:00404632 sub eax, 136h ; WM_CTLCOLORDLG
0000:00404637 jz loc_4048E3
0000:0040463D sub eax, 2 ; WM_CTLCOLORSTATIC
0000:00404640 jz loc_404904
0000:00404646 sub eax, 0C9h ; WM_LBUTTONDOWN
0000:0040464B jz loc_404826
0000:00404651 jmp loc_404925
...
0000:00404925 loc_404925:
0000:00404925 xor ebx, ebx
0000:00404927 loc_404927:
0000:00404927 mov eax, ebx
0000:00404929 pop esi
0000:0040492A pop ebx
0000:0040492B mov esp, ebp
0000:0040492D pop ebp
0000:0040492E retn 10h
0000:0040492E DialogFunc endp
框架及大致相同处:
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
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(sRectA,sPoint) Then
Begin
PostMessage(hDlg,WM_NCLBUTTONDOWN,2,0);
End;
End;
WM_TIMER:
Begin
End;
End;
End;
下面是WM_INITDIALOG部分:
0000:00404656 loc_404656:
0000:00404656 push offset Rect ; lpRect
//注意,一共有3个Rect,分别对应3个Dlg。这里很容易混淆。
//我的做法是在IDA注释里加上地址。要么重命名也可。
0000:0040465B push esi ; hWnd
0000:0040465C call GetClientRect
0000:00404661 mov eax, ds:Rect.top
0000:00404666 add eax, 14h
0000:00404669 mov ds:Rect.bottom, eax
0000:0040466E push 0BBDh ; nIDDlgItem
0000:00404673 push esi ; hDlg
0000:00404674 call GetDlgItem
0000:00404679 mov ds:hWnd, eax
//滚动字幕框的HWND,因为Timer的callback要的。
0000:0040467E push 0BBBh ; nIDDlgItem
0000:00404683 push esi ; hDlg
0000:00404684 call GetDlgItem
0000:00404689 mov ebx, eax
0000:0040468B push offset nullsub_3 ; LPCSTR
//其实不仅是IDA,Sourcer也有这毛病
0000:00404690 push 0 ; DWORD
0000:00404692 push 0 ; DWORD
0000:00404694 push 0 ; DWORD
0000:00404696 push 0 ; DWORD
0000:00404698 push 1 ; DWORD
0000:0040469A push 0 ; DWORD
0000:0040469C push 0 ; DWORD
0000:0040469E push 0 ; DWORD
0000:004046A0 push 2BCh ; int
0000:004046A5 push 0 ; int
0000:004046A7 push 0 ; int
0000:004046A9 push 0 ; int
0000:004046AB push 0FFFFFFF4h ; int
0000:004046AD call CreateFontA
0000:004046B2 push 0 ; lParam
0000:004046B4 push eax ; wParam
0000:004046B5 push 30h ; Msg
0000:004046B7 push ebx ; hWnd
0000:004046B8 call SendMessageA
//设置字体了
0000:004046BD push offset dword_40493C ; lpString
0000:004046C2 push 0BBBh ; nIDDlgItem
0000:004046C7 push esi ; hDlg
0000:004046C8 call SetDlgItemTextA
0000:004046CD push offset dword_404954 ; lpString
0000:004046D2 push 0BBCh ; nIDDlgItem
0000:004046D7 push esi ; hDlg
0000:004046D8 call SetDlgItemTextA
0000:004046DD push offset dword_40496C ; lpString
0000:004046E2 push esi ; hWnd
0000:004046E3 call SetWindowTextA
0000:004046E8 lea eax, [ebp+Rect]
0000:004046EB push eax ; lpRect
0000:004046EC mov eax, ds:hWnd
0000:004046F1 push eax ; hWnd
0000:004046F2 call GetClientRect
//得到滚动字幕的Rect
0000:004046F7 mov ax, word ptr [ebp+Rect.right]
0000:004046FB sub ax, word ptr [ebp+Rect.left]
0000:004046FF mov ds:word_4060C8, ax
//宽
0000:00404705 mov ax, word ptr [ebp+Rect.bottom]
0000:00404709 sub ax, word ptr [ebp+Rect.top]
0000:0040470D mov ds:word_4060CC, ax
//高度
0000:00404713 mov ax, ds:word_4060CC
//这里的话,如果查看xref就知道,4060CC只在这里有赋值
0000:00404719 mov ds:word_4060C4, ax
//4060C4在其他地方有变化(dec),所以应该是类似计数器的作用
//请注意,有时xref在确定变量用途的时候很有用。
0000:0040471F mov eax, offset dword_40497C
//滚动字幕内容的地址
0000:00404724 call sub_403F94
0000:00404729 mov ds:word_4060D8, ax
//字符串里的换行数+1。注意这里的初始值为1。就是说,即使是空字符串,也
//应该在末尾加个换行。但是这里用了mov,联系到sub_403F94里有SEH,
//很容易想到在异常情况下,初始值起作用的。
0000:0040472F push 0 ; lpParam
0000:00404731 movsx eax, ds:word_4060CC
0000:00404738 push eax ; hInstance
0000:00404739 movsx eax, ds:word_4060C8
0000:00404740 push eax ; hMenu
0000:00404741 movsx eax, ds:word_4060D8
0000:00404748 shl eax, 2
0000:0040474B lea eax, [eax+eax*2]
0000:0040474E push eax ; hWndParent
0000:0040474F mov eax, ds:hWnd
0000:00404754 push eax ; nHeight
0000:00404755 push 0 ; nWidth
0000:00404757 mov eax, ds:hInstance
0000:0040475C push eax ; Y
0000:0040475D push 0 ; X
//留意一下,IDA已经第三次发飚了。而且这次跟前两次不一样。
//如果真按照注释对参数是要死人的!反正……push的参数顺序全部倒了……
0000:0040475F mov edx, offset dword_404A28 ; lpWindowName
0000:00404764 mov eax, offset dword_404A2C ; lpClassName
//象上面这样只有一个引用的lpstr就直接写字符串吧。
0000:00404769 mov ecx, 50000001h ; dwStyle
//这里的值是3个值的组合。由于该窗口是Static,所以那个1是SS_CENTER
0000:0040476E call sub_403C98
//调用CreateWindowEx
0000:00404773 mov ds:dword_4060D4, eax
0000:00404778 push offset sub_404484 ; dwNewLong
//专用的callback
0000:0040477D push 0FFFFFFFCh ; nIndex
0000:0040477F mov eax, ds:dword_4060D4
0000:00404784 push eax ; hWnd
0000:00404785 call SetWindowLongA
0000:0040478A push eax ; dwNewLong
0000:0040478B push 0FFFFFFEBh ; nIndex
0000:0040478D mov eax, ds:dword_4060D4
0000:00404792 push eax ; hWnd
0000:00404793 call SetWindowLongA
0000:00404798 mov eax, esi ; hWnd
0000:0040479A call sub_404358
//还好,是那个窗口特效……
0000:0040479F push 0 ; lpTimerFunc
0000:004047A1 push 3Ch ; uElapse
0000:004047A3 push 0A8h ; nIDEvent
0000:004047A8 push esi ; hWnd
0000:004047A9 call SetTimer
0000:004047AE mov ebx, 1
0000:004047B3 jmp loc_404927
sub_403F94实际是统计$0A数目的。
0000:00403F94 sub_403F94 proc near
0000:00403F94
0000:00403F94 var_4 = dword ptr -4
0000:00403F94
0000:00403F94 push ebp
0000:00403F95 mov ebp, esp
0000:00403F97 push ecx
0000:00403F98 push ebx
0000:00403F99 mov [ebp+var_4], eax
0000:00403F9C mov eax, [ebp+var_4]
//var_4里是地址
0000:00403F9F call @System@@LStrAddRef$qqrv ; System::__linkproc__ LStrAddRef(void)
//增加引用计数
0000:00403FA4 xor eax, eax
0000:00403FA6 push ebp
0000:00403FA7 push offset loc_403FEB
0000:00403FAC push dword ptr fs:[eax]
0000:00403FAF mov fs:[eax], esp
//设置SEH
0000:00403FB2 mov bx, 1
0000:00403FB6 mov eax, [ebp+var_4]
//仍然是地址
0000:00403FB9 call @System@_16823 ; System::_16823
//取字符串的净长度。通过查看dword_40497C附近的数据可以发现,
//dword_40497C前面的4个字节,内容是$A8。dword_40497C的最后部分,有一个
//dword的0,加上这个0,总长度是$AC。$AC-$A8=4,恰好是一个dword。
0000:00403FBE dec eax
0000:00403FBF test eax, eax
0000:00403FC1 jl short loc_403FD5
//判断空字符串
0000:00403FC3 inc eax
//加回来
0000:00403FC4 xor edx, edx
//此时bx=1,edx=0
0000:00403FC6
0000:00403FC6 loc_403FC6:
0000:00403FC6 mov ecx, [ebp+var_4]
//字符串的开头地址
0000:00403FC9 cmp byte ptr [ecx+edx-1], 0Ah
//应该是用edx做索引,但是开始时edx=0,ecx+edx-1=(Var_4)-1,这样
//就到了长度字节。
0000:00403FCE jnz short loc_403FD1
0000:00403FD0 inc ebx
0000:00403FD1
0000:00403FD1 loc_403FD1:
0000:00403FD1 inc edx
0000:00403FD2 dec eax
0000:00403FD3 jnz short loc_403FC6
0000:00403FD5
0000:00403FD5 loc_403FD5:
//ebx里应该是换行的数目+1
0000:00403FD5 xor eax, eax
0000:00403FD7 pop edx
0000:00403FD8 pop ecx
0000:00403FD9 pop ecx
0000:00403FDA mov fs:[eax], edx
//恢复SEH
0000:00403FDD push offset loc_403FF2
//实际和retn配套
//不得不说,虽然开始看到403FC6的循环就猜到这个是计算$0A的,但是因为是分析
//模板,开始时没想到里面居然会有push/ret这个变形的jmp。怀疑这个东西不是
//Delphi生成的。但是看403FE2又发现不像是手写的,真是!@#$
0000:00403FE2
0000:00403FE2 loc_403FE2:
0000:00403FE2 lea eax, [ebp+var_4]
0000:00403FE5 call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString &)
//这里没有改变eax,eax还是那个地址
//清除字符串?
0000:00403FEA retn
0000:00402EE8 @System@_16823 proc near
0000:00402EE8 test eax, eax
0000:00402EEA jz short locret_402EEF
0000:00402EEC mov eax, [eax-4]
0000:00402EEF
0000:00402EEF locret_402EEF:
0000:00402EEF retn
0000:00402EEF @System@_16823 endp
0000:00403FF2 loc_403FF2:
0000:00403FF2 mov eax, ebx
//返回值就是ebx
0000:00403FF4 pop ebx
0000:00403FF5 pop ecx
0000:00403FF6 pop ebp
0000:00403FF7 retn
0000:00403FF7 sub_403F94 endp
CreateWindowEx的外套:
0000:00403C98 sub_403C98 proc near
0000:00403C98
0000:00403C98 lpParam = dword ptr 8
0000:00403C98 hInstance = dword ptr 0Ch
0000:00403C98 hMenu = dword ptr 10h
0000:00403C98 hWndParent = dword ptr 14h
0000:00403C98 nHeight = dword ptr 18h
0000:00403C98 nWidth = dword ptr 1Ch
0000:00403C98 Y = dword ptr 20h
0000:00403C98 X = dword ptr 24h
0000:00403C98
0000:00403C98 push ebp
0000:00403C99 mov ebp, esp
0000:00403C9B push ebx
0000:00403C9C mov ebx, [ebp+lpParam]
0000:00403C9F push ebx ; lpParam
0000:00403CA0 mov ebx, [ebp+hInstance]
0000:00403CA3 push ebx ; hInstance
0000:00403CA4 mov ebx, [ebp+hMenu]
0000:00403CA7 push ebx ; hMenu
0000:00403CA8 mov ebx, [ebp+hWndParent]
0000:00403CAB push ebx ; hWndParent
0000:00403CAC mov ebx, [ebp+nHeight]
0000:00403CAF push ebx ; nHeight
0000:00403CB0 mov ebx, [ebp+nWidth]
0000:00403CB3 push ebx ; nWidth
0000:00403CB4 mov ebx, [ebp+Y]
0000:00403CB7 push ebx ; Y
0000:00403CB8 mov ebx, [ebp+X]
0000:00403CBB push ebx ; X
0000:00403CBC push ecx ; dwStyle
0000:00403CBD push edx ; lpWindowName
0000:00403CBE push eax ; lpClassName
0000:00403CBF push 0 ; dwExStyle
0000:00403CC1 call CreateWindowExA
0000:00403CC6 pop ebx
0000:00403CC7 pop ebp
0000:00403CC8 retn 20h
0000:00403CC8 sub_403C98 endp
滚动框的callback,有点眼熟:
0000:00404484 sub_404484 proc near
0000:00404484
0000:00404484 Rect = tagRECT ptr -50h
0000:00404484 Paint = PAINTSTRUCT ptr -40h
0000:00404484 hWnd = dword ptr 8
0000:00404484 arg_4 = dword ptr 0Ch
0000:00404484 wParam = dword ptr 10h
0000:00404484 lParam = dword ptr 14h
0000:00404484
0000:00404484 push ebp
0000:00404485 mov ebp, esp
0000:00404487 add esp, 0FFFFFFB0h
0000:0040448A push ebx
0000:0040448B push esi
0000:0040448C push edi
0000:0040448D mov esi, [ebp+arg_4]
0000:00404490 mov ebx, [ebp+hWnd]
0000:00404493 mov eax, esi
0000:00404495 sub eax, 0Fh
//如果还不能直接看出是WM_PAINT,那也就太逊了。好歹也到这里了……总该有点长
//进吧。
0000:00404498 jnz short loc_404515
//结合下面可以看到,是典型的if then else结构
//往下就是纯粹的API调用,实在没什么好说的。只是要注意寄存器变化。
0000:0040449A lea eax, [ebp+Paint]
0000:0040449D push eax ; lpPaint
0000:0040449E push ebx ; hWnd
0000:0040449F call BeginPaint
0000:004044A4 mov esi, eax
0000:004044A6 lea eax, [ebp+Rect]
0000:004044A9 push eax ; lpRect
0000:004044AA push ebx ; hWnd
0000:004044AB call GetClientRect
0000:004044B0 push 0A0A0A0h ; COLORREF
0000:004044B5 push esi ; HDC
0000:004044B6 call SetTextColor
0000:004044BB push 1 ; int
0000:004044BD push esi ; HDC
0000:004044BE call SetBkMode
0000:004044C3 push offset nullsub_2 ; LPCSTR
0000:004044C8 push 0 ; DWORD
0000:004044CA push 0 ; DWORD
0000:004044CC push 0 ; DWORD
0000:004044CE push 0 ; DWORD
0000:004044D0 push 1 ; DWORD
0000:004044D2 push 0 ; DWORD
0000:004044D4 push 0 ; DWORD
0000:004044D6 push 0 ; DWORD
0000:004044D8 push 0 ; int
0000:004044DA push 0 ; int
0000:004044DC push 0 ; int
0000:004044DE push 0 ; int
0000:004044E0 push 0FFFFFFF4h ; int
0000:004044E2 call CreateFontA
0000:004044E7 mov edi, eax
0000:004044E9 push edi ; HGDIOBJ
0000:004044EA push esi ; HDC
0000:004044EB call SelectObject
0000:004044F0 push 1 ; uFormat
0000:004044F2 lea eax, [ebp+Rect]
0000:004044F5 push eax ; lpRect
0000:004044F6 push 0FFFFFFFFh ; nCount
0000:004044F8 push offset dword_404544 ; lpString
0000:004044FD push esi ; hDC
0000:004044FE call DrawTextA
0000:00404503 lea eax, [ebp+Paint]
0000:00404506 push eax ; lpPaint
0000:00404507 push ebx ; hWnd
0000:00404508 call EndPaint
0000:0040450D push edi ; HGDIOBJ
0000:0040450E call DeleteObject
0000:00404513 jmp short loc_40452D
0000:00404515 loc_404515:
0000:00404515 push 0FFFFFFEBh ; nIndex
0000:00404517 push ebx ; hWnd
0000:00404518 call GetWindowLongA
0000:0040451D mov edx, [ebp+lParam]
0000:00404520 push edx ; lParam
0000:00404521 mov edx, [ebp+wParam]
0000:00404524 push edx ; wParam
0000:00404525 push esi ; Msg
0000:00404526 push ebx ; hWnd
0000:00404527 push eax ; lpPrevWndFunc
0000:00404528 call CallWindowProcA
0000:0040452D loc_40452D:
0000:0040452D mov eax, 1
0000:00404532 pop edi
0000:00404533 pop esi
0000:00404534 pop ebx
0000:00404535 mov esp, ebp
0000:00404537 pop ebp
0000:00404538 retn 10h
0000:00404538 sub_404484 endp
0000:004047B8 loc_4047B8:
0000:004047B8 push 14h ; dwMilliseconds
0000:004047BA call Sleep
0000:004047BF dec ds:word_4060C4
0000:004047C6 push 0 ; uFlags
0000:004047C8 movsx eax, ds:word_4060D8
0000:004047CF shl eax, 2
0000:004047D2 lea eax, [eax+eax*2]
0000:004047D5 push eax ; cy
0000:004047D6 movsx eax, ds:word_4060C8
0000:004047DD push eax ; cx
0000:004047DE movsx eax, ds:word_4060C4
0000:004047E5 push eax ; Y
0000:004047E6 push 0 ; X
0000:004047E8 push 0 ; hWndInsertAfter
0000:004047EA mov eax, ds:dword_4060D4
0000:004047EF push eax ; hWnd
0000:004047F0 call SetWindowPos
0000:004047F5 movsx eax, ds:word_4060C4
0000:004047FC movsx edx, ds:word_4060D8
0000:00404803 shl edx, 2
0000:00404806 lea edx, [edx+edx*2]
0000:00404809 add eax, edx
0000:0040480B neg eax
0000:0040480D test eax, eax
0000:0040480F jle loc_404927
0000:00404815 mov ax, ds:word_4060CC
0000:0040481B mov ds:word_4060C4, ax
0000:00404821 jmp loc_404927
看来About是这个程序的华彩乐章。滚动字幕是使用了创建子窗口,然后改变其
位置的方法。
下面就给出最后的几个部分:
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_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;
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;
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);
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;
这样,整个程序就分析完了。下面作一下总结。
从编程方面看,该程序有几处地方值得借鉴:1、按钮的三维边框;2、渐变标题
栏;3、滚动字幕的方法。
从逆向工程的角度看,难点主要在渐变标题栏和滚动字幕的处理上。主要是这两
个地方有较多的运算。
另外,在分析过程中,有几点是值得注意的:
1、注意区分全局变量和局部变量。局部变量一般用ebx引用。在分析滚动字幕时,
由于把一个全局变量当作局部变量,造成字幕无法重复滚动。不过,如果将该局部变
量用Const说明,还是可以达到目的的。
2、注意变量的类型和地址。这样就不会弄错变量。
3、API中的常量。这些常量一般可以在SDK中找到,但有些是组合值,比如
CreateWindowEx里使用的$50000001,这就需要仔细分析。
4、有符号数的处理。在本例中直接体现在渐变标题栏上。
5、不要迷信反汇编程序。
另外,你必须熟悉该程序使用的语言(尤其是内部结构,而不是仅仅会写几行程
序就可以的),这样才能够得心应手。但伪编译语言(VB、Java、.NET)除外。当然,
你还必须熟悉汇编语言。什么?不熟悉?临时学习?呃,算了吧。逆向工程只是手段
而不是目的,而且这对阁下来说也不好玩。倒是交谊舞对于阁下更实际点儿……阁下
35以上?那……当我什么都没说好了……
OK,这个笔记系列就基本结束了。但是有个缺憾:渐变标题栏没有作到原程序那
样的效果。也许以后我会分析出来的。不过现在只能说声抱歉了。
谢谢各位观赏,也谢谢各位的耐心。
PS:不要轻易决定做逆向工程,更不要轻易说你要做逆向工程并要写下心得以供分
享。但是如果你决定了,那么无论如何要完成它。特别是在第一篇心得贴出来以
后……想想那些网络上的“太监书”,再想想曹老先生的半部《红楼梦》……
===========================================================================
原以为About不会很复杂,没想到里面居然套了那么多东西。直接后果就是这篇文章
比以前贴的任何一篇都长,打开的速度肯定要慢点。不过你既然都看到这里了,就
别抱怨了,OK?
附:
关于Delphi逆向工程笔记系列的说明
事情的起因是我看到laoqian的一篇文章,他提到了FCG的KG模板,但是碍于FCG的规矩不能放出来,只是给了编译过的程序。但是我又比较喜欢收集这个。本来嘛,加入FCG就可以了,但是本人不会脱壳,破解又只能到明码比较的水平,估计没有哪个组织会要。很幸运,那个模板是Delphi的,而且laoqian只用upx加了壳,这样我才可以很方便地把它脱掉。不过他还是给我找了点小麻烦,破坏了upx头部的校验字节,拿upx就脱不掉了。
更幸运的是KG是用SDK写的(这也是惯例)……大家肯定都知道SDK程序编译出来是什么样子。也正是如此,我才可以做这个RE。如果是VCL的话,我也只有去找非明码比较的麻烦了。
做了半天,发现有些很有趣的东西。于是想拿出来。原以为这些东西肯定不太入眼,特别是对于在pediy混的人。但发现反响比较好,这是我始料不及的。
=================================================================