屏幕取词技术系列讲座
2012-03-01 14:44
106 查看
转载:
亦东
(一)
很多人对这个问题感兴趣。
原因是这项技术让人感觉很神奇,也很有商业价值。
现在词典市场金山词霸占了绝对优势,所以再做字典也没什么前途了。我就是这么认为的,所以我虽然掌握了这项技术,却没去做字典软件。只做了一个和词霸相似的软件自己用,本来想拿出来做共享软件,但我的词库是“偷”来的,而且词汇不多,所以也就算了,词库太小,只能取词有什么用呢?而且词霸有共享版的。
但既然很多人想了解这项技术,我也不会保留。我准备分多次讲述这项技术的所有细节。
大约每周一两次。想知道的人就常常来看看吧!
一.基础知识
首先想编这种程序需要一些基础知识。
会用Vc++,包括16/32位。
精通Windows API特别是GDI,KERNEL部分。
懂汇编语言,会用softice调试程序,因为这种程序最好用softice调试。
二.基本原理
在Window 3.x时代,windows系统提供的字符输出函数只有很少的几个。
TextOut
ExtTextOut
DrawText
......
其中DrawText最终是用ExtTextOut实现的。
所以Windows的所有字符输出都是由调用TextOut和ExtTextOut实现的。因此,如果你可以修改这两个函数的入口,让程序先调用你自己的一个函数再调用系统的字符输出,你就可以得到Windows所有输出的字符了。
到了Windows95时代,原理基本没变,但是95比3.x要复杂。开始的时候,一些在windows3.x下编写的取词软件仍然可以是使用。但是后来出了个IE4,结果很多词典软件就因为不支持IE4而被淘汰了,但同时也给一些软件创造了机会,如金山词霸。其实IE4的问题并不复杂,只不过它的输出的是unicode字符,是用TextOutW和ExtTextOutW输出的。知道了这一点,只要也截取就可以了。不过实现方法复杂一点,以后会有详细讲解。现在又出了个IE5,结果词霸也不好用了,微软真是#^@#$%$*&^@#@..........
我研究后找到了一种解决办法,但还有些问题,有时会取错,正在继续研究,希望大家共同探讨。
另外还有WindowsNT,原理也是一样,只是实现方法和95下完全不同。
三.技术要点
要实现取词,主要要解决以下技术问题。
1.截取API入口,获得API的参数。
2.安全地潜入Windows内部,良好地兼容Windows的各个版本
3.计算鼠标所在的单词和字母。
4.如果你在Window95下,做32位程序,还涉及Windows32/16混合编程的技术。
今天先到这里吧!最好准备一份softice for 95/98和金山词霸,让我们先来分析一下别人是怎么做的。
欢迎与我联系
E-Mail:yeedong@163.net
Guest 1999-04-30 16:00:48
请问用VC自己的DEBUGGER不行吗?为什么要用SOFTICE? 我没用过SOFTICE,它有什么特别之处吗?
葫芦 1999-04-30 19:15:03
本人对这个问题也有兴趣,以前研究过16位版本截获TextOut和ExtTextOut的过程;
但对金山词霸,用Softice跟踪,发现SetWindowsHookEx在程序装载时就安装了鼠标钩子,暂停取字/恢复取字只是设置的内部变量,但本人发现金山词霸并没有象16位版本那样修改TextOut和ExtTextOut。
苍蝇 (555021552) 1999-05-02 08:56:57
有哪位大虾愿意先介绍一下SOFTICE?
蟑螂 1999-05-04 13:58:22
把金山词霸的cjktl95.dll用tdump分析可以看到它根本用的不是hook,而是用了一些kernel32.dll中的Win32 SDK里没有包含的函数,使用这些函数来替换改写原先的几个GDI函数。看来是Win95未公开的一些东西。有些人知道,为什么不肯说出来呢?未必见得多么高深!
葫芦 1999-05-05 23:28:07
你可能没有研究过它的目标代码,怎么能断言没有使用hook呢? 其实金山词霸一运行就安装了鼠标钩子。
亦东 1999-05-07 09:52:42
未必见得多么高深?
你知道有些人是怎么知道这些Win95未公开的东西的吗?你不会是以为微软偷偷告诉他们的吧?其实他们大多和我一样是用softice自己跟踪Win95跟出来的。
还有你从cjktl95.dll里tdump出的未公开函数和hook无关,那是做别的用的。
setwindowshook在user里
亦东 1999-05-10 16:16:14
从cjktl95.dll里tdump出的未公开函数和32位和16位之间的互调有关。
主题 屏幕取词技术系列讲座(二)
作者 亦东
很抱歉让大家久等了!
我看了一些人的回帖,发现很多人对取词的原理还是不太清楚。
首先我来解释一下hook问题。词霸中的确用到了hook,而且他用了两种hook其中一种是Windows标准hook,通过SetWindowHook安装一个回调函数,它安装了一个鼠标hook,是为了可以及时响应鼠标的消息用的和取词没太大关系。
另一种钩子是API钩子,这才是取词的核心技术所在。他在TextOut等函数的开头写了一个jmp语句,跳转到自己的代码里。
你用softice看不到这个跳转语句是因为它只在取词的一瞬间才存在,平时是没有的。
你可以在TextOut开头设一个读写断点
bpm textout
再取词,就会找到词霸用来写钩子的代码了。
/**********************************
所以我在次强调,想学这种技术一定要懂汇编语言和熟练使用softice.
**********************************/
至于从cjktl95中dump出来的未公开函数是和Windows32/16混合编程有关的,以后我会提到他们。
我先来讲述取词的过程,
0 判断鼠标是否在一个地方停留了一段时间
1 取得鼠标当前位置
2 以鼠标位置为中心生成一个矩形
3 挂上API钩子
4 让这个矩形产生重画消息
5 在钩子里等输出字符
6 计算鼠标在哪个单词上面,把这个单词保存下来
7 如果得到单词则摘掉API钩子,在一段时间后,无论是否得到单词都摘掉API钩子
8 用单词查词库,显示解释框。
很多步骤实现起来都有一些难度,所以在中国可以做一个完善的取词词典的人屈指可数。
其中0,1,2,7,8比较简单就不提了。
先说如何挂钩子:
所谓钩子其实就是在WindowsAPI入口写一个JMP XXXX:XXXX语句,跳转到自己的代码里。
步骤如下:
1.取得Windows API入口,用GetProcAddress实现
2.保存API入口的前五个字节,因为JMP是0xEA,地址是4个字节
3.写入跳转语句
这步最复杂
Windows的代码段本来是不可以写的,但是Microsoft给自己留了个后门。
有一个未公开函数是AllocCsToDsAlias,
UINT WINAPI ALLOCCSTODSALIAS(UINT);
你可以取到这个函数的入口,把API的代码段的选择符(要是不知道什么是选择符,就先去学学保护模式编程吧)传给他,他会返回一个可写的数据段选择符。这个选择符用完要释放的。用新选择符和API入口的偏移量合成一个指针就可以写windows的代码段了。
这就是取词技术的最核心的东东,不止取词,连外挂中文平台全屏汉化都是使用的这种技术。现在知道为什么这么简单的几句话却很少知道了吧?因为太多的产品使用他,太多的公司靠他赚钱了。
这些公司和产品有:中文之星,四通利方,南极星,金山词霸,实达铭泰的东方快车,roboword,译典通,即时汉化专家等等等等。。。。还有至少20多家小公司。他们的具体实现虽然不同,但大致原理是相同的。
我这些都是随手写的,也没有提纲之类的东西,以后如果有机会我会整理一下,大家先凑合着看吧!xixi...
葫芦 1999-05-06 14:52:30
你说的这个技术是16位的,至少金山词霸III没有采用16位的AllocCsToDsAlias函数,也根本没有修改TextOut开始的语句为JMP XXXXXXXX。softice本人非常精通,是绝对不会错的!
葫芦 1999-05-06 15:38:40
谁假冒吾名,坏吾名声?!本人在此郑重宣布,以上贴子非本人所发!
经过跟踪分析,金山词霸III确实修改了TextOut的入口为转跳到自身代码的JMP XXXXXXXX语句,只是修改没有调用AllocCsToDsAlias,也不是在取字时才去修改,而是常常修改(估计是在Timer中进行的)。
接上帖:
nn_zdm (555031742) 1999-05-18 14:14:19
上面写漏了,应是
WriteProcessMemory(..., "LoadLibrary(..., "mydll.dll ",..). ");
CreateRemoteThread(...) ;
主题 关于屏幕取词的讨论(三)
作者 亦东
让大家久等,很抱歉,前些时候工作忙硬盘又坏了,太不幸了。
这回来点真格的。
咱们以截取TextOut为例。
下面是代码:
//截取TextOut
typedef UINT (WINAPI* ALLOCCSTODSALIAS)(UINT);
ALLOCCSTODSALIAS AllocCsToDsAlias;
BYTE NewValue[5];//保存新的入口代码
BYTE OldValue[5];//API原来的入口代码
unsigned char * Address=NULL;//可写的API入口地址
UINT DsSelector=NULL;//指向API入口的可写的选择符
WORD OffSetEntry=NULL;//API的偏移量
BOOL bHookAlready = FALSE; //是否挂钩子的标志
BOOL InitHook()
{
HMODULE hKernel,hGdi;
hKernel = GetModuleHandle( "Kernel ");
if(hKernel==NULL)
return FALSE;
AllocCsToDsAlias = (ALLOCCSTODSALIAS)GetProcAddress(hKernel, "AllocCsToDsAlias ");//这是未公开的API所以要这样取地址
if(AllocCsToDsAlias==NULL)
return FALSE;
hGdi = GetModuleHandle( "Gdi ");
if(hmGdi==NULL)
return FALSE;
FARPROC Entry = GetProcAddress(hGdi, "TextOut ");
if(Entry==NULL)
return FALSE;
OffSetEntry = (WORD)(FP_OFF(Entry));//取得API代码段的选择符
DsSelector = AllocCsToDsAlias(FP_SEG(Entry));//分配一个等同的可写的选择符
Address = (unsigned char*)MK_FP(DsSelector,OffSetEntry);//合成地址
NewValue[0]=0xEA;
*((DWORD*)(NewValue+1)) = (DWORD)MyTextOut;
OldValue[0]=Address[0];
*((DWORD*)(OldValue+1)) = *((DWORD*)(Address+1));
}
BOOL ClearHook()
{
if(bHookAlready)
HookOff();
FreeSelector(DsSelector);
}
BOOL HookOn()
{
if(!bHookAlready){
for(int i=0;i <5;i++){
Address[i]=NewValue[i];
}
bHookAlready=TRUE;
}
}
BOOL HookOff()
{
if(bHookAlready){
for(int i=0;i <5;i++){
Address[i]=OldValue[i];
}
bHookAlready=FALSE;
}
}
//钩子函数,一定要和API有相同的参数和声明
BOOL WINAPI MyTextOut(HDC hdc,int nXStart,int nYStart,LPCSTR lpszString,UINT cbString)
{
BOOL ret;
HookOff();
ret = TextOut(hdc,nXStart,nYStart,lpszString,cbString);//调原来的TextOut
HookOn();
return ret;
}
上面的代码是一个最简单的挂API钩子的例子,我要提醒大家的是,这段代码是我凭记忆写的,我以前的代码丢了,我没有编译测试过
因为我没有VC++1.52.所以代码可能会有错。
建议使用Borland c++,按16位编译。
如果用VC++1.52,则要改个选项
在VC++1.52的Option里,有个内存模式的设置,选大模式,和 "DS!=SS DS Load on Function entry. ",切记,否则会系统崩溃。
有什么不明白的可以给我写信
yeedong@163.net
Guest 1999-05-21 22:20:47
你这是16为的地址存取模式吧
你看这个MK_FP,win32不用了,
而且GetProcAddress(hKernel, "AllocCsToDsAlias ")
这个API有用吗?
sorry
Guest 1999-05-21 22:31:47
亦东,想请教一个问题,
win32下,每个process有
自己的地址空间,process
A得到process B 的一个窗口C的handle,这个
handle的值 等于process B自己得到的window C 的handle值 吗?
我想应该不相等,但系统是如何转换的呢?(比如process A 向
window C 发消息,系统如何
知道process A 里的handle 和process B 里的
handle 都是指的window C)
. 是不是用duplicatehandle()?
(声明,我是真的不知道)
亦东 1999-05-21 22:54:48
这段代码就是十六位的。
你用Win32根本就不能编译。
32位没有AllocCsToDsAlias,因为在32位里不能写系统代码段(其实有办法,不是这样,不过比较麻烦)。
系统代码都在0x80000000以上,都是只读的。
所以要截WinAPI只能用16位的代码。
每个Process有自己的地址空间没错,但Window的句柄是共享的,同一个窗口在任何进程里的句柄都是一样的。
你可以在自己的进程里向任何窗口发消息。
Window的句柄很多,有的是共享的有的不是,
我也不知道那里有说明,一般是凭经验或试试看。
GUEST 1999-05-22 20:51:51
如果 window handle 换成
moudle handle呢?我
用moudlefirst,moudlenext遍历
得到的某个moudle 的句柄,
在任何一个process 中得到的
这个moudle handle 都是一样的值吗。(这个handle 和进程地址空间无关吗?)。
thx
亦东 1999-05-23 22:31:59
绝对有关
在Win32里module handle就是模块的起始地址。
说起来比较复杂
在95和NT里有些不同
在Win32里,每个模块(DLL,EXE)有一个ImageBase,这个数存放在DLL和EXE的文件头里。每个模块通常是不一样的。当Windows加载这个模块时优先考虑把模块放到Imagebase指定的地址,但有时会出现两个模块的地址重叠会有冲突,Windows会把模块移到与Imagebase最近的地址。所以Imagebase相同的模块在不同进程可能会在不同的地址上。这个地址就是module handle.Imagebase是可以在编译时指定的。
你用moudlefirst,moudlenext遍历得到的module handle是和进程有关的。
比如:你编了一个Imagebase为0x10000000的DLL A,进程A调用这个DLL A,在进程A里这个DLL被加载到地址0x10000000处,他的module handle为0x10000000,进程B也调用这个DLL A,但是进程B还调用另外一个DLL B,这另外的DLL B也是Imagebase为0x10000000的而且先加载,这是进程B的这个DLL A可能就被加载到0x13000000了,DLL A在进程B里的module handle 就是0x13000000了。
在95下,模块是共享的,也就是Windows只加载一份模块到内存,所有用到这个模块的进程都映射同一个模块,也就是说在95里每个模块在物理内存里只有一份。NT则不同,他为每个进程都加载一份模块。所以NT比95需要的内存多。所以在NT里不但在不同进程里的Module handle可能不同,连物理地址都是不同的。
yeedong@163.net
亦东
(一)
很多人对这个问题感兴趣。
原因是这项技术让人感觉很神奇,也很有商业价值。
现在词典市场金山词霸占了绝对优势,所以再做字典也没什么前途了。我就是这么认为的,所以我虽然掌握了这项技术,却没去做字典软件。只做了一个和词霸相似的软件自己用,本来想拿出来做共享软件,但我的词库是“偷”来的,而且词汇不多,所以也就算了,词库太小,只能取词有什么用呢?而且词霸有共享版的。
但既然很多人想了解这项技术,我也不会保留。我准备分多次讲述这项技术的所有细节。
大约每周一两次。想知道的人就常常来看看吧!
一.基础知识
首先想编这种程序需要一些基础知识。
会用Vc++,包括16/32位。
精通Windows API特别是GDI,KERNEL部分。
懂汇编语言,会用softice调试程序,因为这种程序最好用softice调试。
二.基本原理
在Window 3.x时代,windows系统提供的字符输出函数只有很少的几个。
TextOut
ExtTextOut
DrawText
......
其中DrawText最终是用ExtTextOut实现的。
所以Windows的所有字符输出都是由调用TextOut和ExtTextOut实现的。因此,如果你可以修改这两个函数的入口,让程序先调用你自己的一个函数再调用系统的字符输出,你就可以得到Windows所有输出的字符了。
到了Windows95时代,原理基本没变,但是95比3.x要复杂。开始的时候,一些在windows3.x下编写的取词软件仍然可以是使用。但是后来出了个IE4,结果很多词典软件就因为不支持IE4而被淘汰了,但同时也给一些软件创造了机会,如金山词霸。其实IE4的问题并不复杂,只不过它的输出的是unicode字符,是用TextOutW和ExtTextOutW输出的。知道了这一点,只要也截取就可以了。不过实现方法复杂一点,以后会有详细讲解。现在又出了个IE5,结果词霸也不好用了,微软真是#^@#$%$*&^@#@..........
我研究后找到了一种解决办法,但还有些问题,有时会取错,正在继续研究,希望大家共同探讨。
另外还有WindowsNT,原理也是一样,只是实现方法和95下完全不同。
三.技术要点
要实现取词,主要要解决以下技术问题。
1.截取API入口,获得API的参数。
2.安全地潜入Windows内部,良好地兼容Windows的各个版本
3.计算鼠标所在的单词和字母。
4.如果你在Window95下,做32位程序,还涉及Windows32/16混合编程的技术。
今天先到这里吧!最好准备一份softice for 95/98和金山词霸,让我们先来分析一下别人是怎么做的。
欢迎与我联系
E-Mail:yeedong@163.net
Guest 1999-04-30 16:00:48
请问用VC自己的DEBUGGER不行吗?为什么要用SOFTICE? 我没用过SOFTICE,它有什么特别之处吗?
葫芦 1999-04-30 19:15:03
本人对这个问题也有兴趣,以前研究过16位版本截获TextOut和ExtTextOut的过程;
但对金山词霸,用Softice跟踪,发现SetWindowsHookEx在程序装载时就安装了鼠标钩子,暂停取字/恢复取字只是设置的内部变量,但本人发现金山词霸并没有象16位版本那样修改TextOut和ExtTextOut。
苍蝇 (555021552) 1999-05-02 08:56:57
有哪位大虾愿意先介绍一下SOFTICE?
蟑螂 1999-05-04 13:58:22
把金山词霸的cjktl95.dll用tdump分析可以看到它根本用的不是hook,而是用了一些kernel32.dll中的Win32 SDK里没有包含的函数,使用这些函数来替换改写原先的几个GDI函数。看来是Win95未公开的一些东西。有些人知道,为什么不肯说出来呢?未必见得多么高深!
葫芦 1999-05-05 23:28:07
你可能没有研究过它的目标代码,怎么能断言没有使用hook呢? 其实金山词霸一运行就安装了鼠标钩子。
亦东 1999-05-07 09:52:42
未必见得多么高深?
你知道有些人是怎么知道这些Win95未公开的东西的吗?你不会是以为微软偷偷告诉他们的吧?其实他们大多和我一样是用softice自己跟踪Win95跟出来的。
还有你从cjktl95.dll里tdump出的未公开函数和hook无关,那是做别的用的。
setwindowshook在user里
亦东 1999-05-10 16:16:14
从cjktl95.dll里tdump出的未公开函数和32位和16位之间的互调有关。
主题 屏幕取词技术系列讲座(二)
作者 亦东
很抱歉让大家久等了!
我看了一些人的回帖,发现很多人对取词的原理还是不太清楚。
首先我来解释一下hook问题。词霸中的确用到了hook,而且他用了两种hook其中一种是Windows标准hook,通过SetWindowHook安装一个回调函数,它安装了一个鼠标hook,是为了可以及时响应鼠标的消息用的和取词没太大关系。
另一种钩子是API钩子,这才是取词的核心技术所在。他在TextOut等函数的开头写了一个jmp语句,跳转到自己的代码里。
你用softice看不到这个跳转语句是因为它只在取词的一瞬间才存在,平时是没有的。
你可以在TextOut开头设一个读写断点
bpm textout
再取词,就会找到词霸用来写钩子的代码了。
/**********************************
所以我在次强调,想学这种技术一定要懂汇编语言和熟练使用softice.
**********************************/
至于从cjktl95中dump出来的未公开函数是和Windows32/16混合编程有关的,以后我会提到他们。
我先来讲述取词的过程,
0 判断鼠标是否在一个地方停留了一段时间
1 取得鼠标当前位置
2 以鼠标位置为中心生成一个矩形
3 挂上API钩子
4 让这个矩形产生重画消息
5 在钩子里等输出字符
6 计算鼠标在哪个单词上面,把这个单词保存下来
7 如果得到单词则摘掉API钩子,在一段时间后,无论是否得到单词都摘掉API钩子
8 用单词查词库,显示解释框。
很多步骤实现起来都有一些难度,所以在中国可以做一个完善的取词词典的人屈指可数。
其中0,1,2,7,8比较简单就不提了。
先说如何挂钩子:
所谓钩子其实就是在WindowsAPI入口写一个JMP XXXX:XXXX语句,跳转到自己的代码里。
步骤如下:
1.取得Windows API入口,用GetProcAddress实现
2.保存API入口的前五个字节,因为JMP是0xEA,地址是4个字节
3.写入跳转语句
这步最复杂
Windows的代码段本来是不可以写的,但是Microsoft给自己留了个后门。
有一个未公开函数是AllocCsToDsAlias,
UINT WINAPI ALLOCCSTODSALIAS(UINT);
你可以取到这个函数的入口,把API的代码段的选择符(要是不知道什么是选择符,就先去学学保护模式编程吧)传给他,他会返回一个可写的数据段选择符。这个选择符用完要释放的。用新选择符和API入口的偏移量合成一个指针就可以写windows的代码段了。
这就是取词技术的最核心的东东,不止取词,连外挂中文平台全屏汉化都是使用的这种技术。现在知道为什么这么简单的几句话却很少知道了吧?因为太多的产品使用他,太多的公司靠他赚钱了。
这些公司和产品有:中文之星,四通利方,南极星,金山词霸,实达铭泰的东方快车,roboword,译典通,即时汉化专家等等等等。。。。还有至少20多家小公司。他们的具体实现虽然不同,但大致原理是相同的。
我这些都是随手写的,也没有提纲之类的东西,以后如果有机会我会整理一下,大家先凑合着看吧!xixi...
葫芦 1999-05-06 14:52:30
你说的这个技术是16位的,至少金山词霸III没有采用16位的AllocCsToDsAlias函数,也根本没有修改TextOut开始的语句为JMP XXXXXXXX。softice本人非常精通,是绝对不会错的!
葫芦 1999-05-06 15:38:40
谁假冒吾名,坏吾名声?!本人在此郑重宣布,以上贴子非本人所发!
经过跟踪分析,金山词霸III确实修改了TextOut的入口为转跳到自身代码的JMP XXXXXXXX语句,只是修改没有调用AllocCsToDsAlias,也不是在取字时才去修改,而是常常修改(估计是在Timer中进行的)。
接上帖:
nn_zdm (555031742) 1999-05-18 14:14:19
上面写漏了,应是
WriteProcessMemory(..., "LoadLibrary(..., "mydll.dll ",..). ");
CreateRemoteThread(...) ;
主题 关于屏幕取词的讨论(三)
作者 亦东
让大家久等,很抱歉,前些时候工作忙硬盘又坏了,太不幸了。
这回来点真格的。
咱们以截取TextOut为例。
下面是代码:
//截取TextOut
typedef UINT (WINAPI* ALLOCCSTODSALIAS)(UINT);
ALLOCCSTODSALIAS AllocCsToDsAlias;
BYTE NewValue[5];//保存新的入口代码
BYTE OldValue[5];//API原来的入口代码
unsigned char * Address=NULL;//可写的API入口地址
UINT DsSelector=NULL;//指向API入口的可写的选择符
WORD OffSetEntry=NULL;//API的偏移量
BOOL bHookAlready = FALSE; //是否挂钩子的标志
BOOL InitHook()
{
HMODULE hKernel,hGdi;
hKernel = GetModuleHandle( "Kernel ");
if(hKernel==NULL)
return FALSE;
AllocCsToDsAlias = (ALLOCCSTODSALIAS)GetProcAddress(hKernel, "AllocCsToDsAlias ");//这是未公开的API所以要这样取地址
if(AllocCsToDsAlias==NULL)
return FALSE;
hGdi = GetModuleHandle( "Gdi ");
if(hmGdi==NULL)
return FALSE;
FARPROC Entry = GetProcAddress(hGdi, "TextOut ");
if(Entry==NULL)
return FALSE;
OffSetEntry = (WORD)(FP_OFF(Entry));//取得API代码段的选择符
DsSelector = AllocCsToDsAlias(FP_SEG(Entry));//分配一个等同的可写的选择符
Address = (unsigned char*)MK_FP(DsSelector,OffSetEntry);//合成地址
NewValue[0]=0xEA;
*((DWORD*)(NewValue+1)) = (DWORD)MyTextOut;
OldValue[0]=Address[0];
*((DWORD*)(OldValue+1)) = *((DWORD*)(Address+1));
}
BOOL ClearHook()
{
if(bHookAlready)
HookOff();
FreeSelector(DsSelector);
}
BOOL HookOn()
{
if(!bHookAlready){
for(int i=0;i <5;i++){
Address[i]=NewValue[i];
}
bHookAlready=TRUE;
}
}
BOOL HookOff()
{
if(bHookAlready){
for(int i=0;i <5;i++){
Address[i]=OldValue[i];
}
bHookAlready=FALSE;
}
}
//钩子函数,一定要和API有相同的参数和声明
BOOL WINAPI MyTextOut(HDC hdc,int nXStart,int nYStart,LPCSTR lpszString,UINT cbString)
{
BOOL ret;
HookOff();
ret = TextOut(hdc,nXStart,nYStart,lpszString,cbString);//调原来的TextOut
HookOn();
return ret;
}
上面的代码是一个最简单的挂API钩子的例子,我要提醒大家的是,这段代码是我凭记忆写的,我以前的代码丢了,我没有编译测试过
因为我没有VC++1.52.所以代码可能会有错。
建议使用Borland c++,按16位编译。
如果用VC++1.52,则要改个选项
在VC++1.52的Option里,有个内存模式的设置,选大模式,和 "DS!=SS DS Load on Function entry. ",切记,否则会系统崩溃。
有什么不明白的可以给我写信
yeedong@163.net
Guest 1999-05-21 22:20:47
你这是16为的地址存取模式吧
你看这个MK_FP,win32不用了,
而且GetProcAddress(hKernel, "AllocCsToDsAlias ")
这个API有用吗?
sorry
Guest 1999-05-21 22:31:47
亦东,想请教一个问题,
win32下,每个process有
自己的地址空间,process
A得到process B 的一个窗口C的handle,这个
handle的值 等于process B自己得到的window C 的handle值 吗?
我想应该不相等,但系统是如何转换的呢?(比如process A 向
window C 发消息,系统如何
知道process A 里的handle 和process B 里的
handle 都是指的window C)
. 是不是用duplicatehandle()?
(声明,我是真的不知道)
亦东 1999-05-21 22:54:48
这段代码就是十六位的。
你用Win32根本就不能编译。
32位没有AllocCsToDsAlias,因为在32位里不能写系统代码段(其实有办法,不是这样,不过比较麻烦)。
系统代码都在0x80000000以上,都是只读的。
所以要截WinAPI只能用16位的代码。
每个Process有自己的地址空间没错,但Window的句柄是共享的,同一个窗口在任何进程里的句柄都是一样的。
你可以在自己的进程里向任何窗口发消息。
Window的句柄很多,有的是共享的有的不是,
我也不知道那里有说明,一般是凭经验或试试看。
GUEST 1999-05-22 20:51:51
如果 window handle 换成
moudle handle呢?我
用moudlefirst,moudlenext遍历
得到的某个moudle 的句柄,
在任何一个process 中得到的
这个moudle handle 都是一样的值吗。(这个handle 和进程地址空间无关吗?)。
thx
亦东 1999-05-23 22:31:59
绝对有关
在Win32里module handle就是模块的起始地址。
说起来比较复杂
在95和NT里有些不同
在Win32里,每个模块(DLL,EXE)有一个ImageBase,这个数存放在DLL和EXE的文件头里。每个模块通常是不一样的。当Windows加载这个模块时优先考虑把模块放到Imagebase指定的地址,但有时会出现两个模块的地址重叠会有冲突,Windows会把模块移到与Imagebase最近的地址。所以Imagebase相同的模块在不同进程可能会在不同的地址上。这个地址就是module handle.Imagebase是可以在编译时指定的。
你用moudlefirst,moudlenext遍历得到的module handle是和进程有关的。
比如:你编了一个Imagebase为0x10000000的DLL A,进程A调用这个DLL A,在进程A里这个DLL被加载到地址0x10000000处,他的module handle为0x10000000,进程B也调用这个DLL A,但是进程B还调用另外一个DLL B,这另外的DLL B也是Imagebase为0x10000000的而且先加载,这是进程B的这个DLL A可能就被加载到0x13000000了,DLL A在进程B里的module handle 就是0x13000000了。
在95下,模块是共享的,也就是Windows只加载一份模块到内存,所有用到这个模块的进程都映射同一个模块,也就是说在95里每个模块在物理内存里只有一份。NT则不同,他为每个进程都加载一份模块。所以NT比95需要的内存多。所以在NT里不但在不同进程里的Module handle可能不同,连物理地址都是不同的。
yeedong@163.net
相关文章推荐
- Android系列讲座(1):Notification 与状态栏信息
- 理解终端复用器tmux系列讲座
- 【软件测试自动化-QTP系列讲座 38】== 自定义场景恢复RecoveryFunction ==
- 2014年系列技术讲座之基于大数据的数据挖掘
- 【软件测试自动化-QTP系列讲座 41】== 强制获取文本相对坐标 ==
- 2014年系列技术讲座之项目群管理模式改进及效果
- MySQL查询优化系列讲座之查询优化器
- 【软件测试自动化-QTP系列讲座 17】 == 揭开QTP的神秘面纱 (四)插件开发 == (入门篇)
- MySQL查询优化系列讲座之调度和锁定
- SEO相关软件和工具评测系列讲座(一)笔记
- Intel并行编程及软件工具系列讲座观看指南
- Intel并行编程及软件工具系列讲座观看指南
- IT战略规划之流程再造 —2013年中科院计算所培训中心系列公益讲座
- 【软件测试自动化-QTP系列讲座 39】== 注册异类子控件强制注入开启HOOK ==
- Geodatabase and ArcSDE 系列讲座
- Android系列学习讲座之一--为App签名(为apk签名)
- unity3D游戏开发实战原创视频讲座系列13之帽子戏法游戏开发(预告)
- 【软件测试自动化-QTP系列讲座 40】== 创建多个QTP实例 ==
- 微软开发者系列讲座下载
- C#语言系列讲座(15) 特 征