屏幕取词

以下是我从别人处摘录的,作者我忘了,先向作者说声对不起。 ?
? ?
? ?
? 屏幕上的文字大都是由gdi32.dll的以下几个函数显示的:TextOutA、TextOutW、ExtTextOutA、ExtTextOutW。实现屏幕抓词 ?
? 的关键就是截获对这些函数的调用,得到程序发给它们的参数。 ? ?
? ?
?    我的方法有以下三个步骤: ? ?
? ?
?    一、得到鼠标的当前位置 ? ?
? ?
?    通过SetWindowsHookEx实现。 ? ?
? ?
?    二、向鼠标下的窗口发重画消息,让它调用系统函数重画 ? ?
? ?
?    通过WindowFromPoint,ScreenToClient,InvalidateRect ? 实现。 ? ?
? ?
?    三、截获对系统函数的调用,取得参数(以TextOutA为例) ? ?
? ?
?    1.仿照TextOutA作成自己的函数MyTextOutA,与TextOutA有相同参数和返回值,放在系统钩子所在的DLL里。 ? ?
? ?
?    SysFunc1=(DWORD)GetProcAddress(GetModuleHandle("gdi32.dll"),"TextOutA"); ? ?
? ?
?    BOOL ? WINAPI ? MyTextOutA(HDC ? hdc, ? int ? nXStart, ? int ? nYStart, ? LPCSTR ? lpszString,int ? cbString) ? ?
? ?
?    { ? //输出lpszString的处理 ? ?
? ?
? return ? ((FARPROC)SysFunc1)(hdc,nXStart,nYStart,lpszString,cbString);} ? ?
? ?
?    2.由于系统鼠标钩子已经完成注入其它GUI进程的工作,我们不需要为注入再做工作。 ? ?
? ?
?    如果你知道所有系统钩子的函数必须要在动态库里,就不会对“注入”感到奇怪。当进程隐式或显式调用一个动态库里的函数时 ?
? ,系统都要把这个动态库映射到这个进程的虚拟地址空间里(以下简称“地址空间”)。这使得DLL成为进程的一部分,以这个进程的 ?
? 身份执行,使用这个进程的堆栈(见图1)。 ? ?
? ?
? ?
?    图1 ? DLL映射到虚拟地址空间中 ? ?
? ?
?    对系统钩子来说,系统自动将包含“钩子回调函数”的DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入 ?
? 了那些进程。 ? ?
? ?
?    3.当包含钩子的DLL注入其它进程后,寻找映射到这个进程虚拟内存里的各个模块(EXE和DLL)的基地址。EXE和DLL被映射到 ?
? 虚拟内存空间的什么地方是由它们的基地址决定的。它们的基地址是在链接时由链接器决定的。当你新建一个Win32工程时,VC++ ?
? 链接器使用缺省的基地址0x00400000。可以通过链接器的BASE选项改变模块的基地址。EXE通常被映射到虚拟内存的0x00400000处, ?
? DLL也随之有不同的基地址,通常被映射到不同进程的相同的虚拟地址空间处。 ? ?
? ?
?    如何知道EXE和DLL被映射到哪里了呢? ? ?
? ?
?    在Win32中,HMODULE和HINSTANCE是相同的。它们就是相应模块被装入进程的虚拟内存空间的基地址。比如: ? ?
? ?
?    HMODULE ? hmodule=GetModuleHandle(〃gdi32.dll〃); ? ?
? ?
?    返回的模块句柄强制转换为指针后,就是gdi32.dll被装入的基地址。 ? ?
? ?
?    关于如何找到虚拟内存空间映射了哪些DLL?我用如下方式实现: ? ?
? ?
? while(VirtualQuery ? (base, ? &mbi, ? sizeof ? (mbi))〉0) ? ?
? ?
? { ? if(mbi.Type==MEM—IMAGE) ? ?
? ?
? ChangeFuncEntry((DWORD)mbi.BaseAddress,1); ? ?
? ?
? base=(DWORD)mbi.BaseAddress+mbi.RegionSize; ? } ? ?
? ?
?    4.得到模块的基地址后,根据PE文件的格式穷举这个模块的IMAGE—IMPORT—DESCRIPTOR数组,看是否引入了gdi32.dll。 ?
? 如是,则穷举IMAGE—THUNK—DATA数组,看是否引入了TextOutA函数。 ? ?
? ?
?    5.如果找到,将其替换为相应的自己的函数。 ? ?
? ?
?    系统将EXE和DLL原封不动映射到虚拟内存空间中,它们在内存中的结构与磁盘上的静态文件结构是一样的。即PE ? (Portable ? Executable) ? 文件格式。 ? ?
? ?
?    所有对给定API函数的调用总是通过可执行文件的同一个地方转移。那就是一个模块(可以是EXE或DLL)的输入地址表(import ? address ? table)。那里有所有本模块调用的其它DLL的函数名及地址。对其它DLL的函数调用实际上只是跳转到输入地址表,由输入地址表再跳转到DLL真正的函数入口。例如: ? ?
? ?
? ?
?    图2 ? 对MessageBox()的调用跳转到输入地址表,从输入地址表再跳转到MessageBox函数 ? ?
? ?
? ?
? ?
?    IMAGE—IMPORT—DESCRIPTOR和IMAGE—THUNK—DATA分别对应于DLL和函数。它们是PE文件的输入地址表的格式(数据结构参见winnt.h)。 ? ?
? ?
?    BOOL ? ChangeFuncEntry(HMODULE ? hmodule) ? ?
? ?
?    { ? PIMAGE—DOS—HEADER ? pDOSHeader; ? ?
? ?
?    PIMAGE—NT—HEADERS ? pNTHeader; ? ?
? ?
?    PIMAGE—IMPORT—DESCRIPTOR ? pImportDesc; ? ?
? ?
? / ? get ? system ? functions ? and ? my ? functions′entry ? / ? ?
? ?
?    pSysFunc1=(DWORD)GetProcAddress(GetModuleHandle(〃gdi32.dll〃),〃TextOutA〃); ? ?
? ?
?    pMyFunc1= ? (DWORD)GetProcAddress(GetModuleHandle(〃hookdll.dll〃),〃MyTextOutA〃); ? ?
? ?
? pDOSHeader=(PIMAGE—DOS—HEADER)hmodule; ? ?
? ?
?    if ? (IsBadReadPtr(hmodule, ? sizeof(PIMAGE—NT—HEADERS))) ? ?
? ?
?    ? return ? FALSE; ? ?
? ?
?    if ? (pDOSHeader-〉e—magic ? != ? IMAGE—DOS—SIGNATURE) ? ?
? ?
?    ? return ? FALSE; ? ?
? ?
?    pNTHeader=(PIMAGE—NT—HEADERS)((DWORD)pDOSHeader+(DWORD)pDOSHeader-〉e—lfanew); ? ?
? ?
?    if ? (pNTHeader-〉Signature ? != ? IMAGE—NT—SIGNATURE) ? ?
? ?
?    ? return ? FALSE; ? ?
? ?
?    pImportDesc ? = ? (PIMAGE—IMPORT—DESCRIPTOR)((DWORD)hmodule+(DWORD)pNTHeader-〉OptionalHeader.DataDirectory ? ?
? ?
?    ? [IMAGE—DIRECTORY—ENTRY—IMPORT].VirtualAddress); ? ?
? ?
?    if ? (pImportDesc ? == ? (PIMAGE—IMPORT—DESCRIPTOR)pNTHeader) ? ?
? ?
? return ? FALSE; ? ?
? ?
?    while ? (pImportDesc-〉Name) ? ?
? ?
?    { ? PIMAGE—THUNK—DATA ? pThunk; ? ?
? ?
?    strcpy(buffer,(char ? )((DWORD)hmodule+(DWORD)pImportDesc-〉Name)); ? ?
? ?
? CharLower(buffer); ? ?
? ?
? if(strcmp(buffer,"gdi32.dll")) ? ?
? ?
? { ? pImportDesc++; ? ?
? ?
? continue; ? ?
? ?
? }else ? ?
? ?
? { ? pThunk=(PIMAGE—THUNK—DATA)((DWORD)hmodule+(DWORD)pImportDesc-〉FirstThunk); ? ?
? ?
? while ? (pThunk-〉u1.Function) ? ?
? ?
? { ? if ? ((pThunk-〉u1.Function) ? == ? pSysFunc1) ? ?
? ?
? { ? VirtualProtect((LPVOID)(&pThunk-〉u1.Function), ? ?
? ?
?    ? sizeof(DWORD),PAGE—EXECUTE—READWRITE, ? &dwProtect); ? ?
? ?
?    ? (pThunk-〉u1.Function)=pMyFunc1; ? ?
? ?
?    ? VirtualProtect((LPVOID)(&pThunk-〉u1.Function), ? sizeof(DWORD),dwProtect,&temp); ? } ? ?
? ?
? pThunk++; ? } ? return ? 1;}}} ? ?
? ?
?    替换了输入地址表中TextOutA的入口为MyTextOutA后,截获系统函数调用的主要部分已经完成,当一个被注入进程调用TextOutA时,其实调用的是MyTextOutA,只需在MyTextOutA中显示传进来的字符串,再交给TextOutA处理即可。 ?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值