首页 > 编程知识 正文

win10抓包工具,微软流服务代理

时间:2023-05-06 14:31:41 阅读:137522 作者:3059

我们拦截并执行函数的最直接的目的是为函数添加功能、修改返回值、添加额外的代码用于调试和性能测试、拦截并研究、解密和使用函数的输入输出。 通过访问源代码,可以使用重建操作系统和APP应用程序的方法,在它们之间插入新的功能和扩展功能。 但是,在当今商业化的开发世界,以及只公开二进制代码的系统中,研究者很少有机会获得源代码。 本文主要介绍了基于Windows二进制PE文件的Detour的API侦听技术。 在Linux平台上,此操作非常简单,因为最初的操作系统设计者引入了LD_PRELOAD。 如果设置LD_PRELOAD=mylib.so,则APP应用程序在加载dll时会检查mylib.so的符号表,并在relocation时优先使用mylib.so的symbol。 如果mylib.so具有printf (),则此printf将替代libc中的printf。 这个mylib.so printf可以直接访问libc.so的printf函数指针,以获取真正的printf条目地址。 这样,所有dll的API HOOK都在loader加载dll时完成,非常自然,所有与平台相关的部分都交给loader处理。

一. Detour开发库:

个人资料

Detours是一个用于在x86平台上侦听任何Win32函数调用的工具库。 中断代码可以在运行时动态加载。 Detours用无条件转移指令替换目标函数的前几个指令,并将控制流移动到用户提供的拦截函数。 目标函数中的某些指令保存在一个名为“trampoline”(译注:英语中为蹦床、杂技)的函数中。 在这里,我认为翻译成目标函数的克隆/副本的一部分是合适的。 这些指令包括用目标函数替换的代码和重新跳转到目标函数的无条件分支。 拦截函数可以通过替换目标函数或者在执行“trampoline”函数时调用目标函数作为子程序来扩展功能。

Detours在运行时插入。 内存中目标函数的代码没有在硬盘上更改,因此可以提高粒度,以便于截获二进制函数的执行。 例如,在执行某个APP应用程序时,可能会将加载的DLL中的函数过程插入到侦听代码“detoured”中,同时此DLL也会正常由其他APP应用程序执行。 也就是说,它是在不被截获的情况下执行的。 DLL二进制文件没有更改,因此发生侦听不会影响其他进程区域的加载。 与DLL重新链接和静态重定向不同,Detours库中使用的这种中断技术不会影响APP应用中方法或系统代码在目标函数中的定位。

如果其他人尝试修改二进制代码以在调试或内部使用其他系统发现手段,Detours将成为常用的开发包。 据我所知,Detours是第一个可以在任何平台上将未修改的目标代码保留为在" trampoline "中调用的子程序的开发包。 以前的系统不是将原始目标代码作为普通子程序调用,而是将监听代码逻辑放置在目标代码中。 我们独特的“trampoline”设计对于扩展现有软件的二进制代码很重要。

为了使用基本的函数侦听功能,Detours还提供了编辑DLL导入表的功能。 这样,可以将任何数据节表添加到现有二进制代码中,也可以将DLL注入到新的或已在运行的进程中。 在流程中注入DLL后,无论是在APP应用程序内还是在系统库中,动态库都可以侦听任何Win32函数。

基本原理

1. WIN32进程内存管理

众所周知,WINDOWS NT实现了虚拟内存,每个WIN32进程都有4GB的虚拟内存空间。 有关WIN32进程虚拟内存结构及其操作的具体信息,请参阅WIN32 API文档。 以下只指出与Detours有关的地方。

(1)进程执行的命令也放置在虚拟存储器空间中

)2)使用QueryProtectEx函数将容纳指令的页面的权限变更为可写入可执行,通过改写其内容,可以修正执行中的程序

)3)使用VirtualAllocEx将虚拟内存从一个进程分配给正在运行的另一个进程,使用QueryProtectEx函数将页面的权限更改为可写可执行,并将要执行的指令作为二进制机器代码写入

屏蔽WIN32 API的原理

Detours定义了三个概念:

(1) Target函数)拦截的函数通常是Windows的API。

)2) Trampoline函数: Target函数的部分副本。 由于Detours将重写Target函数,因此复制并存储Target函数的前五个字节将保留Target函数的过程调用语义,同时便于以后的恢复。

(3) Detour函数)用于代替Target函数的函数。

Detours在Target函数的开头添加5个字节的JMP Address_of_ Detour_ Function命令,将对Target函数的调用引导到自己的Detour函数,在Target函数的开头5个字节中添加jmp aart

图1和图2。
(图1:Detour函数的过程)

(图2: Detour函数的调用过程)

说明:
  目标函数:
目标函数的函数体(二进制)至少有5个字节以上。按照微软的说明文档Trampoline函数的函数体是拷贝前5个字节加一个无条件跳转指令的话(如果没 有特殊处理不可分割指令的话),那么前5个字节必须是完整指令,也就是不能第5个字节和第6个字节是一条不可分割的指令,否则会造成Trampoline 函数执行错误,一条完整的指令被硬性分割开来,造成程序崩溃。对于第5字节和第6个字节是不可分割指令需要调整拷贝到杂技函数(Trampoline)的 字节个数,这个值可以查看目标函数的汇编代码得到。此函数是目标函数的修改版本,不能在Detour函数中直接调用,需要通过对Trampoline函数 的调用来达到间接调用。
  Trampoline函数:
此函数默认分配了32个字节,函数的内容就是拷贝的目标函数的前5个字节,加上一个JMP Address_of_ Target _ Function+5指令,共10个字节。
此函数仅供您的Detour函数调用,执行完前5个字节的指令后再绝对跳转到目标函数的第6个字节继续执行原功能函数。
  Detour函数:
此函数是用户需要的截获API的一个模拟版本,调用方式,参数个数必须和目标函数相一致。如目标函数是__stdcall,则Detour函数声明也必须 是__stdcall,参数个数和类型也必须相同,否则会造成程序崩溃。此函数在程序调用目标函数的第一条指令的时候就会被调用(无条件跳转过来的),如 果在此函数中想继续调用目标函数,必须调用Trampoline函数(Trampoline函数在执行完目标函数的前5个字节的指令后会无条件跳转到目标 函数的5个字节后继续执行),不能再直接调用目标函数,否则将进入无穷递归(目标函数跳转到Detour函数,Detour函数又跳转到目标函数的递归, 因为目标函数在内存中的前5个字节已经被修改成绝对跳转)。通过对Trampoline函数的调用后可以获取目标函数的执行结果,此特性对分析目标函数非 常有用,而且可以将目标函数的输出结果进行修改后再传回给应用程序。
Detour提供了向运行中的应用程序注入Detour函数和在二进制文件基础上注入Detour函数两种方式。本章主要讨论第二种工作方式。通过 Detours提供的开发包可以在二进制EXE文件中添加一个名称为Detour的节表,如下图3所示,主要目的是实现PE加载器加载应用程序的时候会自 动加载您编写的Detours DLL,在Detours Dll中的DLLMain中完成对目标函数的Detour。
(图3)

二、  Detours提供的截获API的相关接口
Detours的提供的API 接口可以作为一个共享DLL给外部程序调用,也可以作为一个静态Lib链接到您的程序内部。
Trampoline函数可以动态或者静态的创建,如果目标函数本身是一个链接符号,使用静态的trampoline函数将非常简单。如果目标函数不能在链接时可见,那么可以使用动态trampoline函数。
  要使用静态的trampoline函数来截获目标函数,应用程序生成trampoline的时候必须使用
DETOUR_TRAMPOLINE宏。DETOUR_TRAMPOLINE有两个输入参数:trampoline的原型和目标函数的名字。
注意,对于正确的截获模型,包括目标函数,trampoline函数,以及截获函数都必须是完全一致的调用形式,包括参数格式和调用约定。当通过 trampoline函数调用目标函数的时候拷贝正确参数是截获函数的责任。由于目标函数仅仅是截获函数的一个可调用分支(截获函数可以调用 trampoline函数也可以不调用),这种责任几乎就是一种下意识的行为。
使用相同的调用约定可以确保寄存器中的值被正确的保存,并且保证调用堆栈在截获函数调用目标函数的时候能正确的建立和销毁。
可以使用DetourFunctionWithTrampoline函数来截获目标函数。这个函数有两个参数:trampoline函数以及截获函数的指针。因为目标函数已经被加到trampoline函数中,所有不需要在参数中特别指定。
  我们可以使用DetourFunction函数来创建一个动态的trampoline函数,它包括两个参数:一个指向目标函数的指针和一个截获函数的指针。DetourFunction分配一个新的trampoline函数并将适当的截获代码插入到目标函数中去。
当目标函数不是很容易使用的时候,DetourFindFunction函数可以找到那个函数,不管它是DLL中导出的函数,或者是可以通过二进制目标函数的调试符号找到。
DetourFindFunction接受两个参数:库的名字和函数的名字。如果DetourFindFunction函数找到了指定的函数,返回该函数 的指针,否则将返回一个NULL指针。DetourFindFunction会首先使用Win32函数LoadLibrary 和 GetProcAddress来定位函数,如果函数没有在DLL的导出表中找到,DetourFindFunction将使用ImageHlp库来搜索有 效的调试符号(译注:这里的调试符号是指Windows本身提供的调试符号,需要单独安装,具体信息请参考Windows的用户诊断支持信息)。 DetourFindFunction返回的函数指针可以用来传递给DetourFunction以生成一个动态的trampoline函数。
我们可以调用DetourRemoveTrampoline来去掉对一个目标函数的截获。
注意,因为Detours中的函数会修改应用程序的地址空间,请确保当加入截获函数或者去掉截获函数的时候没有其他线程在进程空间中执行,这是程序员的责任。一个简单的方法保证这个时候是单线程执行就是在加载Detours库的时候在DllMain中呼叫函数。
三、  使用Detours实现对API的截获的两种方法
建立一个MFC对话框工程,在对话框的OK按钮的单击事件中加入对MessageBoxA函数的调用,编译后的程序名称MessageBoxApp,效果如图。

(图4)
  静态方法
建立一个Dll工程,名称为ApiHook,这里以Visual C++6.0开发环境,以截获ASCII版本的MessageBoxA函数来说明。在Dll的工程加入:
DETOUR_TRAMPOLINE(int WINAPI Real_Messagebox(HWND hWnd ,
    LPCSTR lpText,
    LPCSTR lpCaption,
UINT uType), ::MessageBoxA);
生成一个静态的MessageBoxA的Trampoline函数,在Dll工程中加入目标函数的Detour函数:
int WINAPI MessageBox_Mine( HWND hWnd ,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType)
{
  CString tmp= lpText;
  tmp+=” 被Detour截获”;
  return Real_Messagebox(hWnd,tmp,lpCaption,uType);
//  return ::MessageBoxA(hWnd,tmp,lpCaption,uType);  //Error
}
在Dll入口函数中的加载Dll事件中加入:
DetourFunctionWithTrampoline((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
在Dll入口函数中的卸载Dll事件中加入:
DetourRemove((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
  动态方法
建立一个Dll工程,名称为ApiHook,这里以Visual C++6.0开发环境,以截获ASCII版本的MessageBoxA函数来说明。在Dll的工程加入:
//声明MessageBoxA一样的函数原型
typedef int  (WINAPI * MessageBoxSys)( HWND hWnd ,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType);
//目标函数指针
MessageBoxSys SystemMessageBox=NULL;
//Trampoline函数指针
MessageBoxSys Real_MessageBox=NULL;
在Dll工程中加入目标函数的Detour函数:
int WINAPI MessageBox_Mine( HWND hWnd ,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType)
{
  CString tmp= lpText;
  tmp+=” 被Detour截获”;
  return Real_Messagebox(hWnd,tmp,lpCaption,uType);
//  return ::MessageBoxA(hWnd,tmp,lpCaption,uType);  //Error
}
在Dll入口函数中的加载Dll事件中加入:
  SystemMessageBox=(MessageBoxSys)DetourFindFunction("user32.dll","MessageBoxA");
  if(SystemMessageBox==NULL)
  {
    return FASLE;
  }
  Real_MessageBox=(MessageBoxSys)DetourFunction((PBYTE)SystemMessageBox, (PBYTE)MessageBox_Mine);
在Dll入口函数中的卸载Dll事件中加入:
DetourRemove((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
  重写二进制可执行文件
使用Detours自带的SetDll.exe重写二进制可执行文件,可以在需要截获的程序中加入一个新的Detours的PE节表。对于本文就是新建一个批处理文件调用SetDll.exe。
@echo off
if not exist MessageBoxApp.exe (
echo 请将文件解压到MessageBoxApp.exe的安装目录, 然后执行补丁程序
) else (
setdll /d:ApiHook.dll MessageBoxApp.exe
)
Pause
调用后使用depends.exe(微软VC6.0开发包的工具之一)观察MessageBoxApp.exe前后变化, 可以看到Setdll已经重写MessageBoxApp.exe
成功,加入了对ApiHook.dll的依赖关系。

      (执行SetDll.exe前)                                                       (执行SetDll.exe后)
执行SetDll.exe重写后的MessageBoxApp.exe,点击确定后可以看到结果如下:
至此,MessageBoxApp.exe对MessageBoxA函数的调用已经被截获,弹出的对话框内容已经明显说明这一点。

转载于:https://my.oschina.net/riseworlds/blog/695920

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。