入口点为0的程序

前几天群里有人给了个病毒样本

拿来一看很奇怪,是个exe文件,但入口点显示却是0

用OD加载后会提示出错:

 

之后问了一下同事,大概了解了一下原理:

Windows系统加载PE文件后,会通过PE文件的特定结构读取各种信息。

而该PE文件的各种信息都是完整的,可以正常被读取。

      相关的PE结构捡主要的在这里大概说一下:

      文件开始是一个IMAGE_DOS_HEADER的结构,以数据0x4D5A(ASCII字符为"MZ")开头的e_magic元素。从该结构体开头开始计算偏移量0x3c处为一个DWORD值——被称为e_lfanew,该值为IMAGE_NT_HEADER结构体(即俗称的PE头)的偏移量。PE头分三部分:第一部分是一个名为Signature的字段,固定为0x4550(ASCII字符为"PE");第二部分从PE头开始偏移0x4,名为FileHeader的结构;第三部分从PE头开始偏移0x18,名为OptionalHeader。这个OptionalHeader中的AddressOfEntryPoint与ImageBase两元素之和即是PE文件被加载到内存中运行时,正式开始执行功能的代码起始点。

该文件的AddressOfEntryPoint为0,而ImageBase为400000.

那么尝试在OD下用Ctrl+G查找该地址:

 

可见固定的e_magic元素被识别为了汇编指令dec ebp和pop edx

而后面的8个字节则是被人为修改的。

push edx是为了恢复前面"字符Z"被误认为是指令所造成的出栈操作

而后jmp到自己的修改过的一段代码处:

在运行到这个retn指令后,栈中出现的才是原本的程序入口点:

执行retn之后,程序会自动运行到这个入口点(本身还有一层UPX加壳):

 

总结一下:

其实就是将程序原本的入口点(AddressOfEntryPoint)修改为0,这样在加载PE文件的时候就会从文件的DOS头开始作为二进制指令开始执行。只要固定的e_magic不动就不会影响整体的PE结构识别,这样修改之后的几个字节,来实现向程序原本入口点的直接或间接跳转。

 

用以下代码可以轻松实现任意一个PE文件的修改(跳转方法没有用jmp,比较麻烦。采用了push+retn的方法,很直接):

[cpp]  view plain copy
  1. VOID ChangeExeOEP( PVOID pBuffer)  
  2. {  
  3.     /*将文件映射到内存,通过内存中的句柄获取文件DOS头*/  
  4.     PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;  
  5.     /*通过DOS头获取PE头*/  
  6.     PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + (DWORD)pBuffer);  
  7.     /*通过PE头中OptionalHeader结构中的AddressOfEntryPoint和ImageBase相加获取程序入口点*/  
  8.     DWORD dwOEP = pNtHeader->OptionalHeader.AddressOfEntryPoint + pNtHeader->OptionalHeader.ImageBase;  
  9.     /*初始化跳转数组,其中0x52和0x45分别为push edx指令和inc ebp,作用前面解释过。 
  10.     0x68为push指令,后面四个0x00为预留的原始入口点地址,0xC3为retn指令*/  
  11.     BYTE JmpArray[] = {0x4D,0x5A,0x52,0x45,0x68,0x00,0x00,0x00,0x00,0xC3};  
  12.     /*数组的第五位起填入之前预留的原始入口点地址*/  
  13.     *(DWORD*)(JmpArray + 5) = dwOEP;  
  14.     memcpy( pBuffer,JmpArray,10 );  
  15.     /*将AddressOfEntryPoint元素置零*/  
  16.     pNtHeader->OptionalHeader.AddressOfEntryPoint = 0;  
  17. }  

用该方法修改notepad.exe,以下是修改前和修改后的notepad.exe的对比。仅此两处修改,其余均未变:

修改之后notepad照常运行,而入口点却是0了:

 

就先写到这了,权当学习记录了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值