• 标 题:打造透明的输入法状态条 (7千字)
  • 作 者:jr21066
  • 时 间:2003-06-25 13:58:19
  • 链 接:http://bbs.pediy.com


我酷,我透明-打造透明的输入法状态条

完成时间:2003年6月25日
发信人:JR21066[BCG][DFCG]
所用工具:SPY Window、OllyDbg、UltraEdit


    本人所钟爱的输入法就是龙文(当然不是做广告了,别的输入法我想用这个方法一样可以改造的)。这个软件的特点就是功能多,界面差。原来曾给作者建议把汉字输入时的状态条设为半透明,这样会美观很多,作者也说实现不难,但等了很长时间也没等到,只好自己改造一下了(可能是心血来潮吧)。
    此篇文章的顺利完成,特别要感谢软件调试论坛的"4444444",尤其是"某人说"的热心帮助,让我改造了数据的重定位问题,同时也多学了一招。

    首先,也是很重要的一点,透明显示是Windows 2000及Windows XP所支持的功能,98下就不要试了。不是多余,是多鱼。
    运行SPY Window,这个软件可以侦测到窗口的各种信息。切换输入法使状态条窗口显示出现。这时捕获状态条窗口后窗口类别分别为“lwtImeCompwinime”及“lwtImeCandwinime”,一会就要改它了。另外看到状态条窗口的扩展风格为零,心中窃喜,这样一会设置风格时可以不用读取原有风格,省了不少代码:)
    用UltraEdit打开lwsrf.ime文件,也就是你的输入法程序。在偏移45fdc处修改为“user32”,在偏移45fe4处修改为“SetLayeredWindowAttributes”,一会要用。

    下来正式开始,用OllyDbg加载一个程序,我选的是记事本文件,运行程序后。在OllyDbg中打开模块窗口,就是工具条上那个大写的“E”。寻找你的输入法,我这里是龙文,名字就是“Lwsrf.ime”,选它进入,下断点“SetWindowLongA”。为什么选这个断点呢?因为这个API就是设置窗口属性的,如果在这里修改的话,起码窗口句柄之类会很容易得到的。这时随便打一个字了,要不打个K吧。我就是用的它:)。状态条窗口马上就要显示了。哈,程序分别中断在两个地址上,旁边也显示出窗口的类别了。正是前边用SPY Window找到的那两个类别“lwtImeCompwinime”及“lwtImeCandwinime”。

    话说当时我试呀试,重来,试呀试。其中还有上论坛求助了,过程较长。汗!略过不提。

    这下来真格的,管饱:)
;------------------------------------------------------------
;lwtImeCandwinime窗口的创建及风格设置处
* Reference To: USER32.CreateWindowExA, Ord:0059h
:10001473 FF151C630410            Call dword ptr [1004631C]
* Reference To: USER32.SetWindowLongA, Ord:0258h
:10001479 8B1D20630410            mov ebxdword ptr [10046320]
;这里就是窗口风格设置的地方,我们从这里直接调用改造后的风格设置模块
:1000147F 6AFF                    push FFFFFFFF
:10001481 6A00                    push 00000000
:10001483 50                      push eax
:10001484 894608                  mov dword ptr [esi+08], eax
:10001487 FFD3                    call ebx

;修改后的结果
;原程序的数据,EAX是上边CreateWindowExA所返回的窗口句柄
1000147F    8946 08         MOV DWORD PTR DS:[ESI+8],EAX 
;不是我多余,只是觉得多两个字节,总觉得nop不如这个好看,所以加了压栈操作
10001482    60              PUSHAD 
;10045ED0是在程序最后找到的一点小空地,自留地?小是小点。不过够用了。
10001483    E8 484A0400     CALL lwsrf.10045ED0 ;调用自己的过程
10001488    61              POPAD ;跟上边配对用的.



;----------------------------------------------------------------
;lwtImeCompwinime窗口的创建及风格设置处
* Reference To: USER32.CreateWindowExA, Ord:0059h
:1000AAED FF151C630410            Call dword ptr [1004631C]
* Reference To: USER32.SetWindowLongA, Ord:0258h
:1000AAF3 8B2D20630410            mov ebpdword ptr [10046320]
:1000AAF9 6AFF                    push FFFFFFFF
:1000AAFB 6A00                    push 00000000
:1000AAFD 50                      push eax
:1000AAFE 8906                    mov dword ptr [esi], eax
:1000AB00 FFD5                    call ebp

;修改后的结果,作用同上边
1000AAF9    8906            MOV DWORD PTR DS:[ESI],EAX
1000AAFB    60              PUSHAD
1000AAFC    E8 CFB30300     CALL lwsrf.10045ED0
1000AB01    61              POPAD




;--------------------------------------------------------------------
;这里是我在自留地里种的一点小菜,为了好读没有优化

10045ED0    8BF8            MOV EDI,EAX ;保存窗口句柄到edi
;弹出程序返回地址来获取程序的基地址,主要是重定位问题了.以后就要用它的
10045ED2    5E              POP ESI 
10045ED3    56              PUSH ESI
10045ED4    81E6 0000FFFF   AND ESI,FFFF0000 ;去掉地址的偏移部分
;原程序的调用,照搬了
10045EDA    6A FF           PUSH -1
10045EDC    6A 00           PUSH 0
10045EDE    57              PUSH EDI
;这里的偏移[ESI+46320]是在OllyDbg中按Ctrl+N,找的API的地址表值.比如这里用的是SetWindowLongA,它的值为10046320,减去基地址1000000就是下边的值了.然后再加上刚才算出的基地址ESI得到当前程序的地址.
10045EDF    FF96 20630400   CALL NEAR DWORD PTR DS:[ESI+46320]
;GetVersion,如果系统不支持透明处理,返回
10045EE5    FF96 14620400   CALL NEAR DWORD PTR DS:[ESI+46214]
10045EEB    3C 04           CMP AL,4
10045EED    77 01           JA SHORT lwsrf.10045EF0
10045EEF    C3              RETN
;设置窗口的扩展风格
10045EF0    68 00000800     PUSH 80000                                ASCII "Actx "
10045EF5    6A EC           PUSH -14 ;透明风格
10045EF7    57              PUSH EDI
;SetWindowLongA
10045EF8    FF96 20630400   CALL NEAR DWORD PTR DS:[ESI+46320]
;压栈"user32"字符串
10045EFE    8BC6            MOV EAX,ESI
10045F00    05 DC5F0400     ADD EAX,45FDC
10045F05    50              PUSH EAX
;调用GetModuleHandleA,获取user32.dll的句柄
10045F06    FF96 40610400   CALL NEAR DWORD PTR DS:[ESI+46140]
;压栈"SetLayeredWindowAttributes"
10045F0C    8BD6            MOV EDX,ESI
10045F0E    81C2 E45F0400   ADD EDX,45FE4
10045F14    52              PUSH EDX
10045F15    50              PUSH EAX
;调用GetProcAddress,获取SetLayeredWindowAttributes函数的地址
10045F16    FF96 D8610400   CALL NEAR DWORD PTR DS:[ESI+461D8]
;调用SetLayeredWindowAttributes来设置透明窗口
10045F1C    6A 02           PUSH 2 ;透明,为1时是指定颜色透明
10045F1E    68 C0000000     PUSH 0C0 ;窗口的透明值
10045F23    6A 00           PUSH 0 ;第一项为1时,透明的颜色值
10045F25    57              PUSH EDI ;窗口句柄
;调用SetLayeredWindowAttributes
10045F26    FFD0            CALL NEAR EAX 
10045F28    C3              RETN



上边用到的"user32"、"SetLayeredWindowAttributes"字符串是为了给GetModuleHandleA及GetProcAddress送参数用的。为什么放在代码段里,是因为代码段在程序执行后是不会改变的,如果放在数据段有可能会被程序被覆盖。偏移地址是自己找的。只要有地方都可以放的。



;------------------------------------------------------------------------
下边把要用到的API列一下
SetWindowLongA

    函数功能:该函数改变指定窗口的属性.函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。

    函数原型:LONG SetWindowLong(HWND hWnd,int nlndex,LONG dwNewLong);
    参数:

    hWnd:窗口句柄及间接给出的窗口所属的类。

    nlndex:指定将设定的大于等于0的偏移值。有效值的范围从0到额外类的存储空间的字节数-4:例如若指定了12位或多于12位的额外类存储空间,则应设为第三个32位整数的索引位8。要设置其他任何值,可以指定下面值之一:

    GWL_EXISTYLE:设定一个新的扩展风格。GWL_STYLE:设定一个新的窗口风格。

    GWL_WNDPROC:为窗口过程设定一个新的地址。GWL_ID:设置一个新的窗口标识符。

    GWL_HINSTANCE:设置一个新的应用程序事例句柄。

    GWL_USERDATA:设置与窗口有关的32位值。每一个窗口均有一个由创建该窗口的应用程序使用的32位值。

    当hWnd参数标识了一个对话框时,也可使用下列值:

    DWL_DLGPROC:设置对话框过程的新地址。

    DWL_MSGRESULT:设置在对话框过程中处理的消息的返回值。

    DWL_USER:设置的应用程序私有的新的额外信息,例如一个句柄或指针。

    dwNewLong:指定的替换值。

    返回值:如果函数成功,返回值是指定的32位整数的原来的值。如果函数失败,返回值为0。若想获得更多错误信息,请调用GetLastError函数。


SetLayeredWindowAttributes

SetLayeredWindowAttributes函数,其中hwnd是透明窗体的句柄,crKey为颜色值,bAlpha是透明度,取值范围是[0,255],dwFlags是透明方式,可以取两个值:当取值为LWA_ALPHA时,crKey参数无效,bAlpha参数有效;当取值为LWA_COLORKEY时,bAlpha参数有效而窗体中的所有颜色为crKey的地方将变为透明。

    Const LWA_COLORKEY = &H1

    Const LWA_ALPHA = &H2

    Const GWL_EXSTYLE = (-20)

    Const WS_EX_LAYERED = &H80000
=================================================================================================================