本帖最后由 苏紫方璇 于 2021-8-30 22:35 编辑
最近遇到一个问题,在win10下,部分vb6或者delphi7写的使用A函数控件的程序,TextBox输入中文总是乱码,而复制粘贴则正常。
在网上查找发现,目前通用的办法是删除美式键盘即可解决。
测试一下确实如此,但是,删除后会改变切换输入法的习惯,为了极个别老古董程序改习惯还是不太舒服的。于是就大致看了一下问题所在。
在网上搜索发现,输入法最后会发送一个WM_IME_CHAR的消息,其中包含了输入的文本。
既然是多字节的A类控件,断SendMessageA即可在输入汉字后触发断点。
程序断在user32中,向上查找发现部分流程。
代码如下
[Asm] 纯文本查看 复制代码 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:[ebp+0x14],eax
76801D23 . 0F84 DE000000 je user32.76801E07
76801D29 . 8B35 F4128576 mov esi,dword ptr ds:[0x768512F4] ; imm32.ImmGetCompositionStringA
76801D2F . 8BCE mov ecx,esi
76801D31 . FF15 4C408576 call dword ptr ds:[0x7685404C] ; 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:[esi+0x1]
76801D46 . 51 push ecx ; /dwBytes = 0x0
76801D47 . 6A 08 push 0x8 ; |dwFlags = HEAP_ZERO_MEMORY
76801D49 . FF35 F0198576 push dword ptr ds:[0x768519F0] ; |hHeap = 00430000
76801D4F . FF15 60378576 call dword ptr ds:[<&ntdll.RtlAllocateHe>; \RtlAllocateHeap
76801D55 . 894424 1C mov dword ptr ss:[esp+0x1C],eax
76801D59 . 85C0 test eax,eax
76801D5B . 0F84 46010000 je user32.76801EA7
76801D61 . 56 push esi
76801D62 . 8B35 F4128576 mov esi,dword ptr ds:[0x768512F4] ; imm32.ImmGetCompositionStringA
76801D68 . 8BCE mov ecx,esi
76801D6A . 50 push eax
76801D6B . 68 00080000 push 0x800
76801D70 . FF7424 30 push dword ptr ss:[esp+0x30]
76801D74 . FF15 4C408576 call dword ptr ds:[0x7685404C] ; user32.767EEEA0
76801D7A . FFD6 call esi
76801D7C . 8B4424 1C mov eax,dword ptr ss:[esp+0x1C]
76801D80 . 8A08 mov cl,byte ptr ds:[eax]
76801D82 . 84C9 test cl,cl
76801D84 . 0F84 0A010000 je user32.76801E94
76801D8A . 8B7C24 14 mov edi,dword ptr ss:[esp+0x14]
76801D8E . 33F6 xor esi,esi
76801D90 . 46 inc esi
76801D91 . 8BD8 mov ebx,eax
76801D93 > 64:A1 1800000>mov eax,dword ptr fs:[0x18]
76801D99 . 8B90 DC0F0000 mov edx,dword ptr ds:[eax+0xFDC]
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:[eax+0x898]
76801DAC . 8D53 01 lea edx,dword ptr ds:[ebx+0x1]
76801DAF . 51 push ecx
76801DB0 . 50 push eax
76801DB1 . 895424 30 mov dword ptr ss:[esp+0x30],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:[esp+0x28]
76801DC3 . 8A00 mov al,byte ptr ds:[eax]
76801DC5 . 84C0 test al,al
76801DC7 . 74 1C je short user32.76801DE5
76801DC9 . 0FB60B movzx ecx,byte ptr ds:[ebx]
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:[esp+0x28]
76801DE5 > 43 inc ebx
76801DE6 . EB 14 jmp short user32.76801DFC
76801DE8 > 0FB603 movzx eax,byte ptr ds:[ebx]
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:[esp+0x28]
76801DFC > 8A0B mov cl,byte ptr ds:[ebx]
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加载进去,把代码页改了齐活。
|