在 Windows中,每个进程有自己的私有地址空间。当我们用指针来引用内存的时候,指针的值表示的是进程自己的地址空间中的一个内存地址。进程不能创建一个指针来引用属于其它进程的内存。因此,如果进程有一个缺陷会覆盖随机地址处的内存,那么这个缺陷不会影响到其它进程所使用的内存。 独立的地址空间对开发人员和用户都是非常有利的。对开发人员来说,系统更有可能捕获错误的内存读/写。对用户来说,操作系统变得更加健壮了,因为一个应用程序的错误不会导致其它应用程序或操作系统崩溃。当然,这样的健壮性也是要付出代价的,因为它使我们很难编写能够与其它进程通信的应用程序或对其它进程进行操控的应用程序。 应用程序需要跨越进程边界来访问另一个进程的地址空间的情况如下:
- 我们想要从另一个进程创建的窗口派生子类窗口
- 我们需要一些手段来辅助调试——例如,我们需要确定另一个进程正在使用哪些DLL
- 我们想要给另一个进程安装挂钩
- 我们的DLL只会被映射到那些使用了User.dll的进程中。所有基于GUI的应用程序都使用了User.dll,但大多数基于CUI的应用程序都不会使用它。
- 我们的DLL回被映射到每个基于GUI的应用程序中,但我们可能只想把DLL注入到一个或少数几个应用程序中。
- 我们的DLL回被映射到每个基于GUI的应用程序中,在应用程序终止之前,它将一直存在于进程的地址空间中。
HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, pfnThreadRtn, L"C://MyLib.dll", 0, NULL); "C://MyLib.dll" 位于调用进程的地址空间中 ,我们把这个地址传给新创建的远程线程,远程线程去访问这个内存地址的时候,DLL的路径字符串并不在那里,远程进程的线程很可能会引发访问违规。为了解决这个问题,我们需要把DLL得路径字符串存放到远程进程的地址空间中去。我们可以调用VirtualAllocEx在远程进程的地址空间中为字符串分配一块内存,再把字符串从进程的地址空间复制到远程进程的地址空间中。 BOOL ReadProcessMemory( HANDLE hProcess, LPCVOID pvAddressRemote, PVOID pvBufferLocal, SIZE_T dwSize, SIZE_T* pdwNumBytesRead); BOOL WriteProcessMemory( HANDLE hProcess, PVOID pvAddressRemote, LPCVOID pvBufferLocal, SIZE_T dwSize, SIZE_T* pdwNumBytesWritten); 让我们总结一下必须采取的步骤: 1)用VirtualAllocEx 函数在远程进程的地址空间中分配一块内存。 2)用 WriteProcessMemory 函数把DLL的路径名复制到第1步分配的内存中。 3)用GetProcAddress 函数来得到LoadLibraryW 或LoadLibraryA 函数(在Kernel32.dll中)的实际地址。 4)用 CreateRemoteThread 函数在远程进程中创建一个线程,让新线程调用正确的LoadLibrary函数并在参数中传 入第1步分配的内存地址。这时,DLL已经被注入到远程进程的地址空间中,DLL的DllMain函数会收到 DLL_PROCESS_ATTACH 通知并且可以执行我们想要执行的代码。当DllMain返回的时候,远程线程会 从LoadLibraryW/A调用返回到BaseThreadStart函数。 BaseThreadStart函数然后调用ExitThread,使远程线程 终止。 现在远程进程中有一块内存,它是我们在第1步分配的,DLL也还在远程进程的地址空间中。为了对它们进程清理,我们需要在远程线程退出之后执行后续步骤。 5)用VirtualFreeEx来释放第1步分配的内存。 6)用GetProcAddress来得到FreeLibrary函数的实际地址。 7)用CreateRemoteThread函数在远程进程中创建一个线程,让该线程调用FreeLibrary函数并在参数中传入远程 DLL的HMODULE。 5.使用木马DLL来注入DLL 注入DLL的另一种方式是,把我们知道的进程必然会载入的一个DLL替换掉。
- 修改DLL的名称
- 修改应用程序的.exe模块的导入段。
7.使用CreateProcess来注入代码
8.API拦截的一个例子
- 通过覆盖代码来拦截API
- 通过修改模块的导入段来拦截API
通过覆盖代码来拦截API
1.定位要焊接的函数,得到它的内存地址;
2.把这个函数起始的几个字节保存到我们自己的内存中;
3.用CPU的一条JUMP指令来覆盖这个函数其实的几个字节,这条JUMP指令用来跳转到我们的替代函数的内存地址。我们的替代函数签名必须与要拦截的函数的函数签名完全相同:所有的参数必须相同,返回值必须相同,调用约定也必须相同。
4.当线程调用被拦截函数的时候,跳转指令实际上会跳转到我们的替代函数,这时,我们就可以执行自己想要执行的任何代码。
5.为了撤销对函数的拦截,我们必须把2中保存下来的字节放回被拦截函数起始的几个字节中。
6.我们调用被拦截函数,让该函数执行它的正常处理。
7.当原来的函数返回时,我们再次执行2、3,这样我们的替代函数将来还会被调用到。
这种方法已经基本过时淘汰,它对CPU有依赖性,而且这在抢占式、多线程环境中根本不能工作。
通过修改模块的导入段来拦截API
这种方法不仅容易实现,而且也相当健壮。我们从模块的导入段说起。。。
一个模块的导入段包含一组DLL,为了能让模块运行,这些DLL是必须的。此外,导入段还包括一个符号表,其中列出了该模块从各DLL中导入的符号。当该模块调用一个导入函数的时候,线程实际上会先从模块的导入表中得到相应的导入函数的地址,然后再跳转到那个地址。
因此,为了拦截一个特定的函数,我们所需要做的就是修改它在模块的导入段中的地址。
完全不存在对CPU的依赖性,而且由于我们并没有修改函数的代码,不必担心线程同步的问题。
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (0)
站点信息
- 文章2300
- 用户1336
- 访客10859735
每日一句
True success inspires others to act.
真正的成功是激励他人行动。
真正的成功是激励他人行动。
语法错误: 意外的令牌“标识符”
全面理解Gradle - 定义Task
Motrix全能下载工具 (支持 BT / 磁力链 / 百度网盘)
谷歌Pixel正在开始起飞?
获取ElementUI Table排序后的数据
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is
亲测!虚拟机VirtualBox安装MAC OS 10.12图文教程
华为手机app闪退重启界面清空log日志问题
android ndk开发之asm/page.h: not found
手机屏幕碎了怎么备份操作?
免ROOT实现模拟点击任意位置
新手必看修改DSDT教程
thinkpad t470p装黑苹果系统10.13.2
新会员