导入表注入

引言

导入表注入就是把一个自己的dll程序加载进另一个exe进程的4GB内存空间。我们通过写进一张新的导入表来实现这个注入功能。

下面贴出海哥在滴水逆向第三期给出的部分dll程序代码:
首先是dll程序的头文件

void Init();
void Destroy();
extern "C" _declspec(dllexport) void ExportFunction();  

然后是它的源文件

void Init()
{
	MessageBox(0,"Init","Init",MB_OK);
}
void Destroy()
{
	MessageBox(0,"Destroy","Destroy",MB_OK);
}
void ExportFunction()
{
	MessageBox(0,"ExportFunction","ExportFunction",MB_OK);
}

采用隐式调用的方法注入

#include "stdafx.h"
#include "MyDll.h"
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		Init();
		break;
	case DLL_PROCESS_DETACH:
		Destroy();
		break;
    }
    return TRUE;
}

在刚打开注入后的程序时,发现弹出了Init()窗口,在关闭该程序时,又弹出了Destroy()窗口。

也就是说,dll的入口在往4GB里面粘贴的时候会调用一次,在把这个dll从4GB空间里面拿出来的时候还会再调用一次。但是如果这个程序不退出的话,系统永远都不会将这个dll从4GB空间里面给拿走。

而显式调用相比隐式调用会更加灵活。它可以在需要加载dll的时候用LoadLibrary()加载进来;在不需要这个dll的时候还可以用FreeLibrary()直接把它释放掉。同样会分别调用两次dll的入口。

我们可以移动哪些表?

数据目录项不能动,因为文件加载时,系统需要根据这个表去找需要的导入表导出表之类的数据
导出表结构可以动,但是由于导出表不止一张,所以需要将这一堆连着的导入表结构全部移动
INT表可移动,但是IAT表不能动,因为IAT表移动的代价太过巨大。在加载完的时候会生成一个call[xxx],这个xxx就是IAT表的首地址,若果我们移动了IAT表,但是我们不知道有哪些地方直接引用(如call[xxx],jmp xxx等)了IAT表,就需要遍历整个PE结构来找出它们,工程量太过巨大,所以我们不动IAT表。

导入表注入

我们通过给exe程序重新写进一个导入表来实现导入表注入。但是当系统一检查,发现导入表结构的OriginalFirstThunk指向的INT表和FirstThunk为空时,会判断这张导入表是没有意义的,操作系统不会加载它。所以,我们需要写入的导入表结构必须完整。也就是说,我们需要写入一张新的导入表,并且至少要有一个函数的INT表和IAT表以及对应的IMPORT_BY_NAME表。否则,操作系统认为这张导入表没有意义,就不会加载它。

实现步骤:
  1. 根据数据目录项找到导入表,获取它的信息
    在这里插入图片描述
    VirtualAddress和Size这两个值都需要
  2. 找到真正的导入表结构
    在这里插入图片描述
    计算新增一个导入表所需要的内存空间
    在这里插入图片描述
    我们将整个导入表结划分为ABCD四个部分。A部分是导入表结构的五个DWORD类型成员,总计20字节大小。B部分是OriginalFirstThunk指向的INT表和FirstThunk指向的IAT表,由于两张表均不能为空,我们需要在这两张表中分别写进一个数据,而这两张表都需要以0结尾,再加上每个数据占4个字节,所以B部分总计4*4=16字节大小。C部分由于储存的是一个dll名称的字符串,需要以’\0’结尾,所以C部分大小为dll名称长度+1。D部分_IMAGE_IMPORT_BY_NAME结构虽然只有3个字节大小,但是由于Name[1]只是储存函数名称的首字符,而这个名称也是以0结尾,所以D部分大小为函数名称长度+1+2。
    然后判断是否有一个节的空白区>Size(数据目录项指向的导入表的成员变量,记录了原导入表的大小)+20+A+B+C+D;如果空间不够,可以将CD两部分存储在其他空白区;如果空间仍然不够,则需要新增一个节或者扩大最后一个节来解决。
  3. 将原导入表全部Copy到空白区
  4. 在Copy的导入表后追加一个导入表
  5. 追加一个8个字节的INT表和一个8个字节的IAT表
  6. 追加一个IMAHE_IMPORT_BY_NAME结构,前两个字节的Hint存0,后面是函数名称字符串
  7. 将_IMAGE_IMPORT_BY_NAME结构的RVA赋值给INT表和IAT表中的第一项
  8. 分配空间存储dll名称的字符串,并将该字符串的RVA赋值给NAME属性
  9. 修正_IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值