对[FCG]KeyGen2.0按钮特效的分析4
粗略看了一下sub_406D7D,发现其中有很多对程序里其它函数的调用。所以这部分延后分析。
sub_406D7D调用了以下函数:sub_406B69、sub_406974、sub_4070D9、sub_407274,其中sub_406B69已经分析。
seg000:00406974 sub_406974 proc near ; CODE XREF: sub_406D7D+53
seg000:00406974 ; sub_406D7D+80 ...
seg000:00406974
seg000:00406974 arg_4 = dword ptr 0Ch
seg000:00406974 arg_8 = dword ptr 10h
seg000:00406974
seg000:00406974 push ebp
seg000:00406975 mov ebp, esp
seg000:00406977 mov eax, [ebp+arg_4]
seg000:0040697A cmp [ebp+arg_8], 0
seg000:0040697E jnz short loc_406982
seg000:00406980 not eax
seg000:00406982
seg000:00406982 loc_406982: ; CODE XREF: sub_406974+A
seg000:00406982 pop ebp
seg000:00406983 retn
seg000:00406983 sub_406974 endp
逻辑非常简单:如果参数3为0则返回参数2的反值,否则直接返回参数2。从堆栈看,有参数1,只是被忽略了。
Function sub_406974(param1:LongWord;param2:LongWord;param3:LongWord)
Begin
If param3=0 Then
Result:=param2 XOR $FFFFFFFF
Else
Result:=param2;
End;
sub_4070D9调用了sub_406C06、sub_406F99、sub_406CA5三个函数。
seg000:00406C06 sub_406C06 proc near ; CODE XREF: sub_4070D9+25
seg000:00406C06
seg000:00406C06 Rect = tagRECT ptr -10h
seg000:00406C06 arg_0 = dword ptr 8
seg000:00406C06
seg000:00406C06 push ebp
seg000:00406C07 mov ebp, esp
seg000:00406C09 add esp, 0FFFFFFF0h
//分配临时变量
seg000:00406C0C push ebx
seg000:00406C0D mov ebx, [ebp+arg_0]
//ebx=arg0
seg000:00406C10 lea eax, [ebp+Rect]
seg000:00406C13 push eax ; lpRect
seg000:00406C14 push dword ptr [ebx] ; hWnd
//从这里可以看出,arg0实际是指针,指向的结构体开始部分为窗口句柄
seg000:00406C16 call GetWindowRect
seg000:00406C1B push dword ptr [ebx] ; hWnd
seg000:00406C1D call GetWindowDC
seg000:00406C22 mov [ebx+4], eax
//将对应的DC保存到结构体的[4]
seg000:00406C25 push dword ptr [ebx+4] ; HDC
seg000:00406C28 call CreateCompatibleDC
seg000:00406C2D mov [ebx+8], eax
//memdc
seg000:00406C30 push 1 ; int
seg000:00406C32 push dword ptr [ebx+8] ; HDC
seg000:00406C35 call SetBkMode
seg000:00406C3A cmp dword ptr [ebx+10h], 0
//如果结构体的[10h]是0
seg000:00406C3E jz short loc_406C4D
//非0就直接选择对象
seg000:00406C40 push dword ptr [ebx+10h] ; HGDIOBJ
seg000:00406C43 push dword ptr [ebx+8] ; HDC
seg000:00406C46 call SelectObject
seg000:00406C4B jmp short loc_406C6F
seg000:00406C4D
seg000:00406C4D loc_406C4D: ; CODE XREF: sub_406C06+38
seg000:00406C4D mov edx, [ebp+Rect.bottom]
seg000:00406C50 sub edx, [ebp+Rect.top]
seg000:00406C53 push edx ; int
seg000:00406C54 mov ecx, [ebp+Rect.right]
seg000:00406C57 sub ecx, [ebp+Rect.left]
seg000:00406C5A push ecx ; int
seg000:00406C5B push dword ptr [ebx+4] ; HDC
seg000:00406C5E call CreateCompatibleBitmap
seg000:00406C63 push eax ; HGDIOBJ
seg000:00406C64 push dword ptr [ebx+8] ; HDC
seg000:00406C67 call SelectObject
seg000:00406C6C mov [ebx+10h], eax
//看来[10h]是bitmap的句柄
seg000:00406C6F
seg000:00406C6F loc_406C6F: ; CODE XREF: sub_406C06+45
seg000:00406C6F cmp dword ptr [ebx+0Ch], 1
seg000:00406C73 jnz short loc_406C9B
//[0ch]是什么,从下文看不出
seg000:00406C75 push 0CC0020h ; DWORD
//SRCCOPY
seg000:00406C7A push 0 ; int
seg000:00406C7C push 0 ; int
seg000:00406C7E push dword ptr [ebx+4] ; HDC
seg000:00406C81 mov eax, [ebp+Rect.bottom]
seg000:00406C84 sub eax, [ebp+Rect.top]
seg000:00406C87 push eax ; int
seg000:00406C88 mov edx, [ebp+Rect.right]
seg000:00406C8B sub edx, [ebp+Rect.left]
seg000:00406C8E push edx ; int
seg000:00406C8F push 0 ; int
seg000:00406C91 push 0 ; int
seg000:00406C93 push dword ptr [ebx+8] ; HDC
seg000:00406C96 call BitBlt
//保存原始DC?
seg000:00406C9B
seg000:00406C9B loc_406C9B: ; CODE XREF: sub_406C06+6D
seg000:00406C9B mov eax, [ebx+8]
//返回MEM DC的句柄
seg000:00406C9E pop ebx
seg000:00406C9F mov esp, ebp
seg000:00406CA1 pop ebp
seg000:00406CA2 retn 4
seg000:00406CA2 sub_406C06 endp
Type
WindowsDCInfo=Record
hWindow:HWND;
WinDC:HDC;
CompDC:HDC;
unknown:LongWord;
hBitmap:HBITMAP;
End;
PWindowsDCInfo=^WindowsDCInfo;
Function sub_406C06(Var DCInfo:WindowsDCInfo):HDC;
Var
Rect:TRect;
Begin
GetWindowRect(DCInfo.hWindow,Rect);
DCInfo.WinDC:=GetWindowDC(DCInfo.hWindow);
DCInfo.CompDC:=CreateCompatibleDC(DCInfo.WinDC);
SetBkMode(DCInfo.CompDC,TRANSPARENT);
If DCInfo.hBitmap<>0 Then
Begin
SelectObject(DCInfo.CompDC,DCInfo.hBitmap);
End
Else
Begin
DCInfo.hBitmap:=CreateCompatibleBitmap(DCInfo.WinDC,Rect.right-Rect.left,Rect.bottom-Rect.top);
SelectObject(DCInfo.CompDC,DCInfo.hBitmap);
End;
If DCInfo.unknown=1 Then
Begin
BitBlt(DCInfo.CompDC,0,0,Rect.right-Rect.left,Rect.bottom-Rect.top,DCInfo.WinDC,0,0,SRCCOPY);
End;
Result:=DCInfo.CompDC;
End;
显然,某些东西依然未知。
看起来,sub_406F99就是生成渐变的核心过程。各位打起精神来! 首先,从GradientFill的两个call得到,var_48处是一个Arrayp[0..3] of TRIVERTEX的结构数组。var_54和var_8分别是GRADIENT_TRIANGLE和GRADIENT_RECT。但d5里对于TRIVERTEX的定义似乎有问题:COLOR16是8位而不是16位。最好的办法是自己重新写定义。
seg000:00406F99 ; int __stdcall sub_406F99(HDC,int,int)
seg000:00406F99 sub_406F99 proc near ; CODE XREF: sub_4070D9+DC
seg000:00406F99 ; sub_4070D9+F0
seg000:00406F99
seg000:00406F99 var_54 = dword ptr -54h
seg000:00406F99 var_50 = dword ptr -50h
seg000:00406F99 var_4C = dword ptr -4Ch
seg000:00406F99 var_48 = dword ptr -48h
seg000:00406F99 var_8 = dword ptr -8
seg000:00406F99 var_4 = dword ptr -4
seg000:00406F99 arg_0 = dword ptr 8
seg000:00406F99 arg_4 = dword ptr 0Ch
seg000:00406F99 arg_8 = dword ptr 10h
seg000:00406F99
seg000:00406F99 push ebp
seg000:00406F9A mov ebp, esp
seg000:00406F9C add esp, 0FFFFFFACh
//分配局部堆栈变量
seg000:00406F9F push ebx
seg000:00406FA0 push esi
seg000:00406FA1 push edi
seg000:00406FA2 mov eax, [ebp+arg_8]
//eax=arg_8
seg000:00406FA5 mov edx, [ebp+arg_4]
//edx=arg_4
seg000:00406FA8 lea esi, [ebp+var_48]
seg000:00406FAB xor ebx, ebx
//ebx=0
seg000:00406FAD
seg000:00406FAD loc_406FAD: ; CODE XREF: sub_406F99+70
seg000:00406FAD xor ecx, ecx
seg000:00406FAF mov cl, [eax+ebx*4]
//arg_8应该是指针
seg000:00406FB2 shl ecx, 8
//ecx=((eax+ebx*4)^) shl 8
seg000:00406FB5 mov edi, ebx
seg000:00406FB7 shl edi, 4
seg000:00406FBA mov [esi+edi+8], cx
//注意:TRIVERTEX长度为10h=4h shl 4,所以这里应该写成
//var_48[ebx].Red=ecx and $FFFF
seg000:00406FBF movzx ecx, word ptr [eax+ebx*4]
seg000:00406FC3 sar ecx, 8
seg000:00406FC6 and ecx, 0FFh
seg000:00406FCC shl ecx, 8
//ecx=(((arg_8+ebx*4)^ sar 8)and $ff) shl 8
seg000:00406FCF mov edi, ebx
seg000:00406FD1 shl edi, 4
seg000:00406FD4 mov [esi+edi+0Ah], cx
//var_48[ebx].Green=ecx and $FFFF
seg000:00406FD9 mov ecx, [eax+ebx*4]
seg000:00406FDC shr ecx, 10h
seg000:00406FDF and ecx, 0FFh
seg000:00406FE5 shl ecx, 8
seg000:00406FE8 mov edi, ebx
seg000:00406FEA shl edi, 4
seg000:00406FED mov [esi+edi+0Ch], cx
//var_48[ebx].Blue=(((arg_8+ebx*4)^ shr $10)and $ff) shl 8
seg000:00406FF2 mov ecx, [eax+ebx*4]
seg000:00406FF5 shr ecx, 18h
seg000:00406FF8 shl ecx, 8
seg000:00406FFB mov edi, ebx
seg000:00406FFD shl edi, 4
seg000:00407000 mov [esi+edi+0Eh], cx
//var_48[ebx].Alpha=(((arg_8^+ebx*4) shr $18) shl 8) and $ffff
seg000:00407005 inc ebx
seg000:00407006 cmp ebx, 4
seg000:00407009 jl short loc_406FAD
//loc_406FAD到此为一个循环
//for ebx:=0 to 3 do ....
//综合一下,arg_8的结构应该是Array[0..3] of DWORD,元素的结构为TColorRef,但是最高8位为Alpha值
seg000:0040700B mov ecx, [edx]
seg000:0040700D mov [esi], ecx
//看来arg_4也是指针
//var48[0].x=arg_4^
seg000:0040700F mov ecx, [edx+4]
seg000:00407012 mov [esi+4], ecx
//var48[0].y=arg_4^[4]
seg000:00407015 mov ecx, [edx+8]
seg000:00407018 lea ebx, [esi+10h]
seg000:0040701B mov [ebx], ecx
//var48[1].x=arg_4^[8]
seg000:0040701D mov ecx, [edx+4]
seg000:00407020 lea ebx, [esi+10h]
seg000:00407023 mov [ebx+4], ecx
//var48[1].y=arg_4^[4]
seg000:00407026 mov ecx, [edx]
seg000:00407028 lea ebx, [esi+20h]
seg000:0040702B mov [ebx], ecx
//var48[2].x=arg_4^
seg000:0040702D mov ecx, [edx+0Ch]
seg000:00407030 lea ebx, [esi+20h]
seg000:00407033 mov [ebx+4], ecx
//var48[2].y=arg_4^[$c]
seg000:00407036 mov ecx, [edx+8]
seg000:00407039 lea ebx, [esi+30h]
seg000:0040703C mov [ebx], ecx
//var48[3].x=arg_4^[$8]
seg000:0040703E mov edx, [edx+0Ch]
seg000:00407041 lea ecx, [esi+30h]
seg000:00407044 mov [ecx+4], edx
//var48[3].y=arg_4^[$c]
//看来arg_4指向的应该是rect结构
seg000:00407047 mov edx, [eax]
seg000:00407049 cmp edx, [eax+8]
seg000:0040704C jnz short loc_407054
//if arg_8^<>arg_8^[8] then goto loc_407054
seg000:0040704E mov ecx, [eax+4]
seg000:00407051 cmp ecx, [eax+0Ch]
//无实际用途?
seg000:00407054
seg000:00407054 loc_407054: ; CODE XREF: sub_406F99+B3
seg000:00407054 mov edx, [eax]
seg000:00407056 cmp edx, [eax+4]
seg000:00407059 jnz short loc_40706A
//if arg_8^<>arg_8^[4] then goto loc_40706A
seg000:0040705B mov ecx, [eax+8]
seg000:0040705E cmp ecx, [eax+0Ch]
seg000:00407061 jnz short loc_40706A
//if arg_8^[8]<>arg_8^[$c] then goto loc_40706A
seg000:00407063 mov ebx, 1
//ebx=GRADIENT_FILL_RECT_V
seg000:00407068 jmp short loc_40706F
seg000:0040706A
seg000:0040706A loc_40706A: ; CODE XREF: sub_406F99+C0
seg000:0040706A ; sub_406F99+C8
seg000:0040706A mov ebx, 2
//ebx=GRADIENT_FILL_TRIANGLE
seg000:0040706F
seg000:0040706F loc_40706F: ; CODE XREF: sub_406F99+CF
seg000:0040706F cmp ebx, 2
seg000:00407072 jnz short loc_407089
//if ebx<>GRADIENT_FILL_TRIANGLE then goto loc_407089
seg000:00407074 xor eax, eax
seg000:00407076 mov [ebp+var_54], eax
seg000:00407079 mov [ebp+var_50], 1
seg000:00407080 mov [ebp+var_4C], 2
//var_54.Vertex1=0
//var_54.Vertex2=1
//var_54.Vertex3=2
seg000:00407087 jmp short loc_407095
seg000:00407089
seg000:00407089 loc_407089: ; CODE XREF: sub_406F99+D9
seg000:00407089 xor edx, edx
seg000:0040708B mov [ebp+var_8], edx
seg000:0040708E mov [ebp+var_4], 3
//var_8.UpperLeft=0
//var_8.LowerRight=3
seg000:00407095
seg000:00407095 loc_407095: ; CODE XREF: sub_406F99+EE
seg000:00407095 push ebx ; ULONG
seg000:00407096 push 1 ; ULONG
seg000:00407098 cmp ebx, 2
seg000:0040709B jnz short loc_4070A2
seg000:0040709D lea ecx, [ebp+var_54]
seg000:004070A0 jmp short loc_4070A5
seg000:004070A2
seg000:004070A2 loc_4070A2: ; CODE XREF: sub_406F99+102
seg000:004070A2 lea ecx, [ebp+var_8]
seg000:004070A5
seg000:004070A5 loc_4070A5: ; CODE XREF: sub_406F99+107
seg000:004070A5 push ecx ; PVOID
seg000:004070A6 push 4 ; ULONG
seg000:004070A8 push esi ; PTRIVERTEX
seg000:004070A9 push [ebp+arg_0] ; HDC
seg000:004070AC call GradientFill
//注意0040709B的判断
seg000:004070B1 cmp ebx, 2
seg000:004070B4 jnz short loc_4070D0
//如果ebx=GRADIENT_FILL_TRIANGLE,那么继续
seg000:004070B6 mov [ebp+var_54], 3
//var_54.Vertex1=3
seg000:004070BD push 2 ; ULONG
//GRADIENT_FILL_TRIANGLE
seg000:004070BF push 1 ; ULONG
seg000:004070C1 lea eax, [ebp+var_54]
seg000:004070C4 push eax ; PVOID
seg000:004070C5 push 4 ; ULONG
seg000:004070C7 push esi ; PTRIVERTEX
seg000:004070C8 push [ebp+arg_0] ; HDC
seg000:004070CB call GradientFill
seg000:004070D0
seg000:004070D0 loc_4070D0: ; CODE XREF: sub_406F99+11B
seg000:004070D0 pop edi
seg000:004070D1 pop esi
seg000:004070D2 pop ebx
seg000:004070D3 mov esp, ebp
seg000:004070D5 pop ebp
seg000:004070D6 retn 0Ch
seg000:004070D6 sub_406F99 endp
从调用代码看,这段代码没有返回值。下面的代码做了一点整理。
Type
COLOR16 = Word;
PTriVertex = ^TTriVertex;
_TRIVERTEX = Packed Record
x: Longint;
y: Longint;
Red: COLOR16;
Green: COLOR16;
Blue: COLOR16;
Alpha: COLOR16;
End;
TTriVertex = _TRIVERTEX;
TRIVERTEX = _TRIVERTEX;
AlphaRGB=Packed Record
Case Byte Of
1:(
Alpha:Byte;
Blue:Byte;
Green:Byte;
Red:Byte);
2:(
ARGB:LongWord);
End;
Procedure DoGradientFill(WinDC:HDC;DCRect:PRect;AlphaRGBArray:Array[0..3] of AlphaRGB);
Var
GT:GRADIENT_TRIANGLE;
TVs:Array[0..3] of TRIVERTEX;
GR:GRADIENT_RECT;
i:LongWord;
Begin
For i:=0 To 3 Do
Begin
TVs[i].Red:=AlphaRGBArray[i].Red;
TVs[i].Green:=AlphaRGBArray[i].Green;
TVs[i].Blue:=AlphaRGBArray[i].Blue;
TVs[i].Alpha:=AlphaRGBArray[i].Alpha;
End;
TVs[0].x:=DCRect^.Left;
TVs[0].y:=DCRect^.Top;
TVs[1].x:=DCRect^.Right;
TVs[1].y:=DCRect^.Top;
TVs[2].x:=DCRect^.Left;
TVs[2].y:=DCRect^.Bottom;
TVs[3].x:=DCRect^.Right;
TVs[3].y:=DCRect^.Bottom;
If (DCRect^.Left=DCRect^.Top) AND (DCRect^.Right=DCRect^.Bottom) Then
Begin
GR.UpperLeft:=0;
GR.LowerRight:=3;
GradientFill(WinDC,@TVs,4,@GR,1,GRADIENT_FILL_RECT_V);
End
Else
Begin
GT.Vertex1:=0;
GT.Vertex2:=1;
GT.Vertex3:=2;
GradientFill(WinDC,@TVs,4,@GT,1,GRADIENT_FILL_TRIANGLE);
GT.Vertex1:=3;
GradientFill(WinDC,@TVs,4,@GT,1,GRADIENT_FILL_TRIANGLE);
End;
End;
小结:保持清醒的头脑是非常重要的。我曾经算错mov的地址,后来从头看才发现错误所在。
OK,休息。