作用:将一个源EXE文件(一般是我们自己编写的)附加在一个目标EXE(一般是由他人编写的)文件上,使其能在目标文件执行之前执行
dos命令:attach_img dst_file src_file

创作动机:
        在看完罗云彬的《WIN32汇编》和看雪论坛的《加密解密》,对PE格式有了一定的了解,于是便想写一个简单对话框,在上面写一首诗,然后把这个对话框,附加两条美丽的鱼上,送给自己喜欢的女孩子,这样这个女孩子一点这条鱼就会弹出看到我写给他的诗,关闭个框子后,鱼就游起来了。但是这两条鱼并不是我写的,所以要想达到这个目标,必须利用PEDIY技术。于是我先写了一个简单的MessageBox程序作测试,整个程序非常简单,仅仅只有一句代码,invoke MessageBox...,结果成功了。但是整个过程却极其麻烦。主要体现在对于全局符变量的引用,和dll中函数的引用,即费时又费力。于是便有了创作一个这样软件的想法,写一个程序,让这个程序帮我完成附加PE的功能,而我只需要专注于对话框程序的开发即可。

原理:
第一步,将源文件附加在目标文件上,然后新建一个节做为入口点,先调用源文件的入口点,再调用目标文件的入口点即可。这个过程非常简单,仅仅只需要将源文件的各个节解析出来,加在目标文件上即可。加入口点的节也不是太麻烦。但是在完成这个步聚之前,有三个极需要解决的问题,重定位源文件,输入表的整合,资源表的整合。

第二步,重定位源文件。
假设目标文件有如下两个节:
名称        Voffset        vSize
.dsttext        1000           100
.dstdata       2000           100
源文件有如下两个节:
名称        Voffset        vSize
.srctext        3000           100
.srcdata       4000           100

我们将源文件的附加在目标文件后,得到的EXE文件的节应该是这样:
名称        Voffset        vSize
.dsttext        1000           100
.dstdata       2000           100
.srctext        3000           100
.srcdata       4000           100

我们注意到源文件的每个节的RVA都发生了变化,这会带来以下问题,如果源文件有对全局符号的引用,该怎么办,假源文件中有如下语句mov eax,[402000],则此句在新的exe文件中则应该是mov eax,[404000]。也就是说对于源文件中每个对全局符号引用的地方都需要加上2000h(在此例中)。问题就在于,我们怎么能知道源EXE文件中有哪些地方引用了全局符号呢?这使我想到了dll的重定位,在链接dll的时候,在重定位表中会有对每个全局符号引用的记录。当系统装入dll的时候,就根据重位表中的数据,修正对每个全局符号的引用。
也就是说,只要有重定位表,我们就可以对源程序进行重定位操作了。但是我们的源程序是exe并不是dll,exe默认是没有重定位表的,该怎么办呢。能不能在链接的时候让链接器指定某个链接选项,让链接器对EXE也生成重定位表呢。实践表明,当使用/debug选项进行链接的时候,生成的EXE文件中会有重定位表。如果源程序是在visual stdio中用C写的,则不用管,因为visual stdio建立的工程,默认都是debug版的。

第二步,是对输入表的整合,这个应该并不复杂。稍有点PE常识的人应该都能完成。新建一个节,将源文件和目标文件的输入表合并,放在这个节中,最后修改目录表中的输入表地址为这个段即可。在此不做过多介绍。


第三步,是对资源表的整合,这个就有点复杂了,因为资源表的结构是个递归。但是也不是个大问题。有一点需要注意,我们在编写源程序的时候,要保证源程序的资源ID不要和目标文件的资源ID冲突,否则则可能会出现源程序获取到的资源是目标文件 的,或者目标文件获取的资源是源程序的问题。

有了以上几步,整个程序也就算是结束了,但是还有一个问题需要考虑,如果源程序中调用了ExitProcess方法退出了进程,那么目标程序就得不到执行了,如果源程序使用汇编编写也罢,自己控制下就可以了,但是如果源程序是使用C编写的,这个就不好搞了,因为C在main函数执行完成后,总会调用exit方法退出进程。针对这个问题的解决方案如下,我们在源程序执行之前,将输入表中exitprocess函数和cexit函数的地址,改为目标程序的入口点。这样当源程序中调用了exitprocess等退出进程的函数的时候,就自动跳到目标程序去执行了。当然这个方法有一个缺点就是,使得attach_img.exe这个程序变得在附加源程序的时候变得和语言有关了,试想VB的退出函数是什么,还有其他很多语言,他们的退出函数又是什么。由于,我只悉C和汇编两语言,所以也只对这两种语言进行了支持。

另外在编写源程序的时候,还需要注意以下两点:

如果源程序是便用C编写,并且调用了C的标准库函数,则对C标准库,请使用静态链接的方式,不要使用动态链接库进行链接,否则运行时会出现,找不到msvcrt.dll的错误,造成此问题的原因是因为,windows在加载msvcrt.dll时,此dll必需在资源类型为RT_MANIFEST的清单资源,或者与exe同目录,同名的.manifest清单文件中声明中声明。否则windows将拒绝加载,理论上来说,这个我也可以支持,但是精力有限,大家还是用静态链接吧!在visual stdio中如下设置即可,项目-》属性-》c/c++=>代码生成-》运行时库,选择/mt或者/mtd。

2.对于winmain函数的第一个参数hInstance,重新赋值,hInstance=GetModuleHandle(NULL),这个参数不知道为什么不正确了,重新赋值即可。


归纳起来,在编写源程序时,需要注意以下三点:
1./debug进行链接
2.静态链接C运行时库
3.hInstance重新赋值
剩下的就交给attach_img.exe来完成吧!

附件是程序的源码,以下是对各个文件的简介:
attach_img.inc 头文件,包含声明
attach_img.asm  入口文件,解析命令行参数等
append_img.asm 逻辑控制
reloc.asm 重定位操作
import _table.asm 输入表]操作
res_table.asm 资源表操作
section.asm 节操作
tht_main.asm 新建入口点节,以及修正退出函数
tools.asm 工具类

如果你在使用中发现BUG,可发邮件至814536434@qq.com或者taohongtao@zhangyue.com。也希望大家能够对这个程序继续完善,比如,对dll附加的支持,将源程序附加在任何位置等。

上传的附件 attach_img.rar