文章目录
- 在空白节插入代码
- 构造恶意代码
- 计算函数相对地址
- 修改入口地址
- 返回原地址
- 扩大节
- 新增节
对与一个程序我们需要在里面添加自己的功能,让程序增加一些我们的函数,那么我们就需要了解PE文件结构,然后对其进行修改,这里我们将基于程序包含的函数进行调用。
在空白节插入代码
在一个PE程序中,我们需要找到那里是我们可以修改的,对于文件头,节表,节数据等我们进行修改就会影响程序正常的功能,我们首先要找到一个空白区域。由于文件对齐的原因,开白节是最好的选择。
构造恶意代码
这里我们需要先构造我们要执行的语句,可以是好的语句,也可以是恶意的。
好的代码就是起壳的作用
恶意的代码就是shellcode
在刚开始时我们可以尝试调用程序已经存在的函数就可以,对于一个函数我们可以通过工具或其它方法查询其地址,然后我们构造命令:
E8 + 执行函数地址
E8对应汇编指令call,即调用函数
计算函数相对地址
这里我们假设该程序中存在一个messagebox的函数,我们先去确定其在内存的地址,然后:
地址 = messagebox的内存地址 - E8指令的地址 - 指令长度(5)
- messagebox的内存地址就是我们要调用的函数地址,
- call是相对地址,并且执行一条语句时,cs:ip指向的是下一条语句,所以还要减5的指令长度。
修改入口地址
这里我们要修改的入口地址是内存中的地址,让程序从我们的代码处开始执行。
imageBase + AddressOfEntryPoint = 我们的代码内存地址
imageBase + AddressOfEntryPoint指向内存中的程序入口地址,我们需要将其改为我们的代码地址
返回原地址
我们的目的不是破环程序的运行,因此我们还需要在执行完我们的程序后返回它原本的地址。
E9 原入口地址
E9是jump的机器码。
扩大节
如果我们需要插入的代码非常多,这个时候我们有两个方法,一个是扩大节,一个是增加节。
扩大节就是将原本的节空间变大,这里一般是扩大最后一个节
因为在扩大中间的时候,会改变后面节的起始地址,需要修改大量数据,而只扩大最后一个,涉及的修改较少
typedef struct _IMAGE_SECTION_HEADER
{BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //节的名字,只取8个字节union {DWORD PhysicalAddress;DWORD VirtualSize; } Misc; //双字 是该节在没有对齐前的真实尺寸,该值可以不准确。DWORD VirtualAddress; // 节区在内存中的偏移地址DWORD SizeOfRawData; // 在文件中对齐后的尺寸DWORD PointerToRawData; // 在文件中的偏移DWORD PointerToRelocations; // 在OBJ文件中使用DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics; // 节区属性字段
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
这里我们看到节表数据,里面涉及的成员只修改最后一个时是否涉及:
成员名称 | 表示意义 | 最后一个节是否涉及 |
---|---|---|
Misc | 对齐前的大小 | 涉及 |
VirtualAddress | 节区内存的偏移地址 | |
SizeOfRawData | 在文件中对齐后的大小 | 涉及 |
PointerToRawData | 在文件中的偏移 | |
SizeOfImage | 文件大小 | 涉及 |
最后一个成员是在扩展PE头中,后面是否涉及指的是只修改最后一个成员时是否需要修改。
新增节
新增加一个节来写我们的数据,这个操作需要首先对PE头里的成员有所了解。
- 在标准PE头中有一个节表数量的成员NumberOfSections
- 我们需要增加一个节表成员
- 计算节的偏移,内存大小,文件大小
- 修改 sizeofImage大小