callach 发表于 2013-3-30 15:14:27

delphi 输入法注入完整版

首先输入法必备的19个接口自己不要删除,不然输入法编译出来安装失败不要狗叫= =

其次输入法的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败不能注入

如何修改参照最下面的方法

‍------------------------------------------------------------------

思路:

1.创建一个文件映射对象,映射到内存,写入需要注入的dll名称,进程ID
2.保存原有默认输入法句柄,复制输入法程序到系统目录,并调用ImmInstallIME安装输入法
3.创建事件对象,以便同步dll的加载与卸载。
4.向目标进程的窗口句柄发送WM_INPUTLANGCHANGEREQUEST消息,lParam为输入法句柄
5.等待注入完成,广播WM_INPUTLANGCHANGEREQUEST消息,lParam为原有默认输入法句柄
6.卸载输入法,释放事件对象。



先来ime输入法,记得把编译出来的程序后缀设置为ime

library   Ime;

uses
Windows,
SysUtils,
Classes,
Psapi,
ImeMain in 'ImeMain.pas',
ImeInject in 'ImeInject.pas';

{$E ime}
{$RIme.res}

procedure MyDllProc(Reason: Integer);
var
LoadDllEvent:THandle;
UnLoadDllEvent:THandle;
begin

case Reason of

    DLL_PROCESS_ATTACH:
      begin
      UnLoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_UNLOADDLL);
      if UnLoadDllEvent>0 then
      begin
          ResetEvent(UnLoadDllEvent);
      end;
      RegisterImeWindow;
      GetImeInjectInfo(@InjectInfo);
      if InjectInfo.ProcessId=GetCurrentProcessId then
      begin
          LoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_LOADDLL);
          LoadLibrary(@InjectInfo.DllName);      

         if LoadDllEvent>0 then
          begin
            SetEvent(LoadDllEvent);
          end;
      end;
      end;

    DLL_PROCESS_DETACH:
      begin
      UnRegisterImeWindow;
      UnLoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_UNLOADDLL);
      if UnLoadDllEvent>0 then
      begin
          SetEvent(UnLoadDllEvent);
      end;
      end;

end;
end;

exports
ImeConversionList,
ImeConfigure,
ImeDestroy,
ImeEscape,
ImeInquire,
ImeProcessKey,
ImeSelect,
ImeSetActiveContext,
ImeSetCompositionString,
ImeToAsciiEx,
NotifyIME,
ImeRegisterWord,
ImeUnregisterWord,
ImeGetRegisterWordStyle,
ImeEnumRegisterWord,
UIWndProc,
StatusWndProc,
CompWndProc,
CandWndProc;
begin
DllProc := @MyDllProc;
MyDllProc(DLL_PROCESS_ATTACH);
end.

‍-----------------------------------------------------

ime的主要单元

unit ImeMain;

interface

uses Windows,SysUtils,Classes,Imm,ImeInject;

const
IME_WINDOWCLASSNAME='Ime';
IME_SMODE_NONE=$0000;
UI_CAP_2700=$00000001;
SELECT_CAP_CONVERSION=$00000001;
// IME property bits
IME_PROP_END_UNLOAD=$00000001;
IME_PROP_KBD_CHAR_FIRST=$00000002;
IME_PROP_IGNORE_UPKEYS=$00000004;
IME_PROP_NEED_ALTKEY=$00000008;
IME_PROP_NO_KEYS_ON_CLOSE=$00000010;
IME_PROP_AT_CARET=$00010000;
IME_PROP_SPECIAL_UI=$00020000;
IME_PROP_CANDLIST_START_FROM_1=$00040000;
IME_PROP_UNICODE=$00080000;
IME_PROP_COMPLETE_ON_UNSELECT=$00100000;
type
PImeInfo=^TImeInfo;
TImeInfo=record
    dwPrivateDataSize:DWORD;
    fdwProperty:DWORD;
    fdwConversionCaps:DWORD;
    fdwSentenceCaps:DWORD;
    fdwUICaps:DWORD;
    fdwSCSCaps:DWORD;
    fdwSelectCaps:DWORD;
end;
PTransMsg = ^TTransMsg;
TTransMsg = record
    message: uInt;
    wParam: WParam;
    lParam: LParam;
end;
PTransMsgList = ^TTransMsgList;
TTransMsgList = record
    uMsgCount: uInt;
    TransMsg: array of TTransMsg;
end;
PPrivContext = ^TPrivContext;
TPrivContext = record
    iImeState: Integer;

    fdwImeMsg: DWord;   

    dwCompChar: DWord;
    fdwGcsFlag: DWord;
    uSYHFlg: uInt;
    uDYHFlg: uInt;
    uDSMHCount: uInt;
    uDSMHFlg: uInt;
    bSeq: array of Char; // sequence code of input char
    fdwGB: DWord;
end;
function RegisterImeWindow:BOOL;
procedure UnRegisterImeWindow;
function ImeConversionList(hImc:HIMC;lpSource:PChar;lpCandList:PCandidateList;
uBufLen,uFlag:UINT):DWORD;stdcall;
function ImeConfigure(hKl:HKL;hWnd:HWND;dwMode:DWORD;lpData:Pointer)
:BOOL;stdcall;
function ImeDestroy(uForce:UINT):BOOL;stdcall;
function ImeEscape(hImc:HIMC;uSubFunc:UINT;lpData:PChar):LRESULT;stdcall;
function ImeInquire(lpImeInfo:PImeInfo;lpszUIClass:PChar;lpszOption:DWORD)
:BOOL;stdcall;
function ImeProcessKey(hImc:HIMC;uKey:UINT;lKeyData:LPARAM;
lpbKeyState:PKeyboardState):BOOL;stdcall;
function ImeSelect(hImc:HIMC;fSelect:BOOL):BOOL;stdcall;
function ImeSetActiveContext(hImc:HIMC;fFlag:BOOL):BOOL;stdcall;
function ImeSetCompositionString(hImc:HIMC;dwIndex:DWORD;lpComp:Pointer;
dwComp:DWORD;lpRead:Pointer;dwRead:DWORD):BOOL;stdcall;
function ImeToAsciiEx(uVKey,uScanCode:UINT;lpbKeyState:PKeyboardState;
lpdwTransKey:PTransMsgList;fuState:UINT;hImc:HIMC):UINT;stdcall;
function NotifyIME(hImc:HIMC;dwAction:DWORD;dwIndex:DWORD;
dwValue:DWORD):BOOL;stdcall;
function ImeRegisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
:BOOL;stdcall;
function ImeUnregisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
:BOOL;stdcall;
function ImeGetRegisterWordStyle(nItem:UINT;lpStyleBuf:PStyleBuf):UINT;stdcall;
function ImeEnumRegisterWord(lpfnRegisterWordEnumProc:RegisterWordEnumProc;
lpszReading:PChar;dwStyle:DWORD;lpszString:PChar;lpData:Pointer):UINT;stdcall;
function UIWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
function StatusWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
function CompWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
function CandWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;

var
InjectInfo:TImeInject;

implementation

function RegisterImeWindow:BOOL;
var
wc:WNDCLASSEX;
begin
wc.style:=CS_IME or CS_VREDRAW or CS_HREDRAW or CS_DBLCLKS;
wc.lpfnWndProc:=@UIWndProc;
wc.cbClsExtra:=0;
wc.cbWndExtra:=0;
wc.hInstance:=HInstance;
wc.hIcon:=0;
wc.hCursor:=LoadCursor(0, IDC_ARROW );
wc.hbrBackground:=GetStockObject(WHITE_BRUSH);
wc.lpszMenuName:=nil;
wc.lpszClassName:=IME_WINDOWCLASSNAME;
wc.hIconSm:=0;
Result:=Windows.RegisterClassEx(wc)<>0;
end;


procedure UnRegisterImeWindow;
begin
Windows.UnregisterClass(IME_WINDOWCLASSNAME,HInstance);
end;

function ImeConversionList(hImc:HIMC;lpSource:PChar;lpCandList:PCandidateList;
uBufLen,uFlag:UINT):DWORD;
begin
Result:=0;
end;

function ImeConfigure(hKl:HKL;hWnd:HWND;dwMode:DWORD;lpData:Pointer):BOOL;
begin
Result:=dwMode=IME_CONFIG_GENERAL;
end;

function ImeDestroy(uForce:UINT):BOOL;
begin
Result:=not BOOL(uForce);
end;

function ImeEscape(hImc:HIMC;uSubFunc:UINT;lpData:PChar):LRESULT;
begin
Result:=0;
end;

function ImeInquire(lpImeInfo:PImeInfo;lpszUIClass:PChar;lpszOption:DWORD):BOOL;
begin
Result := False;
lpImeInfo.dwPrivateDataSize:=SizeOf(TPrivContext);
lpImeInfo.fdwProperty:=IME_PROP_KBD_CHAR_FIRST or IME_PROP_IGNORE_UPKEYS;
lpImeInfo.fdwConversionCaps:=IME_CMODE_FULLSHAPE or IME_CMODE_NATIVE;
lpImeInfo.fdwSentenceCaps:=IME_SMODE_NONE;
lpImeInfo.fdwUICaps:=UI_CAP_2700;
lpImeInfo.fdwSCSCaps:=0;
lpImeInfo.fdwSelectCaps:=SELECT_CAP_CONVERSION;
StrCopy(lpszUIClass,IME_WINDOWCLASSNAME);
Result:=True;
end;

function ImeProcessKey(hImc:HIMC;uKey:UINT;lKeyData:LPARAM;
lpbKeyState:PKeyboardState):BOOL;
begin
Result:=False;
end;

function ImeSelect(hImc:HIMC;fSelect:BOOL):BOOL;
begin
Result:=True;
end;

function ImeSetActiveContext(hImc:HIMC;fFlag:BOOL):BOOL;
begin
Result:=True;
end;


function ImeSetCompositionString(hImc:HIMC;dwIndex:DWORD;lpComp:Pointer;
dwComp:DWORD;lpRead:Pointer;dwRead:DWORD):BOOL;
begin
Result:=False;
end;

function ImeToAsciiEx(uVKey,uScanCode:UINT;lpbKeyState:PKeyboardState;
lpdwTransKey:PTransMsgList;fuState:UINT;hImc:HIMC):UINT;
begin
Result:=0;
end;

function NotifyIme(hImc:HIMC;dwAction:DWORD;dwIndex:DWORD;
dwValue:DWORD):BOOL;
begin
Result:=False;
end;

function ImeRegisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar):BOOL;
begin
Result:=False;
end;

function ImeUnregisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
:BOOL;
begin
Result:=False;
end;

function ImeGetRegisterWordStyle(nItem:UINT;lpStyleBuf:PStyleBuf):UINT;
begin
Result:=0;
end;

function ImeEnumRegisterWord(lpfnRegisterWordEnumProc:RegisterWordEnumProc;
lpszReading:PChar;dwStyle:DWORD;lpszString:PChar;lpData:Pointer):UINT;
begin
Result:=0;
end;

function UIWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;

function StatusWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;

function CompWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;

function CandWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;
end.

---------------------------------------------------------------

ime和注入程序的公共单元

unit ImeInject;

interface

uses Windows,SysUtils;

const
GUID_INJECT='{7E145D1D-663A-5BDC-EA47-B11342BF2315}';
GUID_LOADDLL='{7E145D1D-663A-5BDC-EA47-B11342BF2416}';
GUID_UNLOADDLL='{7E145D1D-663A-5BDC-EA47-B11342BF2517}';

type
PImeInject= ^TImeInject;
TImeInject= packed record
    DllName:array of Char;//注入的dll路径
    ProcessId: DWORD;//注入的进程ID
end;
procedure CreateImeInjectInfo(DllName: string; ProcessId: DWORD; var FileMapHandle:THandle);
procedure GetImeInjectInfo(ImeInject:PImeInject);

implementation
procedure CreateImeInjectInfo(DllName:string; ProcessId: DWORD; var FileMapHandle:THandle);
var
InjectInfo:PImeInject;
begin
FileMapHandle:=0;
FileMapHandle := CreateFileMapping(INVALID_HANDLE_VALUE,nil,PAGE_READWRITE,0,SizeOf(TImeInject),GUID_INJECT); //以可读写形式创建有名文件映象
if FileMapHandle > 0 then //返回的文件映射对象句柄不为零
begin
    InjectInfo:=MapViewOfFile(FileMapHandle,FILE_MAP_ALL_ACCESS,0,0,0); //在调用的进程中地址空间映射一个可完全控制文件视图
    if InjectInfo<>nil then//如果返回的映射视图的起始地址不为空
    begin
      ZeroMemory(InjectInfo,SizeOf(TImeInject)); //TImeInject结构内存填零
      CopyMemory(@(InjectInfo.DllName),PChar(DllName),MAX_PATH-1);//填写结构体里的内容
      InjectInfo.ProcessId:=ProcessId; //填写进程ID
      UnmapViewOfFile(InjectInfo);// 删除映射视图
    end;
end;
end;

procedure GetImeInjectInfo(ImeInject:PImeInject);
var
FileMapHandle:THandle;
InjectInfo:PImeInject;
begin
ZeroMemory(ImeInject,SizeOf(TImeInject));//结构体内存填零
FileMapHandle:=OpenFileMapping(FILE_MAP_READ,False,GUID_INJECT); //打开GUID_INJECT的文件映射
if FileMapHandle>0 then
begin
    InjectInfo:=MapViewOfFile(FileMapHandle,FILE_MAP_READ,0,0,0);
    if InjectInfo<>nil then
    begin
      CopyMemory(ImeInject,InjectInfo,SizeOf(TImeInject));
      UnmapViewOfFile(InjectInfo);
    end;
    CloseHandle(FileMapHandle);
end;
end;
end.

-----------------------------------------------------------------------------------------

注入程序,注意引用 ImeInject 单元 ,Imm 单元 和 Registry 单元



const
WM_INPUTLANGCHANGEREQUEST = $0050;

var

FileMapHandle: THandle;



Procedure Inject(WindowName:string;Dllpath:string);
var
WindowHandle: THandle;
InjectProcessId: DWORD;
LoadDllEvent: THandle;
UnLoadDllEvent: THandle;
DefaultImeHandle: THandle;
ImeHandle: THandle;
ImeId: string;
ImePath: string;
SysDir: array of Char;
begin
WindowHandle := FindWindow(nil, PChar(WindowName));
if WindowHandle > 0 then
begin
    GetWindowThreadProcessId(WindowHandle, InjectProcessId);
    if InjectProcessId > 0 then
    begin
      if FileMapHandle > 0 then
      CloseHandle(FileMapHandle);
      CreateImeInjectInfo(PChar(Dllpath), InjectProcessId,
      FileMapHandle);
      if FileMapHandle > 0 then
      begin
      SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, @DefaultImeHandle, 0);
      ZeroMemory(@SysDir, MAX_PATH);
      GetSystemDirectory(@SysDir, MAX_PATH);
      ImePath := string(SysDir) + '\ImeInject.ime';
      //复制输入法文件到系统目录
      if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'ImeInject.ime'),
          PChar(ImePath), False) then
      begin
          //安装输入法
          ImeHandle := ImmInstallIME(PChar(ImePath), 'zhusjm输入法');
          if ImeHandle > 0 then
          begin
            UnLoadDllEvent := CreateEvent(nil, True, True, GUID_UNLOADDLL);
            LoadDllEvent := CreateEvent(nil, True, False, GUID_LOADDLL);
            //向目标窗口发送激活输入法的消息
            PostMessage(WindowHandle,WM_INPUTLANGCHANGEREQUEST, 0,ImeHandle);
            //等待注入完成
            if WaitForSingleObject(LoadDllEvent, 3000) = WAIT_OBJECT_0 then
            begin
            ShowMessage('注入成功');
            //广播消息,使我们的输入法卸载
            PostMessage(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, 0,
                DefaultImeHandle);
            //等待输入法卸载
            if WaitForSingleObject(UnLoadDllEvent, 3000) = WAIT_OBJECT_0 then
            begin
            end;
            end;
            UnloadKeyboardLayout(ImeHandle);
            DeleteFile(ImePath);
            CloseHandle(UnLoadDllEvent);
            CloseHandle(LoadDllEvent);
          end;
      end;
      end;
    end;
end;
end;‍

---------------------------------------------------------------------

因为ime的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败

输入法ime的 资源文件,新建 rc 写入以下内容用delphi的brcc32.exe编译成res 然后 ime 里面

引用这个资源再编译出来ime输入法才能被ImmInstallIME函数安装

VS_VERSION_INFO VERSIONINFO //版本信息结构
FILEVERSION 1,0,0,1   //文件版本
PRODUCTVERSION 1,0,0,1 //这里是主版本信息
FILEFLAGSMASK 0x3fL   //这里设为0x3fL就好
#ifdef _DEBUG
FILEFLAGS 0x1L       //VS_FF_DEBUG包括debug信息
#else
FILEFLAGS 0x0L       //无
#endif
FILEOS 0x4L         //win32程序
FILETYPE 0x3L       //文件类型,2是dll,1是exe,3是VFT_DRV 驱动程序
FILESUBTYPE 0xbL    //VFT2_DRV_INPUTMETHOD 输入法驱动程序
BEGIN
BLOCK "StringFileInfo" //这里设置文件其他的版本信息(详细信息)
BEGIN
    BLOCK "080403A8"   //所用语言080403A8简体中文
    BEGIN
      VALUE "Comments","Microsoft(R) Windows(R) Operating System"   //备注
      VALUE "CompanyName","Microsoft(R)\0"         //公司名
      VALUE "FileDescription", "zhu.ime\0"       //产品描述
      VALUE "FileVersion", "1. 0. 0. 1\0"       //文件版本
      VALUE "InternalName", ""               //内部名称
      VALUE "LegalCopyright", "Copyright (C) 2000.01\0" //版权信息
      VALUE "OriginalFilename", "zhu.ime\0"         //源文件名
      VALUE "ProductName", "zhu.ime\0"         //产品名
      VALUE "ProductVersion", "1. 0. 0. 1\0"       //产品版本
    END
END
BLOCK "VarFileInfo"
BEGIN
    VALUE "Translation", 0x804, 0x03A8
END                  
END

鸢都醉逍遥 发表于 2013-9-2 22:39:44

支持流星社区....!

鸢都醉逍遥 发表于 2013-9-2 22:39:56

支持流星社区....!

65162310 发表于 2013-11-18 11:40:22

收藏了111111111
页: [1]
查看完整版本: delphi 输入法注入完整版