使用IAT表注入模块到进程中 样例

        模块注入到进程的方法有很多,想一一写例子,学习一下,也练习一下!

        首先先从IAT表注入开始吧!

        如果了解PE文件的格式的话,原理很简单。当一个模块被系统加载起来后,会遍历模块的导入表,将静态导入的函数地址填充到导入表中,以便进程执行起来后,调用到该模块时,能够使用导入函数。要获取导入函数地址,首先要将导出该函数的模块加载起来。

        那方法来了,我们是否可以在进程启动时,在必然被加载的模块(比如exe模块,ntdll.dll,kernel32.dll等)导入表被系统遍历之前(注意了,一定是导入表被遍历之前。),将导入表修改一下,添加进我们的模块,并且将相应的IAT的数据添加进来。这样,当系统遍历到该模块的导入表时,遍历到我们自己的模块的导入表项,它就会将我们的模块加载起来,并且将模块导出函数的地址填到我们自己组织的导入表函数项中。

        如下是PE文件中导入表的结构:

        使用IAT表注入模块到进程中 样例_第1张图片

        首先按照上述的结构,为我们的DLL准备一个导入表(我们以修改Test.exe的导入表,注入Dll.dll模块为例):        

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    };
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
        简单一些,通过Test.exe Nt头的 DataDirectory 目录的 Import Table对应的地址以及大小,将对应的导入表信息(IMAGE_IMPORT_DESCRIPTOR结构体组成的数组)复制出来,并且在最后添加一项。

        对IMAGE_IMPORT_DESCRIPTOR 结构体,我们需要填充三项,OriginalFirstThunk 域,Name域,FirstThunk域。为了简便,对于Dll.dll我们只导入一个函数即可。注意,Name使用了全路径,这样就可以简化模块路径的设置,防止模块所在路径不在Path 中,而无法加载模块。
        为了构造 OriginalFirstThunk / FirstThunk 偏移所对应的内容,以及Name偏移模块全路径。定义如下的结构体:

// 导入表定义
typedef struct tag_IATTableContent
{
	IMAGE_THUNK_DATA OriginalThunk[2];
	IMAGE_THUNK_DATA FirstThunk[2];
	IMAGE_IMPORT_BY_NAME ImportByName;
	CHAR szFuncName[64];
	CHAR szDllName[MAX_PATH];
}IATTableContent, *LPIATTableContent;
        将导入表内容进行填写,OriginalThunk / FirstThunk同时指向 ImportByName ,即它的偏移值(相对于Test.exe起始地址)。注意szFuncName 这个字符数组用于扩展ImportByName的Name域,以有足够的空间容纳函数名称。IMAGE_IMPORT_BY_NAME结构体的 Name域只有一个字节,需要额外为它添加空间。

        将 IMAGE_IMPORT_DESCRIPTOR 的Name的偏移设置为 szDllName 的偏移。

        

        通过上述的过程,我们就已经完成了一个新的导入表构造,剩下的工作就是在模块的导入表未被系统遍历之前将我们构造的导入表赋值给模块Nt头中。(详细内容可以参考代码)

        例子使用了一种取巧的方法,调用CreateProcessW函数时,将第六个参数 dwCreateFlags 设置为CREATE_SUSPENDED,这样创建进程后,进程马上被挂起,程序中的第一个模块Test.exe的导入表还没有被遍历。所以在这时我们可以进行我们的“非法”的勾当,达到邪恶的目的。

      下载样例


        By  Andy  @ 2015-07-30

你可能感兴趣的:(Windows,编程)