msimg32.dll劫持失败原因分析
问题描述
前一段事件做一个题的时候,需要修改主程序执行逻辑,当时想想应该很简单,直接做dll劫持然后在该DllMain中去修改主程序Exe的执行逻辑(因为之前看到飘云阁的 Visual Assist X劫持用的msimg32)。很顺利的在调试系统(win xp)做完了,达到了预期目的。但是拿到win7和win10上运行顿时就不行了。
主要问题有两个:
- win7上直接不加载劫持dll,msimg32.dll了
- win10上会加载msimg32.dll,但是加载时间靠后,在主程序逻辑执行后才被加载,这会修改逻辑也没用了
当时时间紧急,也比较慌。没有分析,改了方案直接修改主程序二进制,文件补丁方式做的
问题分析调试
问题1

首先depends看下主程序dll依赖情况,发现确实有msimg32.dll啊。怎么会出现win7不加载呢?好像前面有个沙漏,F1查看depends帮助发现这个沙漏标志msimg32.dll是延迟加载dll(延迟加载的dll是在该dll中的函数被调用的时候才被加载,延迟加载提高的程序的启动速度)。那为什么winxp会加载呢?

上神器procmon,发现是在imm32.dll中加载了msimg32.dll,搜索imm32.dll发现是和输入法相关。对比两个系统发现winxp调试系统安装了qq拼音输入法而win7上没有,应该qq拼音的原因。将xp的qq输入法卸载,果然xp系统也不加载了。但是具体什么原因还不知道,直接上调试器,但开始不知道怎么下断点,就直接将msimg32.dll的入口点修改二进制为0xcc,直接断下(其实可以直接对bu ntdll!LdrLoadDll “dU /c 50 poi(@ebp+8)”
,开始下的LoadLibaryExW以为加载dll都会通过这个函数),堆栈情况如下
1 | ChildEBP RetAddr Args to Child |
发现在加载QQPINYIN.IME的时候,在解决QQPINYIN.IME依赖dll的时候加载了msimg32.dll。

问题2
好了,问题1解决了,该问题2了。win10上同样装的qq输入法,但是输入法劫持dll的加载时机却靠后了,这是怎么回事呢?
在procmon观察,在win10系统QQpinyin.ime是被QQPinyinTSF.dll这个dll加载的,而在winxp上是imm32.dll。上调试器观察下有什么不同
winxp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
260012eac4 "C:\WINDOWS\system32\QQPINYIN.IME"
00 0012eaa4 763071f4 kernel32!LoadLibraryW+0x5
01 0012ecd0 76307680 IMM32!ImmNotifyIME+0x21c
02 0012ee64 763077bb IMM32!ImmNotifyIME+0x6a8
03 0012ee74 77d6b570 IMM32!ImmLoadIME+0x4c
04 0012ee84 77d6be00 USER32!IMPSetIMEA+0x6c
05 0012f0d4 77d6c8cf USER32!IMPSetIMEA+0x8fc
06 0012f0f8 77d6c952 USER32!IMPSetIMEA+0x13cb
07 0012f114 77d18734 USER32!IMPSetIMEA+0x144e
08 0012f140 77d18816 USER32!GetDC+0x6d
09 0012f1a8 77d2a013 USER32!GetDC+0x14f
0a 0012f1d8 77d2a998 USER32!IsWindowUnicode+0xa1
0b 0012f1f8 0040d08f USER32!CallWindowProcA+0x1b
0c 0012f26c 77d18734 image00400000+0xd08f
0d 0012f298 77d18816 USER32!GetDC+0x6d
0e 0012f300 77d28ea0 USER32!GetDC+0x14f
0f 0012f354 77d28eec USER32!DefWindowProcW+0x180
10 0012f37c 7c92e453 USER32!DefWindowProcW+0x1cc
11 0012f844 77d26423 ntdll!KiUserCallbackDispatcher+0x13
12 0012f91c 77d2683e USER32!IsDlgButtonChecked+0x1629
13 0012f940 77d39b43 USER32!CreateDialogIndirectParamAorW+0x33
14 0012f960 0040c465 USER32!CreateDialogIndirectParamA+0x1b
15 0012f9c8 0040c68e image00400000+0xc465
16 0012fa0c 004010e4 image00400000+0xc68e
17 0012ffc0 7c817067 image00400000+0x10e4
18 0012fff0 00000000 kernel32!RegisterWaitForInputIdle+0x49
win101
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
530019d848 "C:\WINDOWS\SysWow64\IME\QQPinyinTSF\QQPinyinTSF.dll"
00 0019d794 752ac012 KERNELBASE!LoadLibraryExW+0x5
01 0019d7b8 752abf8a combase!LoadLibraryWithLogging+0x1b
02 0019d7e4 752ac136 combase!CClassCache::CDllPathEntry::LoadDll+0x50
03 0019d824 752ad6f7 combase!CClassCache::CDllPathEntry::Create+0x3c
04 0019da74 752f98ce combase!CClassCache::CClassEntry::CreateDllClassEntry+0xe3
05 0019dda4 752accb2 combase!CClassCache::GetClassObjectActivator+0x82e
06 0019ddd8 752ac898 combase!CClassCache::GetClassObject+0x30
07 0019de48 752b6dfa combase!CServerContextActivator::CreateInstance+0x128
08 0019de94 752acef2 combase!ActivationPropertiesIn::DelegateCreateInstance+0xba
09 0019deec 752b1575 combase!CApartmentActivator::CreateInstance+0xa2
0a 0019df1c 752b1640 combase!CProcessActivator::CCICallback+0x65
0b 0019df40 752b16d7 combase!CProcessActivator::AttemptActivation+0x40
0c 0019df80 752b18f7 combase!CProcessActivator::ActivateByContext+0x77
0d 0019dfb0 752b6ddb combase!CProcessActivator::CreateInstance+0x67
0e 0019dffc 752b2e7d combase!ActivationPropertiesIn::DelegateCreateInstance+0x9b
0f 0019e260 752b6de2 combase!CClientContextActivator::CreateInstance+0xfd
10 0019e2ac 752f77a0 combase!ActivationPropertiesIn::DelegateCreateInstance+0xa2
11 0019ec18 752f6ba2 combase!ICoCreateInstanceEx+0xae0
12 0019ecc8 752f8209 combase!CComActivator::DoCreateInstance+0x162
13 0019ed08 7510dece combase!CoCreateInstance+0xa9
14 0019ee44 7510e28f MSCTF!CThreadInputMgr::_CreateTip+0x1be
15 0019ee84 7510c458 MSCTF!CThreadInputMgr::ActivateInputProfile+0x10f
16 0019efb0 7510c85d MSCTF!CThreadInputMgr::OnActiveProfileChange+0x668
17 0019f1e0 7511e12f MSCTF!CThreadInputMgr::OnInputFocusEvent+0x2cd
18 0019f8a0 743a9733 MSCTF!WinEventProc+0x5bf
19 0019f8e8 777608c6 USER32!__ClientCallWinEventProc+0x43
1a 0019f920 775d24ec ntdll!KiUserCallbackDispatcher+0x36
1b 0019f924 743b24d3 win32u!NtUserGetMessage+0xc
1c 0019f950 0040bc09 USER32!GetMessageA+0x53
WARNING: Stack unwind information not available. Following frames may be wrong.
1d 0019f96c 0040eff5 image00400000+0xbc09
1e 0019f9dc 00000000 image00400000+0xeff5
00670ab0 "C:\WINDOWS\system32\IME\QQPinyinTSF\QQPinyin.ime"
00 0019e974 7578c711 KERNELBASE!LoadLibraryExW+0x5
01 0019e988 568cb24f KERNELBASE!LoadLibraryW+0x11
WARNING: Stack unwind information not available. Following frames may be wrong.
02 0019ecf4 568cd764 QQPinyinTSF!DllGetClassObject+0x24cf
03 0019ed18 568cb8da QQPinyinTSF!DllGetClassObject+0x49e4
04 0019eda8 750f4939 QQPinyinTSF!DllGetClassObject+0x2b5a
05 0019eddc 7510dc53 MSCTF!CTip::Activate+0x63
06 0019ee48 7510e2d9 MSCTF!CThreadInputMgr::_ActivateTip+0x9f
07 0019ee84 7510c458 MSCTF!CThreadInputMgr::ActivateInputProfile+0x159
08 0019efb0 7510c85d MSCTF!CThreadInputMgr::OnActiveProfileChange+0x668
09 0019f1e0 7511e12f MSCTF!CThreadInputMgr::OnInputFocusEvent+0x2cd
0a 0019f8a0 743a9733 MSCTF!WinEventProc+0x5bf
0b 0019f8e8 777608c6 USER32!__ClientCallWinEventProc+0x43
0c 0019f920 775d24ec ntdll!KiUserCallbackDispatcher+0x36
0d 0019f924 743b24d3 win32u!NtUserGetMessage+0xc
0e 0019f950 0040bc09 USER32!GetMessageA+0x53
0f 0019f96c 0040eff5 image00400000+0xbc09
10 0019f9dc 00000000 image00400000+0xeff5
总结一下QQpinyin.ime在winxp和win10上的不同调用序列:
winxp:kernel32!RegisterWaitForInputIdle———>user32!CreateDialogIndirectParamA———->USER32!IMPSetIMEA+0x13cb———>IMM32!ImmNotifyIME+0x21c
win10:USER32!GetMessageA+0x53————>MSCTF!CThreadInputMgr::_CreateTip+0x1be——->combase!CClassCache::CDllPathEntry::LoadDll+0x50 ——–>MSCTF!CTip::Activate+0x63———->QQPinyinTSF!DllGetClassObject+0x24cf
基本描述了问题(在xp上在exe主函数未执行前QQpinyin.ime就已经被加载了,在win10是在exez主函数执行完成后开始获取消息的时候加载的ime),但是没有解释为什么会这样
google搜索一下发现了在xp与win10上输入法的框架的不同:1
2
3
4
5
6
7
8Windows提供了两套输入法框架: Windows XP及之前,是IMM (Input Method Manager),
基于纯函数API的。目前市面上非微软中文输入法基本上都是只实现IMM框架。Windows XP开
始及以后,Windows提供新的输入框架TSF,是基于COM的实际上,到了WindowsVista,Windows7,
所有的应用程序和各种输入控件都是优先使用TSF的实现。但之所以Windows Vista,Windows 7
用户还能使用各种基于IMM的输入法,是因为Windows提供了一个组件来将所有TSF的请求转为IMM的API。
(PunCha:难道Win8开始就不提供了吗?!很有可能,因为Win8下很多Imm的函数
都不能使用了)按照微软的说法,TSF会最终取代IMM框架。而微软拼音基于兼容,
功能和性能方面的原因,将这两个框架都实现了。
总结
总结一下就是,由于使用QQ输入法而引入了Dll劫持漏洞但是由于输入法框架的不同导致劫持dll的加载时机的不同。
参考文献
Visual Assist X 劫持破解 Patch With Key (通杀1041~2118) 解决变灰问题
动态链接库的静态链接导致程序的DLL劫持漏洞-借助QQ程序xGraphic32.dll描述
TSF(Text Service Framework)简介
逗比的输入法实现(一):基本情况