首页
社区
课程
招聘
导入表想增加一个DLL,实现程序启动时加载自己的DLL
发表于: 2015-1-29 21:40 6698

导入表想增加一个DLL,实现程序启动时加载自己的DLL

2015-1-29 21:40
6698
这几天在看PE结构的书,有一个想法就是在EXE文件中修改程序导入表结构,实现程序启动时带起一个DLL。
    但是增加IMAGE_IMPORT_DESCRIPTOR结构以后,始终出现如下错误:

我的步骤如下:
1.找一片连续为0代码地址,将已有的导入表COPY过去。
2.增加一个IMAGE_IMPORT_DESCRIPTOR结构,并填写数据。情况如下图


这里添加了一个IMAGE_IMPORT_DESCRIPTOR结构,并且写入了NAME字段 和 FirstThunks字段的位置
3.修改程序导入表地址,和大小字段
最后出现如下几种情况:
1.当目录下无mydll.dll的情况
     没有找到Mydll.dl,这个程序未能启动


2.当有mydll.dll但无导出函数mufunc的情况
    无法定位程序输入点 myfunc 于动态链接库上

     
3.有mydll.dll和导出函数myfunc的时候
    会出现:应用程序正常初始化(0xc0000005)失败


最后为什么会出现这种情况呢。是我思路错了么,还是有什么结构没填写。         

O说明:
    图里面的File offset 和 RVA相等,因为映射是1000对1000
    其他修改OEP加载DLL的办法我也知道,但是我希望弄懂这是咋回事,希望各位大大指点迷津。
    图片刚刚链接弄错了,不好意思。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (12)
雪    币: 12502
活跃值: (5248)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
偶也想这们加载DLL
2015-1-29 22:03
0
雪    币: 60
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
试问 有Dll 无 function 怎么自启动?

除非动态引用,
2015-1-29 23:04
0
雪    币: 200
活跃值: (38)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
图呢???
2015-1-29 23:04
0
雪    币: 58
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
图好像还在审核
2015-1-30 08:12
0
雪    币: 58
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
DLL有到出函数的。在没有的情况会说定位不到XXX函数。图还没审核
2015-1-30 08:13
0
雪    币: 10
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
等图出来 在来看
2015-1-30 08:53
0
雪    币: 627
活跃值: (663)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
8
能够发帖,图应该不需要审核,是你编辑帖子的问题。

“0xC0000005: Access Violation”错,这是内存访问的问题,说明你有地方改得不对。
由于看不到图,只能从你的描述猜测。
1.找一片连续为0代码地址,将已有的导入表COPY过去。
2.增加一个IMAGE_IMPORT_DESCRIPTOR结构,并填写数据。情况如下图
3.修改程序导入表地址,和大小字段
这样看来,可能是IMAGE_IMPORT_DESCRIPTOR的内容有问题!
[FONT="Courier"]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;[/FONT]
其中,Name和FirstThunk两个字段必填。
Name:一个RVA指针,指向导入lib名。比如你的情况为指向"mydll.dl\0"。
FirstThunk:一个RVA指针,指向IMAGE_THUNK_DATA32/IMAGE_THUNK_DATA64链表。表以一个NULL结束。
[FONT="Courier"]typedef struct _IMAGE_THUNK_DATA32 {
    union {
        PBYTE  ForwarderString;
        PDWORD Function;
        DWORD Ordinal;
        PIMAGE_IMPORT_BY_NAME  AddressOfData;
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;[/FONT]
这里最常见的两种导入方式:by Ordinal或by Name。
如果是"by Ordinal",就填你导入函数的Ordinal。
如果是"by Name",又是一个RVA指针,指向IMAGE_IMPORT_BY_NAME。
[FONT="Courier"]typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    BYTE    Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;[/FONT]
其中Name必填,指向你的导入函数名,比如"MyFunction1\0"。

PS:DLL不一定非得有导出函数,DllEntry总归是有的。有人会把DllEntry也当作一个导出函数。
也就是说,当这个DLL载入时,该做的事情在DllEntry里去完成。也许有函数在DLL里,你在DLL的Exports里没有列出来,这时需要硬编码:得到你DLL的载入基址后,加上你导出函数的RVA,再Call过去。
DLL在卸载时,DllEntry会被再调用一次,给你一个Cleanup的机会。

在作系统DLL Hook的时候,你得“继承”原DLL的所有导出项,选其中一个或几个导出函数作为Monitor,在时机成熟时再做Patching,比如一个加了壳的目标解压缩完成后。
2015-1-30 10:12
0
雪    币: 94
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
给你个简单的思路,改导出模块名称,你的DLL导出函数和原导出函数一致并将调用转发到原来真正的DLL即可
2015-1-30 10:34
0
雪    币: 10
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
8楼讲的非常详细 学习了!
2015-1-30 11:25
0
雪    币: 627
活跃值: (663)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
11
看到图了。
FirstThunk指向IMAGE_THUNK_DATA32的链表,少个结束NULL!
1) 最简单,这样改:
[FONT=Courier]00000360:  68 03 00 00.00 00 00 00.00 00 6D 79.66 75 6E 00  ..........myfun.[/FONT]
因为位置不够,函数名由"myfunc"缩短为"myfun",重新编译MyDll.dll。
2) 不重新编译。00000370的库名向下挪一行,调整相应指针。
2015-1-30 12:17
0
雪    币: 58
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
问题最终得到了解决,在导入表所在节添加可写入属性,猜测原因是程序初始化的时候会往IAT填写(导入函数真实地址)。
   不过我还有一点疑问就是,以前我做小PE的时候在PE头找空间折叠,却并未出现相关问题。同样在PE头,为什么会有差别呢?
   最后感谢一下MistHill
2015-2-1 08:47
0
雪    币: 7457
活跃值: (4186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
应该是一直要可写属性吧,加载器在加载的时候会将FIRSTTHUNK指向的IAT里的ITD数组改写为对应函数的真实地址,没有可写属性写不了吧。
2015-2-1 09:16
0
游客
登录 | 注册 方可回帖
返回
//