Hook技术入门

007bug2021-07-20 16:26:02

0x00 前言

要说在Hook技术里面最基础的,那就是IAT Hook,它的原理就是通过修改PE结构中的IAT表,将其替换成我们自己定义的函数,最终实现Hook,所以在进行Hook之前,我们得很清楚的PE结构,接下来我们先讲解一下怎么索引到IAT表。


0x01 PE文件格式解析

随便拖一个程序进入Uedit进行分析

这一部分就是PE文件的DOS头,先看看DOS头的结构体,咱边看结构体边分析:

typedef struct IMAGE_DOS_HEADER
  {
        WORD e_magic;        WORD e_cblp;
        WORD e_cp;
        WORD e_crlc;
        WORD e_cparhdr;
        WORD e_minalloc;
        WORD e_maxalloc;
        WORD e_ss;
        WORD e_sp;
        WORD e_csum;
        WORD e_ip;
        WORD e_cs;
        WORD e_lfarlc;
        WORD e_ovno;
        WORD e_res[4];
        WORD e_oemid;
        WORD e_oeminfo;
        WORD e_res2[10];
        DWORD e_lfanew;            
  }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

在DOS头里面最关键是两个成员就是e_magic,e_lfanew(其他的可以忽略),e_magic就是DOS头的标识,也就是MZ,为什么是MZ呢,其实就是Mark Zbikowski,他是MS-DOS主要开发者之一,为了纪念老人家,e_lfanew就是下一个头的偏移(基于文件基址),可能有同学要有疑问了,为啥现在还要有这个DOS头呢,因为微软为了向下兼容,所以才没有删除DOS头,那么加上偏移我们来看看:

PE头也有它自己的结构体,Signature和e_magic是一个道理,这里的Signature是PE。

typedef struct IMAGE_NT_HEADERS   {        
     DWORD Signature;         
     IMAGE_FILE_HEADER FileHeader;
     IMAGE_OPTIONAL_HEADER32 OptionalHeader;   
} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;

选择的区域是上面结构体中的FileHeader

它也有自己的结构体,感兴趣的小伙伴可以自己去查查每个字段的具体含义,这里就不展开了:

typedef struct _IMAGE_FILE_HEADER {   
        WORD      Machine;                 //运行平台 
        WORD      NumberOfSections;        //节表数目    
        DWORD     TimeDateStamp;           //时间戳     
        DWORD     PointerToSymbolTable;    
        DWORD     NumberOfSymbols;         //符号数  
        WORD      SizeOfOptionalHeader;    //可选部首长度 
        WORD      Characteristics;         //文件属性 
}

说完FileHeader,重点就来了,那就是OptionalHeade,除去Signature,FileHeader剩下的就是OptionalHeade:


结构体如下,我们关注其最重要的一个成员DataDirectory(数据目录),它包含了我们要替换的导入表。

typedef struct _IMAGE_OPTIONAL_HEADER {
  WORD                 Magic;
  BYTE                 MajorLinkerVersion;
  BYTE                 MinorLinkerVersion;
  DWORD                SizeOfCode;
  DWORD                SizeOfInitializedData;
  DWORD                SizeOfUninitializedData;
  DWORD                AddressOfEntryPoint;
  DWORD                BaseOfCode;
  DWORD                BaseOfData;
  DWORD                ImageBase;
  DWORD                SectionAlignment;
  DWORD                FileAlignment;
  WORD                 MajorOperatingSystemVersion;
  WORD                 MinorOperatingSystemVersion;
  WORD                 MajorImageVersion;
  WORD                 MinorImageVersion;
  WORD                 MajorSubsystemVersion;
  WORD                 MinorSubsystemVersion;
  DWORD                Win32VersionValue;
  DWORD                SizeOfImage;
  DWORD                SizeOfHeaders;
  DWORD                CheckSum;
  WORD                 Subsystem;
  WORD                 DllCharacteristics;
  DWORD                SizeOfStackReserve;
  DWORD                SizeOfStackCommit;
  DWORD                SizeOfHeapReserve;
  DWORD                SizeOfHeapCommit;
  DWORD                LoaderFlags;
  DWORD                NumberOfRvaAndSizes;
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;

它妥妥的有十六张表,我们只关注导入表:



typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk;    
} DUMMYUNIONNAME;
DWORD TimeDateStamp; 
DWORD ForwarderChain; 
DWORD Name;                   //指向DLL名字的RVA
DWORD FirstThunk;         
} IMAGE_IMPORT_DESCRIPTOR;

这里面最重要的就是OriginalFirstThunk,Name,FirstThunk

其中OriginalFirstThunk,FirstThunk分别指向INT和IAT表,心心念念的IAT表终于登场了,这两个成员指向的都是同一个表,为什么这样做等下说



当我们的函数加载完成后,我们IAT指向了函数真正的地址

在IAT在加载完真正的函数地址之后,如果没有INT表来标识具体的函数名称的话,操作系统就完全不知道它加载的这个函数名称是啥,只有一个函数的实现偏移和实现,并不知道它是啥,所以才会有INT表的存在。


0x02 IAT Hook 代码编写

到此PE结构也就讲解完了,也就可以开始写IAT Hook

我们的代码应该包含以下功能:

1.定义我们自己的Hook后的函数

int WNAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
  return OldMessageBoxA(hWnd, "Hello NSDA", lpCaption, uType);
}

我们自己的MessageBox必须和原来的MessageBox的参数一模一样,这样才能保证在调用自己的函数的时候不会报错

2.接下来就是找到IAT表

HMODULE ImageBase = GetModuleHandle(NULL);  //获得模块基地址                            
PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD)ImageBase;                  
DWORD dwTemp = (DWORD)pDosHead + (DWORD)pDosHead->e_lfanew;
PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;                                                           
PIMAGE_OPTIONAL_HEADER pOpHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;

DWORD dwInputTable = pOpHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;  
DWORD dwTemp = (DWORD)GetModuleHandle(NULL) + dwInputTable;
PIMAGE_IMPORT_DESCRIPTOR   pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
PIMAGE_IMPORT_DESCRIPTOR   pCurrent = pImport;

通过GetModuleHandle获得模块基地址之后,我们就可以拿到程序的DOS头,PE头,文件头,可选头

3.接下来就是遍历IAT将其替换成我们自己函数的地址

  while (*(DWORD*)pFirstThunk != NULL)                        
    {
      if (*(DWORD*)pFirstThunk == (DWORD)OldMessageBoxA)       
      {
        DWORD oldProtected;
        VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);  
        memcpy(pFirstThunk, (DWORD *)&dwTemp, 4);                                    
        VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected);            
      }
      pFirstThunk++;
    }

通过遍历IAT表找到MessageBox的地址之后进行替换,有一点需要注意的,需要先修改文件的页属性才能进行替换(在XP系统上不用)

完整代码就不贴了,大伙们可以自己去尝试把完整的代码写出来,下面看看Hook完的效果:

文章作者: 广软NSDA安全团队
dwordtypedef
本作品采用《CC 协议》,转载必须注明作者和本文链接
程序是指令、数据及其组织形式的描述,进程是程序的实体。在进程中当EXE模块调用CreateFile()函数的时候,会去调用kernel32.dll模块中的CreateFile()函数,因为真正的CreateFile()函数的实现在kernel32.dll模块中。
在Windows大部分应用都是基于消息机制,他们都拥有一个消息过程函数,根据不同消息完成不同功能,windows通过钩子机制来截获和监视系统中的这些消息。一般钩子分局部钩子与全局钩子,局部钩子一般用于某个线程,而全局钩子一般通过dll文件实现相应的钩子函数。
全局钩子注入在Windows大部分应用都是基于消息机制,他们都拥有一个消息过程函数,根据不同消息完成不同功能,windows通过钩子机制来截获和监视系统中的这些消息。一般钩子分局部钩子与全局钩子,局部钩子一般用于某个线程,而全局钩子一般通过dll文件实现相应的钩子函数。
前言一次跟师傅交流时师傅谈到有些EDR或AV,他们保护目标主机,甚至无进程,不经想到病毒实际上也常用这种技术。
简介这次实验是在WIN7 X86系统上进程,使用的编译器是VS2017。所谓的DLL注入,其实就是在其他的进程中把我们编写的DLL加载进去。所以DLL注入的核心就是把要注入的DLL的路径写到目标进程中,然后在目标进程中调用LoadLibrary函数,并且指定参数为保存了DLL路径的地址。要实现DLL注入,首先就要创建一个用来注入的DLL。
最近在研究某数字杀软的时候看到有个配置选项:这个自我保护实际上是加载360SelfProtection.sys驱动(看这名字应该还有360SelfProtection_win10.sys文件),在0环通过hook等手段保护注册表项,重要进程进程等。
Dll注入
2021-11-08 14:57:41
最近太忙啦XDM,又在做一些列的分析复现工作量有点大,更新要慢一点了。一致,也不会覆盖其他的进程信息。
在win2012以前的操作系统版本下,由于WDigest将明文储存到lsass进程中,可以抓取明文密码。
DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件。
007bug
暂无描述