节表:
节表确定了节数据的属性,数量,大小等等;
BYTE name,节的自定义名字,常见.text等等,但这并不是固定的,多数加壳程序可以修改节的名字;
uniom{DWORD VirtualSize} Misc 在内存中实际的大小
DWORD VirtualAddress 在内存中的偏移,他加上扩展PE头中的ImageBase就是在内存中真正的地址;(换句话说,他是在内存中的)
DWORD SizeOfRawData 节在文件中的大小
DWORD PointerToRawData 节区在文件中的偏移 (换句话说,他是在文件中的)
DWORD Charactetistics 节的属性 //属性这种东西,就是将字节中的数据转化为二进制,然后对着属性表查看每一个标志位
注意:没有初始化的变量,在文件中是没有位置的;
但是他在内存中是有位置的;
所以在内存中的实际大小会大于在文件中的大小;展开数据时,以MAX的值为准;
----------------------------------------------------------
所谓的RVA还有FOA
RVA:在内存中的相对地址;
内存中的地址减去扩展PE头中IMAGE_BASE起始地址,得到这个差值;
要从未展开到内存中的文件中找到一个全局变量的地址,就是这节课的学习重点;使用差值和拉伸量,计算出在第几个节中;
回到文件系统这个节和偏移量找到全局变量修改即可;
---------------------------------------------------------
在PE空白区添加代码;
直接写代码是不存在的,因为目标文件编译之后都是一堆的0和1;
再上一步,就是硬编码;
所以我们的目标其实是将硬编码注入到目标的PE文件中;(注入的文件要是直接CALL)
也就是E8开头的CALL;
然后通过jmp指令跳回去,也就是E9指令;
首先,通过VS写出代码,到反汇编,复制出硬编码指令;
如果CALL是间接CALL(FF),则使用直接CALL的形式,CALL间接的地址;
间接地址与硬编码的转化形式:
地址-直接CALL本身所在的地址-5;
那么我们要运行的这个代码地址在哪?打开OD,进入user32模块,寻找我们要调用的那个函数,ctrl+N到函数列表,找到他的地址;现在还在第一阶段,所以这个做法仅对本机生效;
E8地址并不是直接用winhex拖入文件得到的地址,而是要在内存中的地址,也就是IMAGE_BASE+偏移;
复制出CALL的硬编码;
然后通过JMP跳回,复制出JMP的硬编码;这也就是我们需要添加的代码;
地址-跳转所在的地址-5;
入口:扩展PE头中有一个程序的入口,用IMAGE_BASE+这个入口的偏移,就是程序的入口;我们用JMP跳回入口;
改好之后就可以执行了吗?
不行,因为没人调用他;
所以我们要把程序入口点改成这里,运行完了再跳回去;
这个步骤简单,只要把入口地址改成我们硬编码的头地址即可;
在投机取巧的CALL地址时,我可以使用找到目标地址,直接书写CALL指令,然后复制出硬编码的形式进行操作;
-----------------------------------------------
扩大节:
使用的工具是UE
最好不要扩大前面的节,否则要修改的地方太多了;所以我们原则上只扩大最后一个节;
1,分配一块新的空间大小S,直接右键插入即可;
2,N="(SizeOfRawData或者VirtualSize内存对齐后的值+S)"
改的时候按照16进制加,别瞎加
这里,谁大选谁作为计算单位;
将最后一个节的SizeOfRawData和VirtualSize修改为N
SizeOfRawData:最后一个节在文件中对齐的大小
VirtualSize:最后一个节在内存中对齐的大小
3,修改SizeOfImage的大小
我们扩大节肯定是为了加执行代码,所以如果节属性中没有可执行的属性,我们还要在属性里修改一下
--------------------------------------------------
新增节:
扩大节有一点小弊端,一是自己的数据和文件原本的数据混在一起;
二是如果原本节的属性是只读,我们还要回去修改,麻烦;
1,首先观察exe节表中,是否有足够的空间,40个字节,能够让我们书写进一个节的属性;
2,在节表中新增成员(第一个节一般是代码节,可执行,所以复制一下美滋滋,不用改属性了)
3,修改PE头中节的数量;
4,修改SizeOfImage的大小;
5,在原有数据的最后,新增一个节的数据,这个数据必须是内存数据的整数倍;
6,修正新增节表的属性
---------------------------------------------------
合并节:
新增节必须要求目标文件节表拥有40个字节的空间能够让我们书写;
有程序没有这40个字节;
方法一:
如果目标程序没有被处理过,那么dos头的部分有一块dos块,这部分的数据是没用的.我们只需要在MZ头的尾部,PE指针位置修改PE开始的位置,然后将其覆盖掉即可.
也就是整个代码向上提;
方法二:
方法一种,如果目标被处理过,dos块和节表都没地方了,就需要用到合并节的方法.
1,按照内存对齐展开;
2,将第一个节的内存大小,文件大小改成一样;
3,将第一个节的属性改为包含所有节的属性;
4,修改节的数量为1;