Execute PE file on virtual memory

Hi everyone. I've been reversing some malware like ramnit and I noticed that they contain most of their codes in embedded executable programs and proceed to execute the program as if it's part of the parent program. This is different from process forking method since that creates a new process while this one just calls into the embedded program as if it's one of it's own function (well almost ). So here is a code I came up with that does just that. What it basically does is, it first maps the executable's different sections on to an executable memory region, it then imports and builds the IAT of the executable and finally performs relocation fix-ups and transfers control to the entry point of the executable after setting up ebx to point to PEB and eax to the EP. Since you can't always allocate on the preferred base address of the executable, relocation table is a MUST. This won't work on executables without relocation tables but that shouldn't matter if you are trying to obfuscate your own code since you can tell the compiler to include relocation tables when you recompile it. You can use this method as another layer of protection from AVs.

#include 
#include 
#include 
#include 
#include "mem_map.h"
 
HMODULE load_dll(const char *dll_name)
{
    HMODULE module;
 
    module = GetModuleHandle(dll_name);
    if (!module)
        module = LoadLibrary(dll_name);
    return module;
}
 
void *get_proc_address(HMODULE module, const char *proc_name)
{
    char *modb = (char *)module;
 
    IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER *)modb;
    IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS *)(modb + dos_header->e_lfanew);
    IMAGE_OPTIONAL_HEADER *opt_header = &nt_headers->OptionalHeader;
    IMAGE_DATA_DIRECTORY *exp_entry = (IMAGE_DATA_DIRECTORY *)
        (&opt_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
    IMAGE_EXPORT_DIRECTORY *exp_dir = (IMAGE_EXPORT_DIRECTORY *)(modb + exp_entry->VirtualAddress);
 
    void **func_table = (void **)(modb + exp_dir->AddressOfFunctions);
    WORD *ord_table = (WORD *)(modb + exp_dir->AddressOfNameOrdinals);
    char **name_table = (char **)(modb + exp_dir->AddressOfNames);
    void *address = NULL;
 
    DWORD i;
 
    /* is ordinal? */
    if (((DWORD)proc_name >> 16) == 0) {
        WORD ordinal = LOWORD(proc_name);
        DWORD ord_base = exp_dir->Base;
        /* is valid ordinal? */
        if (ordinal < ord_base || ordinal > ord_base + exp_dir->NumberOfFunctions)
            return NULL;
         
        /* taking ordinal base into consideration */
        address = (void *)(modb + (DWORD)func_table[ordinal - ord_base]);
    } else {
        /* import by name */
        for (i = 0; i < exp_dir->NumberOfNames; i++) {
            /* name table pointers are rvas */
            if (strcmp(proc_name, modb + (DWORD)name_table[i]) == 0)
                address = (void *)(modb + (DWORD)func_table[ord_table[i]]);
        }
    }
 
    /* is forwarded? */
    if ((char *)address >= (char *)exp_dir &&
        (char *)address < (char *)exp_dir + exp_entry->Size) {
        char *dll_name, *func_name;
        HMODULE frwd_module;
 
        dll_name = strdup((char *)address);
        if (!dll_name)
            return NULL;
        address = NULL;
        func_name = strchr(dll_name, '.');
        *func_name++ = 0;
 
        if (frwd_module = load_dll(dll_name))
            address = get_proc_address(frwd_module, func_name);
 
        free(dll_name);
    }
 
    return address;
}
 
#define MAKE_ORDINAL(val) (val & 0xffff)
int load_imports(IMAGE_IMPORT_DESCRIPTOR *imp_desc, void *load_address)
{
    while (imp_desc->Name || imp_desc->TimeDateStamp) {
        IMAGE_THUNK_DATA *name_table, *address_table, *thunk;
        char *dll_name = (char *)load_address + imp_desc->Name;
        HMODULE module;
 
        module = load_dll(dll_name);
        if (!module) {
            printf("error loading %s\n", dll_name);
            return 0;
        }
 
        name_table = (IMAGE_THUNK_DATA *)((char *)load_address + imp_desc->OriginalFirstThunk);
        address_table = (IMAGE_THUNK_DATA *)((char *)load_address + imp_desc->FirstThunk);
 
        /* if there is no name table, use address table */
        thunk = name_table == load_address ? address_table : name_table;
        if (thunk == load_address)
            return 0;
 
        while (thunk->u1.AddressOfData) {
            unsigned char *func_name;
            /* is ordinal? */
            if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
                func_name = (unsigned char *)MAKE_ORDINAL(thunk->u1.Ordinal);
            else
                func_name = ((IMAGE_IMPORT_BY_NAME *)((char *)load_address + thunk->u1.AddressOfData))->Name;
 
            /* address_table->u1.Function = (DWORD)GetProcAddress(module, (char *)func_name); */
            address_table->u1.Function = (DWORD)get_proc_address(module, (char *)func_name);
 
            thunk++;
            address_table++;
        }
        imp_desc++;
    }
    return 1;
}
 
void fix_relocations(IMAGE_BASE_RELOCATION *base_reloc, DWORD dir_size,
        DWORD new_imgbase, DWORD old_imgbase)
{
    IMAGE_BASE_RELOCATION *cur_reloc = base_reloc, *reloc_end;
    DWORD delta = new_imgbase - old_imgbase;    
 
    reloc_end = (IMAGE_BASE_RELOCATION *)((char *)base_reloc + dir_size);
    while (cur_reloc < reloc_end && cur_reloc->VirtualAddress) {
        int count = (cur_reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
        WORD *cur_entry = (WORD *)(cur_reloc + 1);
        void *page_va = (void *)((char *)new_imgbase + cur_reloc->VirtualAddress);
 
        while (count--) {
            /* is valid x86 relocation? */
            if (*cur_entry >> 12 == IMAGE_REL_BASED_HIGHLOW)
                *(DWORD *)((char *)page_va + (*cur_entry & 0x0fff)) += delta;
            cur_entry++;
        }
        /* advance to the next one */
        cur_reloc = (IMAGE_BASE_RELOCATION *)((char *)cur_reloc + cur_reloc->SizeOfBlock);
    }
}
 
IMAGE_NT_HEADERS *get_nthdrs(void *map)
{
    IMAGE_DOS_HEADER *dos_hdr;
    dos_hdr = (IMAGE_DOS_HEADER *)map;
    return (IMAGE_NT_HEADERS *)((char *)map + dos_hdr->e_lfanew);
}
 
/* returns EP mem address on success
* NULL on failure
*/
void *load_pe(void *fmap)
{
    IMAGE_NT_HEADERS *nthdrs;
    IMAGE_DATA_DIRECTORY *reloc_entry, *imp_entry;
    void *vmap;
    WORD nsections, i;
    IMAGE_SECTION_HEADER *sec_hdr;
    size_t hdrs_size;
    IMAGE_BASE_RELOCATION *base_reloc;
 
    nthdrs = get_nthdrs(fmap);
    reloc_entry = &nthdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    /* no reloc info? */
    if (!reloc_entry->VirtualAddress)
        return NULL;
    /* allocate executable mem (.SizeOfImage) */
    vmap = VirtualAlloc(NULL, nthdrs->OptionalHeader.SizeOfImage,
        MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!vmap)
        return NULL;
 
    /* copy the Image + Sec hdrs */
    nsections = nthdrs->FileHeader.NumberOfSections;
    sec_hdr = IMAGE_FIRST_SECTION(nthdrs);
    hdrs_size = (char *)(sec_hdr + nsections) - (char *)fmap;
    memcpy(vmap, fmap, hdrs_size);
    /* copy the sections */
    for (i = 0; i < nsections; i++) {
        size_t sec_size;
        sec_size = sec_hdr[i].SizeOfRawData;
        memcpy((char *)vmap + sec_hdr[i].VirtualAddress,
            (char *)fmap + sec_hdr[i].PointerToRawData, sec_size);
    }
 
    /* load dlls */
    imp_entry = &nthdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    if (!load_imports((IMAGE_IMPORT_DESCRIPTOR *)
        ((char *)vmap + imp_entry->VirtualAddress), vmap))
        goto cleanup;
    /* fix relocations */
    base_reloc = (IMAGE_BASE_RELOCATION *)((char *)vmap + reloc_entry->VirtualAddress);
    fix_relocations(base_reloc, reloc_entry->Size,
        (DWORD)vmap, nthdrs->OptionalHeader.ImageBase);
    return (void *)((char *)vmap + nthdrs->OptionalHeader.AddressOfEntryPoint);
cleanup:
    VirtualFree(vmap, 0, MEM_RELEASE);
    return NULL;
}
 
int vmem_exec(void *fmap)
{
    void *ep;
 
    ep = load_pe(fmap);
    if (!ep)
        return 0;
 
    __asm {
    mov ebx, fs:[0x30]
    mov eax, ep
    call    eax
    }
 
    return 1;
}

你可能感兴趣的:(Execute PE file on virtual memory)