查看: 331|回复: 0

[原创图文] 逆向基础 通过修改PE加载DLL

[复制链接]

35

主题

47

帖子

3

精华

解密专家

Rank: 16

学币
380
荣耀
0
rank
0
违规
0
发表于 2021-4-15 17:10:13 | 显示全部楼层 |阅读模式
本帖最后由 鸦领主 于 2021-4-15 17:09 编辑

1.1  通过修改PE加载DLL

1.1.1 修改思路
PE文件中导入的DLL信息以结构体的形式存储在IDT(Import Directory Table)中,只需要将DLL添加到列表尾部就可以了,需要知道IDT有无足够的内存空间
1.1.2  查看IDT是否有足够的空间
IMAGE_OPTIONAL_HEADER32.DataDirectory[1].VirtualAddress的值即是IDT的地址(RVA)

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

将视图改成File offset,意思是地址显示为文件偏移,从图中可以看出总共有5个结构体数组,每个导入的dll文件对应一个结构体,最后末尾以NULL结构体结束(),整个IID的大小以文件偏移来看是76CC-772F,64个字节,那么每个结构体就是14个字节

通过修改PE加载DLL

通过修改PE加载DLL

从图中可以看到,IID结构体数组下面是有其他数据的,没有足够的空间来添加其他的DLL文件
1.1.3  移动IDT
有三种方式分别是:
  • 查找文件中的空白区域
  • 增加文件最后一个节区的大小
  • 在文件末尾添加新的节区

通过修改PE加载DLL

通过修改PE加载DLL

尝试第一种方法,这个节区的最后正好有空白区域,查看这个区域是否可用

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

磁盘文件中大小为2E00,实际被加载到内存中的只有2C56,还是1AA没有被使用(2E00-2C56),那么这个区域是可以使用的,那么我们就在8C80(7E80 RAW)这个位置创建IDT
1.1.4  修改导入表的值

通过修改PE加载DLL

通过修改PE加载DLL

一个是IDT的地址,一个是IDT的大小,我们将IDT移动到了8C80,那么将RVA改为8C80,又要添加一个结构体,那么64个字节还需要在加14个字节

通过修改PE加载DLL

通过修改PE加载DLL

那么从现在开始IDT位于8C80,大小是78
1.1.5  删除绑定导入表(BOUND IMPORT TABLE)

通过修改PE加载DLL

通过修改PE加载DLL

BOUND IMPORT TABLE(绑定导入表)是一种提高DLL加载速度的技术
若想正常导入自己的dll,需要向绑定导入表添加信息,但是该导入表是个可选项,不是必须存在的,可以删除(修改其值为0),当前实例中绑定导入表的值是0,不需要修改
1.1.6  创建新IDT
先将原先的IDT复制到8C80(7E80RAW)的位置,

通过修改PE加载DLL

通过修改PE加载DLL

在文件偏移的7ED0的地方分别设置INT,Name,IAT的内存(RVA)地址,地址可以选择别的地方

通过修改PE加载DLL

通过修改PE加载DLL

这个IID设置好了,那么接下来就是设置INT,Name,IAT的值了
1.1.7  设置INT,Name,IAT的值

通过修改PE加载DLL

通过修改PE加载DLL

黑色表示INT,青色表示Name,品红色表示IAT
INT(Import Name Taple,导入名称表)是RVA数组,每个数组中都是一个RVA地址记录着导入函数的名称字符串,上图中只有一个元素,其值是2E590 RVA,该地址是导入的函数的Ordinal(2个字节)和函数的名称字符串(dummy)
Name 是包含DLL文件名称字符串,来到RVA地址 02E570可以看到DLL的名称
IAT 也是RVA数组,各元素既可以拥有和INT一样的值,若INT中的数据准确也可以拥有不同的值,实际运行中,PE装载器会将虚拟内存中的IAT替换为实际函数的地址
1.1.8  修改IAT相关节区的属性
加载PE文件到内存时,PE装载器会修改IAT,写入函数的实际地址,所以你将IAT写入到了哪个节区,那么相应的节区头必须拥有WRITE(可写)属性。

通过修改PE加载DLL

通过修改PE加载DLL

我是将IAT写入到了data节区,节区头的属性拥有WRITE并不需要修改了,可以看到原属性值是C0000040,由3个属性组成
那么可以看出来如果不想要WRITE属性,只需要将原属性值改为40000040,因为80000000是WRITE的值(C0000040-40000040)。
--------------------------------------------------------------------------------------------------------------------------------
我们还没有修改的程序,IAT位于.rdata节区,且.rdata节区头本来就没有可写属性,为什么程序可以正常运行,而我们修改后就不能运行。
原因在于IMAGE_OPTIONAL_HEADER结构体的Data Directory数组中存在IAT

通过修改PE加载DLL

通过修改PE加载DLL

若修改的IAT的地址是在6000-6154的位置,那么就不用再修改IAT的节区头的属性了
比如将dummy设置在6000-6154之间的位置,再将IAT(SIZE)增加8个字节(Ordinal(2个字节)+dummy(5个字节)+0结尾(1个字节))

--------------------------------------------------------------------------------------------------------------------------------
1.1.9 检测验证

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

查看IDT可以看到,向IDT导入的dll的IID结构体设置正常,INT也是正常的说明没有问题。

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

通过修改PE加载DLL

运行程序也是成功了,我的dll只是显示一个消息框
1.1.10   查看dll文件代码
<div>#include<Windows.h>
</div><div>BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
    switch (dwReason)
    {
    case DLL_PROCESS_ATTACH:
        MessageBox(NULL, TEXT("注入成功!!"), TEXT("PE注入"), MB_OK);
        break;
    }
        return TRUE;//必须返回1
}
#ifdef __cplusplus
extern"C" {
#endif
    __declspec(dllexport) void dummy()
    {
        return;
    }
#ifdef  __cplusplus
}
#endif //  __cplusplus</div>
   代码非常的简单只是弹出一个消息框,但是有一个地方需要注意dummy函数是一个导出函数,可以看见它没有执行任何功能,这是为了保持形式上的完整性,使dll能够顺利的添加到导入表。
    在PE文件中导入某个dll,实质就是在文件代码内调用该dll提供的导出函数,PE文件头中记录着dll的名称,函数的名称信息等,所以需要提供至少一个以上的导出函数才能保持形式上的完整性。



温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
学逆向论坛-免费的逆向学习论坛
关闭

论坛公告上一条 /1 下一条

快速回复 返回顶部 返回列表