Hook其他程序中的StringGrid的内容(内牛满面,终于找到了。)
2010-09-20 17:18
316 查看
Hook其他程序中的StringGrid的内容[转]
2009年05月28日 星期四 22:09
2009年05月28日 星期四 22:09
原贴见 http://www.delphibbs.com/delphibbs/dispq.asp?LID=2942729 1.根据StringGrid组件的句柄,想直接通过消息如WM_GETTEXT等来获取StringGrid的内容,显然不可行,普通的Windows消息不能直接获取到某个Cell的内容,TStringGrid并不是Windows的组件,而是Delphi自己的组件,它的Cell内容是存放在TStrings列表中的。 2.根据鼠标所在的位置,通过屏幕取词的技术,是可以Hook到鼠标下的某个Cell的内容,但在实际应用中也不可行,因为不是所有想Hook的Cell都是在显示区可见的,而ApiHook的屏幕取词技术要求Cell的文本重画,才能取得其内容。 既然上面两种方法都不可行,那么我们就要寻找新的方法。 1.思考 由于StringGrid是Delphi自写的组件,而不是Windows的控件,因此要获取StringGrid的某个Cell的内容,只能是获取到StringGrid的对象实例,才能以StringGrid.Cell[X, Y]这样的方式取得任意Cell的内容。 2.启发 在Delphi中,在自己的程序中,用FindControl,是可以根据组件对象的句柄获得对象实例的。那么我们在Hook其他程序的时候能不能采用这种方法来获取StringGrid对象的实例呢?这有个问题,即使我们能够获取到StringGrid的对象实例,但是返回的实例地址是个在其他程序进程地址空间的私有地址(<2GB),这在我们的程序中是无法进行访问的。这个问题不难解决,屏幕取词技术不也是截获到了其他程序的屏幕输出文本吗!? 3.实现 有了上面的思考和启发,那我们就能整理出一个思路来啦。 a.写一个DLL,将Hook StringGrid的代码都放在DLL中,在DLL中,还要包括GetMessage钩子的代码,目的是为了能通过全局钩子将DLL注入到目标程序,使Hook StringGrid的代码运行在目标进程中,这样就可以正确使用FindControl返回的StringGrid实例(也只有在目标进程内调用FindControl,才能够返回StringGrid实例地址)。 b.注入到目标进程的Hook功能,我们怎么进行控制呢?我们怎么让Hook代码知道我们要Hook哪个Cell的内容?怎么询问得知目标StringGrid的行数、列数,以进行正确的遍历获取Cell?... 通过内存映射进行Hook DLL和主程序的数据共享,就可以啦。不过这样实用时不是很方便,因为需要在目标进程中执行Hook代码,显然不能直接调用Hook DLL中的函数,在GetMessage钩子回调函数中来做,也不是很妥当,控制不方便。最好的方法就是在目标进程中创建一个隐形窗口,在该隐形窗口的消息处理中作文章。我们可以通过发送消息的方式通知隐形窗口,执行Hook代码。OK! c.按照上面的思路,我编写了HookSG.dll和测试程序,不过并没有Hook得到想要的结果。是哪里出了问题呢?分析上面的流程,最大的可能就是FindControl并返回实际的StringGrid对象实例,否则,后面的StringGrid.Cells[X, Y]这样的获取Cell内容的代码是断不会有问题的,我也能够确认Hook的代码是在目标进程中执行的。查看FindControl的源代码: function FindControl(Handle: HWnd): TWinControl; var OwningProcess: DWORD; begin Result := nil; if (Handle <> 0) and (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and (OwningProcess = GetCurrentProcessId) then // 都进行了判断调用进程ID是否为Handle所在进程 begin if GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom then Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom))) else Result := ObjectFromHWnd(Handle); end; end; function ObjectFromHWnd(Handle: HWnd): TWinControl; var OwningProcess: DWORD; begin if (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and (OwningProcess = GetCurrentProcessID) then Result := Pointer(SendMessage(Handle, RM_GetObjectInstance, 0, 0)) else Result := nil; end; 再看InitControls中: procedure InitControls; var UserHandle: HMODULE; begin WindowAtomString := Format('Delphi%.8X',[GetCurrentProcessID]); WindowAtom := GlobalAddAtom(PChar(WindowAtomString)); ControlAtomString := Format('ControlOfs%.8X%.8X', [HInstance, GetCurrentThreadID]); ControlAtom := GlobalAddAtom(PChar(ControlAtomString)); RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString)); ... end; 问题就在这里啦。ControlAtomString是根据模块句柄(模块加载基地址)和线程ID动态生成的,目标进程的模块基地址就是EXE基地址,一般是0x00400000,但DLL的模块加载基地址就不是这个了,默认是0x10000000,而实际上可能因为这个地址已经被占用(有其他DLL被加载到这个地址)而进行重定位,所以初始化时添加的Atom和目标进程的ControlAtom就不一样,FindControl当然就不能找到StringGrid对象实例啦。 清楚了这一点,解决起来就简单了,我们自己写个FindControl函数,以目标进程基地址来动态生成ControlAtomString,添加ControlAtom不就可以啦。在DLL中取EXE的基地址,用GetModuleHandle(nil)即可。 OK。解决了这些问题,Hook其他程序的StringGrid的内容就水到渠成,没什么障碍啦。 补充: 上面提到的方法,不仅仅可以Hook其他程序的StringGrid的内容,实际上还可以获取更多的从TWinControl继承的窗口组件的内容、属性、...,拥有了对象的实例,你基本上就拥有了对对象的完全控制。 |
相关文章推荐
- Hook或者API高手请进-跨进程获取其他程序的DBGrid内容(其它人做的程序)
- 经过网上查找,终于找到了选中文本本框的内容方法
- DELPHI 跨进程获取其他程序的DBGrid内容
- WIN API-VFP获得其他程序多个输入框的内容
- 由于某种特殊需求,我需要在winform程序中模拟鼠标点击事件,经过Google,终于找到了如下解决方案。
- 导出StringGrid内容到Excel
- 编写程序定义一个vector 对象,其每个元素都是指向string 类型的指针,读 取该vector 对象,输出每个string 的内容及其相应的长度。
- windows获取其他程序窗口的内容
- 对StringGrid输入一个数后对其他表格填充的代码
- 获得其他程序弹出菜单的内容(一个困扰许久的问题o(╯□╰)o)
- 截取其他程序文本框和密码框内容的一种实现方法
- 跨进程获取其他程序的DBGrid内容
- 截取其他程序文本框和密码框内容的一种实现方法
- 8.9 编写函数打开文件用于输入,将文件内容读入 string 类型的 vector 容器,每一行存储为该容器对象 的一个元素。8.10 重写上面的程序,把文件中的每个单词存储为 容器的一个元素
- 终于找到问题所在了,原来不是程序问题,而是数据质量问题
- 找了很久的低功耗蓝牙程序开发,终于在国外找到了部分资料
- 002一番寻找后,终于找到简单好用的利用runtime解决数组字典为nil时造成的程序崩溃的第三方
- 终于找到那段程序
- 获取其他程序中TreeView的内容
- 键盘hook,dll实现挂载到其他程序