首页
社区
课程
招聘
[分享]金山快译的原理实现--全局钩子勾住textout
2013-9-8 16:58 14203

[分享]金山快译的原理实现--全局钩子勾住textout

2013-9-8 16:58
14203
大家可能都对金山快译可以将英文软件翻译成中文软件的功能感到惊奇
其实就是全局钩子勾住textout函数

钩子头文件如下

void __declspec(dllexport) WINAPI InstallHook(BOOL,DWORD); 
BOOL WINAPI UnInstallHook(); 
LRESULT CALLBACK GetMsgProC(int code,WPARAM wParam,LPARAM lParam); 
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress, 
        PROC pfnDummyFuncAddress,HMODULE hModCallerModule); 
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress, 
        PROC pfnDummyFuncAddress,HMODULE hModCallerModule); 
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress, 
         PROC pfnDummyFuncAddress,HMODULE hModCallerModule); 
BOOL WINAPI H_TextOutA(HDC, int, int, LPCSTR, int); 
BOOL WINAPI H_TextOutW(HDC, int, int, LPCWSTR, int); 
BOOL WINAPI H_ExtTextOutA(HDC, int, int, UINT, CONST RECT *,LPCSTR, UINT, CONST INT *); 
BOOL WINAPI H_ExtTextOutW(HDC, int, int, UINT, CONST RECT *,LPCWSTR, UINT, CONST INT *); 


钩子源文件如下

#include "stdafx.h"   
#include "APIHook_Dll.h"   
#include <ImageHlp.h>   
#include <tlhelp32.h>   
#pragma comment(lib,"ImageHlp") //定义全局共享数据段   
#pragma data_seg("Shared")   
HMODULE hmodDll=NULL;   
HHOOK hHook=NULL;   
#pragma data_seg()   
#pragma comment(linker,"/Section:Shared,rws") //设置全局共享数据段的属性   
///////////////////////////////////// DllMain 函数 /////////////////////////////////////////   
//dll的入口点   
BOOL APIENTRY DllMain( HMODULE hModule,    
                       DWORD  ul_reason_for_call,    
                       LPVOID lpReserved   
      )   
{   
 switch(ul_reason_for_call)   
 {   
 case DLL_PROCESS_ATTACH:   
  //if(sHook)     
     
 case DLL_PROCESS_DETACH:   
  UnInstallHook();   
  break;   
 }   
 hmodDll=hModule;   
    return TRUE;   
}
///////////////////////////////////// HookOneAPI 函数 /////////////////////////////////////////   
//进行IAT转换的关键函数,其参数含义:   
//pszCalleeModuleName:需要hook的模块名   
//pfnOriginApiAddress:要替换的自己API函数的地址   
//pfnDummyFuncAddress:需要hook的模块名的地址   
//hModCallerModule:我们要查找的模块名称,如果没有被赋值,   
//     将会被赋值为枚举的程序所有调用的模块   
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,    
        PROC pfnDummyFuncAddress,HMODULE hModCallerModule)   
{   
 ULONG size;   
 //获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针   
 PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)   
  ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);   
 if (pImportDesc == NULL)   
  return;   
 //查找记录,看看有没有我们想要的DLL   
 for (;pImportDesc->Name;pImportDesc++)   
 {   
  LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name);   
  if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)   
   break;   
 }   
 if (pImportDesc->Name == NULL)   
 {   
  return;   
 }   
 //寻找我们想要的函数   
 PIMAGE_THUNK_DATA pThunk =    
  (PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);//IAT   
 for (;pThunk->u1.Function;pThunk++)   
 {   
  //ppfn记录了与IAT表项相应的函数的地址   
  PROC * ppfn= (PROC *)&pThunk->u1.Function;     
  if (*ppfn == pfnOriginApiAddress)    
  {   
   //如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数   
   WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress),   
    sizeof(pfnDummyFuncAddress),NULL);   
   return;   
  }   
 }   
}   
//查找所挂钩的进程所应用的dll模块的   
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,   
        PROC pfnDummyFuncAddress,HMODULE hModCallerModule)   
{   
 if (pszCalleeModuleName == NULL)   
 {   
  return FALSE;   
 }   
 if (pfnOriginApiAddress == NULL)   
 {   
  return FALSE;   
 }   
 //如果没传进来要挂钩的模块名称,枚举被挂钩进程的所有引用的模块,   
 //并对这些模块进行传进来的相应函数名称的查找   
    
 if (hModCallerModule == NULL)   
 {   
  MEMORY_BASIC_INFORMATION mInfo;   
  HMODULE hModHookDLL;   
  HANDLE hSnapshot;   
  MODULEENTRY32 me = {sizeof(MODULEENTRY32)};   
  //MODULEENTRY32:描述了一个被指定进程所应用的模块的struct   
  VirtualQuery(HookOneAPI,&mInfo,sizeof(mInfo));   
  hModHookDLL=(HMODULE)mInfo.AllocationBase;   
     
  hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);   
  BOOL bOk = Module32First(hSnapshot,&me);   
  while (bOk)   
  {   
   if (me.hModule != hModHookDLL)   
   {   
    hModCallerModule = me.hModule;//赋值   
    //me.hModule:指向当前被挂钩进程的每一个模块    
    HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,   
     pfnDummyFuncAddress,hModCallerModule);   
   }   
   bOk = Module32Next(hSnapshot,&me);   
  }   
  return TRUE;     
 }   
 //如果传进来了,进行查找   
 else   
 {   
  HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,   
    pfnDummyFuncAddress,hModCallerModule);   
  return TRUE;   
 }   
 return FALSE;   
}
//////////////////////////////////// UnhookAllAPIHooks 函数 /////////////////////////////////////   
//通过使pfnDummyFuncAddress与pfnOriginApiAddress相等的方法,取消对IAT的修改   
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,   
         PROC pfnDummyFuncAddress,HMODULE hModCallerModule)   
{   
 PROC temp;   
 temp = pfnOriginApiAddress;   
 pfnOriginApiAddress = pfnDummyFuncAddress;   
 pfnDummyFuncAddress = temp;   
 return HookAllAPI(pszCalleeModuleName,pfnOriginApiAddress,   
  pfnDummyFuncAddress,hModCallerModule);   
} 
////////////////////////////////// GetMsgProc 函数 ////////////////////////////////////////   
//钩子子程。与其它钩子子程不大相同,没做什么有意义的事情,继续调用下一个钩子子程,形成循环   
LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)   
{   
 return CallNextHookEx(hHook,code,wParam,lParam);   
}
//////////////////////////////////// InstallHook 函数 /////////////////////////////////////   
//安装或卸载钩子,BOOL IsHook参数是标志位   
//对要钩哪个API函数进行初始化   
//我们这里装的钩子类型是WH_GETMESSAGE   
void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId)   
{   
 if(IsHook)   
 {   
 hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId);   
    
 //GetProcAddress(GetModuleHandle("GDI32.dll"),"ExtTextOutA"):取得要钩的函数在所在dll中的地址   
    
 HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),   
  "TextOutW"),(PROC)&H_TextOutW,NULL);   
 HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),   
  "TextOutA"),(PROC)&H_TextOutA,NULL);   
 }   
 else   
 {   
  UnInstallHook();   
  UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),   
   "TextOutW"),(PROC)&H_TextOutW,NULL);   
  UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),   
   "TextOutA"),(PROC)&H_TextOutA,NULL);   
 }   
}

///////////////////////////////////// UnInstallHook 函数 ////////////////////////////////////   
//卸载钩子   
BOOL WINAPI UnInstallHook()   
{   
 UnhookWindowsHookEx(hHook);   
 return TRUE;   
}   
///////////////////////////////////// H_TextOutA 函数 /////////////////////////////////////////   
//我们的替换函数,可以在里面实现我们所要做的功能   
//这里我做的是显示一个对话框,指明是替换了哪个函数   
BOOL WINAPI H_TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpString,int cbString)   
{   
//  FILE *stream=fopen("logfile.txt","a+t");   
 MessageBox(NULL,"TextOutA","APIHook_Dll ---rivershan",MB_OK);   
 TextOutA(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符   
// fprintf(stream,lpString);   
// fclose(stream);   
 return TRUE;   
}   
///////////////////////////////////// H_TextOutW 函数 /////////////////////////////////////////   
//同上   
BOOL WINAPI H_TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cbString)   
{    
 MessageBox(NULL,"TextOutW","APIHook_Dll ---rivershan",MB_OK);   
 TextOutW(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符   
 return TRUE;   
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞3
打赏
分享
最新回复 (18)
雪    币: 100
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
allenzh 2013-9-8 18:31
2
0
快二十年前的技术了,不过lz精神可嘉
雪    币: 1275
活跃值: (41)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
suiyu 2013-9-9 08:37
3
0
就是屏幕取词吧。。
雪    币: 242
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
司中 2013-9-9 12:46
4
0
说烂了,当年csdn老大蒋TAO的得意之处。
雪    币: 602
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kangcin 2013-9-9 15:53
5
0
好久的资料啦
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
正happy 1 2013-9-9 18:05
6
0
被发现啦~
雪    币: 680
活跃值: (68)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
稻草人Z 2 2013-9-10 08:28
7
0
mark之
雪    币: 14
活跃值: (78)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
乐乐侠 2013-9-10 20:35
8
0
mark!
雪    币: 174
活跃值: (620)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sunbinjin 1 2013-9-11 11:33
9
0
确实是老技术,不过lz用来研究也挺好的,对于正解原理不错
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rainboyxxx 2013-9-13 09:12
10
0
mark一下
雪    币: 74
活跃值: (543)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wodexinren 2013-9-13 09:18
11
0
mark
雪    币: 211
活跃值: (33)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ooshanshui 2013-9-13 11:09
12
0
mark
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
virtualabc 2013-9-13 11:58
13
0
奇怪,我写test.exe安装钩子(dll以静态方式加载),InstallHook(TRUE, 0);,居然没啥反应,我用360任务管事器查看了下只有test.exe有dll,其它进程都没加载上。而且没任何反应,,谁试过没?
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
殉道KJ 2013-9-13 15:10
14
0
昨天看一本老书的时候就看到了。。。没想到今天一上网也是。。。真巧。。。
雪    币: 135
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
岁月静好 2013-9-20 14:23
15
0
mark
雪    币: 4670
活跃值: (2876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
任蝶飞 2013-9-26 20:18
16
0
不是屏幕取词,你下一个金山快译试试就知道了。他可以把英文软件变成中文的。屏幕取词好像也用到了textout
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
AioliaSky 1 2013-9-26 20:37
17
0
路过,来围观一下
雪    币: 3496
活跃值: (749)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kxzpy 2014-3-15 14:19
18
0
下来实验一下。。
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cqzj70 2014-3-15 16:35
19
0
mark
游客
登录 | 注册 方可回帖
返回