对[FCG]KeyGen2.0按钮特效的分析3、4、5
首先,废话几句。不知道有没有人还记得这个系列?在下因为个人原因,暂停了很久。不过最近在努力继续写。敬请期待……
另:如果您发现有错误/值得讨论的地方,请告诉我。
==========================================
sub_406A1F中一共使用了3个func:sub_406B69、sub_406B89、sub_406D7D。
首先看sub_406B69:
seg000:00406B69 sub_406B69 proc near ; CODE XREF: sub_406A1F+B
seg000:00406B69 ; sub_406AED+A ...
seg000:00406B69
seg000:00406B69 arg_0 = dword ptr 8
//从前面的分析知道这个arg是窗口的句柄
seg000:00406B69
seg000:00406B69 push ebp
seg000:00406B6A mov ebp, esp
seg000:00406B6C mov edx, [ebp+arg_0]
seg000:00406B6F mov eax, ds:dword_40A150
//即上文的WinPropLinkHead
seg000:00406B74 test eax, eax
seg000:00406B76 jz short loc_406B83
//为null
seg000:00406B78
seg000:00406B78 loc_406B78: ; CODE XREF: sub_406B69+18
seg000:00406B78 cmp edx, [eax]
//非空指针,将指针指向结构的CurrentWindow和参数比较
//其实就是寻找参数对应的窗口是否有相应的控制参数块
seg000:00406B7A jz short loc_406B85
//找到,直接返回指针,即eax
seg000:00406B7C mov eax, [eax+10h]
//取下一块的地址
seg000:00406B7F test eax, eax
//下一块的地址是否是null
seg000:00406B81 jnz short loc_406B78
//不是null则循环,否则表示已到链尾
seg000:00406B83
seg000:00406B83 loc_406B83: ; CODE XREF: sub_406B69+D
seg000:00406B83 xor eax, eax
//直接返回null
seg000:00406B85
seg000:00406B85 loc_406B85: ; CODE XREF: sub_406B69+11
seg000:00406B85 pop ebp
seg000:00406B86 retn 4
seg000:00406B86 sub_406B69 endp
这个函数很容易写出:
Function FindWindowInChain(Window:HWND):PWindowProperty; Begin Result:=WinPropLinkHead; While (Result<>Nil) Do Begin If Result^.CurrentWindow=Window Then Begin Break; End; Result:=Result^.NextWindowProperty; End; End;
sub_406B89:
seg000:00406B89 sub_406B89 proc near ; CODE XREF: sub_406A1F+19
seg000:00406B89
seg000:00406B89 ClassName = byte ptr -104h
seg000:00406B89 hWnd = dword ptr 8
seg000:00406B89
seg000:00406B89 push ebp
seg000:00406B8A mov ebp, esp
seg000:00406B8C add esp, 0FFFFFEFCh
//猜测是对齐
seg000:00406B92 push ebx
seg000:00406B93 push esi
//函数功能开始
seg000:00406B94 mov esi, [ebp+hWnd]
//参数
seg000:00406B97 push 104h ; nMaxCount
seg000:00406B9C lea eax, [ebp+ClassName]
seg000:00406BA2 push eax ; lpClassName
seg000:00406BA3 push esi ; hWnd
seg000:00406BA4 call GetClassNameA
seg000:00406BA9 xor ebx, ebx
seg000:00406BAB
seg000:00406BAB loc_406BAB: ; CODE XREF: sub_406B89+41
seg000:00406BAB mov eax, ebx
seg000:00406BAD shl eax, 5
//这里实际是乘以20,字符串数组的第1维大小
seg000:00406BB0 add eax, offset dword_40A154
//字符串数组的地址
seg000:00406BB5 push eax
seg000:00406BB6 lea edx, [ebp+ClassName]
seg000:00406BBC push edx
seg000:00406BBD call lstrcmpi
seg000:00406BC2 test eax, eax
seg000:00406BC4 jz short loc_406BCC
//该窗口的类名符合条件
seg000:00406BC6 inc ebx
seg000:00406BC7 cmp ebx, 2
seg000:00406BCA jb short loc_406BAB
//数组就2个元素
seg000:00406BCC
seg000:00406BCC loc_406BCC: ; CODE XREF: sub_406B89+3B
seg000:00406BCC sub ebx, 1
seg000:00406BCF jb short loc_406BD5
//是Button类
seg000:00406BD1 jz short loc_406BF2
//是Edit类
seg000:00406BD3 jmp short loc_406BF9
//都不是
seg000:00406BD5
seg000:00406BD5 loc_406BD5: ; CODE XREF: sub_406B89+46
seg000:00406BD5 push 0FFFFFFF0h
//GWL_STYLE
seg000:00406BD7 push esi
seg000:00406BD8 call GetWindowLongA_0
seg000:00406BDD mov ebx, eax
seg000:00406BDF and ebx, 1Fh
seg000:00406BE2 sub ebx, 2
seg000:00406BE5 jb short loc_406BE9
seg000:00406BE7 jmp short loc_406BED
seg000:00406BE9
seg000:00406BE9 loc_406BE9: ; CODE XREF: sub_406B89+5C
seg000:00406BE9 xor ebx, ebx
seg000:00406BEB jmp short loc_406BFC
seg000:00406BED
seg000:00406BED loc_406BED: ; CODE XREF: sub_406B89+5E
seg000:00406BED or ebx, 0FFFFFFFFh
seg000:00406BF0 jmp short loc_406BFC
seg000:00406BF2
seg000:00406BF2 loc_406BF2: ; CODE XREF: sub_406B89+48
seg000:00406BF2 mov ebx, 1
seg000:00406BF7 jmp short loc_406BFC
seg000:00406BF9
seg000:00406BF9 loc_406BF9: ; CODE XREF: sub_406B89+4A
seg000:00406BF9 or ebx, 0FFFFFFFFh
seg000:00406BFC
seg000:00406BFC loc_406BFC: ; CODE XREF: sub_406B89+62
seg000:00406BFC ; sub_406B89+67 ...
seg000:00406BFC mov eax, ebx
seg000:00406BFE pop esi
seg000:00406BFF pop ebx
seg000:00406C00 mov esp, ebp
seg000:00406C02 pop ebp
seg000:00406C03 retn 4
seg000:00406C03 sub_406B89 endp
这个函数比较麻烦。因为dword_40A154数组的元素是按照32个字节对齐的,而我在D5里无法写出对应的形式。当然,可以用Array of Char解决这个问题,但是这样一是比较麻烦,二是我得完全按照汇编来写而不能享受数组的方便快捷。所以我在这里不打算做直接的对照翻译。等价的形式会更快。
Const
Classes:Array[0..1] of PChar=('Button','Edit');
Function sub_406B89(Window:HWND):Integer;
Var
ClassName:PChar;
i:LongWord;
Begin
GetMem(ClassName,$104);
GetClassName(Window,ClassName,$104);
For i:=0 To 1 Do
Begin
If lstrcmpi(ClassName,Classes[i])=0 Then Break;
End;
Case i of
0:
Begin
If GetWindowLong(Window,GWL_STYLE) AND $1F<2 Then
Begin
Result:=0;
End
Else
Begin
Result:=-1;
End;
End;
1:
Result:=1;
Else
Result:=-1;
End;
End;
第4、5篇均在第一页
====================================
补充一下,00406BBD处的窗口类名比较时使用的类名实际是和程序有关的。在此例中,窗口由RC建立,所以类名为Button等……
