解决vb6和delphi7在win10下输入中文乱码问题
本帖最后由 苏紫方璇 于 2021-8-30 22:35 编辑最近遇到一个问题,在win10下,部分vb6或者delphi7写的使用A函数控件的程序,TextBox输入中文总是乱码,而复制粘贴则正常。
在网上查找发现,目前通用的办法是删除美式键盘即可解决。
测试一下确实如此,但是,删除后会改变切换输入法的习惯,为了极个别老古董程序改习惯还是不太舒服的。于是就大致看了一下问题所在。
在网上搜索发现,输入法最后会发送一个WM_IME_CHAR的消息,其中包含了输入的文本。
既然是多字节的A类控件,断SendMessageA即可在输入汉字后触发断点。
程序断在user32中,向上查找发现部分流程。
代码如下
76801D16 .33C0 xor eax,eax
76801D18 .50 push eax
76801D19 .50 push eax
76801D1A .68 00080000 push 0x800
76801D1F .51 push ecx
76801D20 .3945 14 cmp dword ptr ss:,eax
76801D23 .0F84 DE000000 je user32.76801E07
76801D29 .8B35 F4128576 mov esi,dword ptr ds: ;imm32.ImmGetCompositionStringA
76801D2F .8BCE mov ecx,esi
76801D31 .FF15 4C408576 call dword ptr ds: ;user32.767EEEA0
76801D37 .FFD6 call esi
76801D39 .8BF0 mov esi,eax
76801D3B .85F6 test esi,esi
76801D3D .0F84 64010000 je user32.76801EA7
76801D43 .8D4E 01 lea ecx,dword ptr ds:
76801D46 .51 push ecx ; /dwBytes = 0x0
76801D47 .6A 08 push 0x8 ; |dwFlags = HEAP_ZERO_MEMORY
76801D49 .FF35 F0198576 push dword ptr ds: ; |hHeap = 00430000
76801D4F .FF15 60378576 call dword ptr ds:[<&ntdll.RtlAllocateHe>; \RtlAllocateHeap
76801D55 .894424 1C mov dword ptr ss:,eax
76801D59 .85C0 test eax,eax
76801D5B .0F84 46010000 je user32.76801EA7
76801D61 .56 push esi
76801D62 .8B35 F4128576 mov esi,dword ptr ds: ;imm32.ImmGetCompositionStringA
76801D68 .8BCE mov ecx,esi
76801D6A .50 push eax
76801D6B .68 00080000 push 0x800
76801D70 .FF7424 30 push dword ptr ss:
76801D74 .FF15 4C408576 call dword ptr ds: ;user32.767EEEA0
76801D7A .FFD6 call esi
76801D7C .8B4424 1C mov eax,dword ptr ss:
76801D80 .8A08 mov cl,byte ptr ds:
76801D82 .84C9 test cl,cl
76801D84 .0F84 0A010000 je user32.76801E94
76801D8A .8B7C24 14 mov edi,dword ptr ss:
76801D8E .33F6 xor esi,esi
76801D90 .46 inc esi
76801D91 .8BD8 mov ebx,eax
76801D93 >64:A1 1800000>mov eax,dword ptr fs:
76801D99 .8B90 DC0F0000 mov edx,dword ptr ds:
76801D9F .85D2 test edx,edx
76801DA1 .79 02 jns short user32.76801DA5
76801DA3 .03C2 add eax,edx
76801DA5 >0FB780 980800>movzx eax,word ptr ds:
76801DAC .8D53 01 lea edx,dword ptr ds:
76801DAF .51 push ecx
76801DB0 .50 push eax
76801DB1 .895424 30 mov dword ptr ss:,edx
76801DB5 .FF15 78338576 call dword ptr ds:[<&api-ms-win-core-loc>;KernelBa.IsDBCSLeadByteEx
76801DBB .85C0 test eax,eax
76801DBD .74 29 je short user32.76801DE8
76801DBF .8B4424 28 mov eax,dword ptr ss:
76801DC3 .8A00 mov al,byte ptr ds:
76801DC5 .84C0 test al,al
76801DC7 .74 1C je short user32.76801DE5
76801DC9 .0FB60B movzx ecx,byte ptr ds:
76801DCC .56 push esi ; /lParam = 0x2BF1E94
76801DCD .C1E1 08 shl ecx,0x8 ; |
76801DD0 .0FB6C0 movzx eax,al ; |
76801DD3 .0BC8 or ecx,eax ; |
76801DD5 .51 push ecx ; |wParam = 0x0
76801DD6 .68 86020000 push 0x286 ; |Message = WM_IME_CHAR
76801DDB .57 push edi ; |hWnd = 0x767CDDB0
76801DDC .E8 DF02FDFF call user32.SendMessageA ; \SendMessageA
76801DE1 .8B5C24 28 mov ebx,dword ptr ss:
76801DE5 >43 inc ebx
76801DE6 .EB 14 jmp short user32.76801DFC
76801DE8 >0FB603 movzx eax,byte ptr ds:
76801DEB .56 push esi ; /lParam = 0x2BF1E94
76801DEC .50 push eax ; |wParam = 0x0
76801DED .68 86020000 push 0x286 ; |Message = WM_IME_CHAR
76801DF2 .57 push edi ; |hWnd = 0x767CDDB0
76801DF3 .E8 C802FDFF call user32.SendMessageA ; \SendMessageA <<============断在这里
76801DF8 .8B5C24 28 mov ebx,dword ptr ss:
76801DFC >8A0B mov cl,byte ptr ds:
76801DFE .84C9 test cl,cl
76801E00 .^ 75 91 jnz short user32.76801D93
系统调用ImmGetCompositionStringA获取输入法输入的字符,这里正常没错,之后通过程序TEB定位到程序的代码页,
使用IsDBCSLeadByteEx确定是否是中文,是就走第一个send,发送多字节,不是就走第二个(即断下位置),发送单字节。
问题就出现在这里了,获取到的代码页为1252,并非中文的936,导致IsDBCSLeadByteEx认为不是中文,走了第二个send。
之后测试在程序断在入口点时,将1252改为936,程序正常输入中文了。
代码页定位:TEB-->0xFDC(WowTebOffset),加上偏移后得到TEB64-->(0x800+0x98)Win32ClientInfo.CodePage( win32k!tagCLIENTINFO结构体)
最后,改下pe文件或者整个dll加载进去,把代码页改了齐活。
flyingdancex 发表于 2021-8-30 16:57
意思是要改系统user32.dll文件里的IsDBCSLeadByteEx,还是,唉~!还是没看明白...
改代码页就可以了,之所以没出成品,因为我无法定位修改的位置,不同的系统位置不一样 看半天意思明白了但还是解决不了... 意思是要改系统user32.dll文件里的IsDBCSLeadByteEx,还是,唉~!还是没看明白... 学习了,原来系统问题还可以这样分析,这才是从根源上解决问题。虽然最难,但是最彻底。 可以很强大 可以很强 苏紫方璇YYDS 值得试一下 虽然没用,先留着以后用