主页 > 编程资料 > Delphi >
发布时间:2015-09-22 作者:网络 阅读:108次

 

代码思路原作者,不详.......................膜拜第一位作者的开创思维

本人只是稍作修改和写入一些原作者没有告诉的东西

首先输入法必备的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}
{$R  Ime.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[0..0] 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[0..12] 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[0..MAX_PATH] 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[0..MAX_PATH] 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


关键字词: