📄 binfmt_pe.c
字号:
} /* end pe_map *//* originally by binfmt_elf.c */static unsigned long randomize_stack_top(unsigned long stack_top){ unsigned int random_variable = 0; if (current->flags & PF_RANDOMIZE) random_variable = get_random_int() % (8*1024*1024);#ifdef CONFIG_STACK_GROWSUP return PAGE_ALIGN(stack_top + random_variable);#else return PAGE_ALIGN(stack_top - random_variable);#endif}/* * load_pe_binary */static int load_pe_binary(struct linux_binprm *bprm, struct pt_regs *regs){ IMAGE_DOS_HEADER *dos_hdr; struct win32_section *ws = NULL; struct win32_image_section *wis; unsigned long error; int retval = 0; unsigned long pe_entry, ntdll_load_addr = 0; unsigned long start_code, end_code, start_data, end_data; unsigned long reloc_func_desc = 0; unsigned long ntdll_entry; struct files_struct *files; int executable_stack = EXSTACK_DEFAULT; unsigned long def_flags = 0; unsigned long stack_top; unsigned long ret_addr = 0xdeadbeef; unsigned long start_address; unsigned long pe_brk = 0;#ifdef NTDLL_SO char *ntdll_name; unsigned long interp_load_addr; unsigned long interp_entry;#endif int maped = 0; struct win32_object *proc_obj, *thread_obj; struct eprocess *process; struct ethread *thread; struct ethread_cons_data etcd; PRTL_USER_PROCESS_PARAMETERS ppb; PKAPC thread_apc; /* check the DOS header */ retval = -ENOEXEC; dos_hdr = (IMAGE_DOS_HEADER *)bprm->buf; if (dos_hdr->e_magic != IMAGE_DOS_SIGNATURE || dos_hdr->e_lfanew <= 0) goto out; retval = -ENOMEM; ws = (struct win32_section *)kmalloc(sizeof(struct win32_section), GFP_KERNEL); if (!ws) goto out; memset(ws, 0, sizeof(*ws)); files = current->files; /* Refcounted so ok */ retval = unshare_files(); if (retval < 0) { kfree(ws); goto out; } if (files == current->files) { put_files_struct(files); files = NULL; } start_code = ~0UL; end_code = 0; start_data = 0; end_data = 0; /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) { kfree(ws); goto out; } /* Discard our unneeded old files struct */ if (files) { steal_locks(files); put_files_struct(files); files = NULL; } /* OK, This is the point of no return */ current->mm->start_data = 0; current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; current->mm->def_flags = def_flags; if ( !(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) current->flags |= PF_RANDOMIZE; arch_pick_mmap_layout(current->mm); /* Do this so that we can load the ntdll, if need be. We will change some of these later */ set_mm_counter(current->mm, rss, 0); current->mm->free_area_cache = current->mm->mmap_base; current->mm->cached_hole_size = 0; retval = setup_arg_pages(bprm, stack_top = randomize_stack_top(STACK_TOP), executable_stack); if (retval < 0) goto out_free_file; current->mm->start_stack = bprm->p; /* map PE image */ ws->ws_file = bprm->file; image_section_setup(ws); pe_map(ws, 0); maped = 1; /* Now we do a little grungy work by mmaping the PE image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ for (wis = ws->ws_sections; wis < ws->ws_sections + ws->ws_nsecs; wis++) { unsigned long k; if (wis->wis_character & IMAGE_SCN_TYPE_NOLOAD) continue; k = ws->ws_realbase + wis->wis_rva; /* * Check to see if the section's size will overflow the * allowed task size. Note that p_filesz must always be * <= p_memsz so it is only necessary to check p_memsz. */ if (k > TASK_SIZE || TASK_SIZE - wis->wis_size < k) /* Avoid overflows. */ goto out_free_file; if (wis->wis_character & IMAGE_SCN_MEM_EXECUTE) { start_code = k; end_code = k + wis->wis_rawsize; } else { if (!start_data) start_data = k; end_data = k + wis->wis_rawsize; } k += wis->wis_size; if (pe_brk < k) /* pe_brk used set mm->brk */ pe_brk = k; /* TODO: start_data and end_data, diff to ELF */ } current->mm->brk = pe_brk; /* extra page, used for interpreter ld-linux.so */ down_write(¤t->mm->mmap_sem); if ((extra_page = do_brk(pe_brk, PAGE_SIZE)) != pe_brk) { up_write(¤t->mm->mmap_sem); goto out_free_file; } up_write(¤t->mm->mmap_sem); current->mm->brk = pe_brk + PAGE_SIZE; ws->ws_entrypoint += ws->ws_realbase;#ifdef NTDLL_SO /* search ntdll.dll.so in $PATH, default is /usr/local/lib/wine/ntdll.dll.so */ ntdll_name = search_ntdll(bprm); /* map ntdll.dll.so */ LdrpMapSystemDll(current, ntdll_name, &ntdll_load_addr, &interp_load_addr); pe_entry = get_pe_entry(); ntdll_entry = get_ntdll_entry(); interp_entry = get_interp_entry();#endif reloc_func_desc = 0; set_binfmt(&pe_format); /* Create EPROCESS */ proc_obj = AllocObject(&process_objclass, NULL, NULL); if (IS_ERR(proc_obj)) { retval = PTR_ERR(proc_obj); goto out_free_file; } process = proc_obj->o_private; /* initialize EProcess and KProcess */ process->section_base_address = (void *)ws->ws_realbase; /* FIXME: PsCreateCidHandle */ /* Create PEB */ if ((retval = create_peb(process))) goto out_free_eproc; /* Create PPB */ create_ppb(&ppb, process, bprm, bprm->filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL); ((PEB *)process->peb)->ProcessParameters = ppb;#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES retval = arch_setup_additional_pages(bprm, executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); goto out; }#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC;#ifdef NTDLL_SO /* copy argv, env, and auxvec to stack, all for interpreter */ create_elf_tables(bprm, ntdll_load_addr, ntdll_phoff, ntdll_phnum, get_start_thunk());#endif /* Set the Esp */#ifdef CONFIG_STACK_GROWSUP ;#else /* setup user stack */ /* ------------- ----------- param PEB_BASE ------------- ----------- start_address entry point ------------- ----------- ret_addr 0xdeadbeef ------------- ----------- */ bprm->p = bprm->p //stack_top - sizeof(ret_addr) // return address, BAD address - sizeof(start_address) // image entry point - sizeof(unsigned long); // paramters for entry point current->mm->start_stack = bprm->p; start_address = ws->ws_entrypoint; *(unsigned long *)bprm->p = ret_addr; *(unsigned long *)(bprm->p + sizeof(ret_addr)) = start_address; *(unsigned long *)(bprm->p + sizeof(ret_addr) + sizeof(start_address)) = PEB_BASE;#endif current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->start_data = start_data; current->mm->end_data = end_data; current->mm->start_stack = bprm->p; if (current->personality & MMAP_PAGE_ZERO) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ down_write(¤t->mm->mmap_sem); error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); } /* allocate a Win32 thread object */ etcd.etcd_task = current; etcd.etcd_process = proc_obj; etcd.etcd_stack_top = stack_top; thread_obj = AllocObject(&thread_objclass, NULL, &etcd); if (IS_ERR(thread_obj)) { retval = PTR_ERR(thread_obj); goto out_free_eproc; } /* the thread object can now be put, since a reference is held * by the Linux task structure. Similarly the process object * is now referenced by the thread object and can also be put */ objput(proc_obj); objput(thread_obj); thread = thread_obj->o_private; /* set the teb */ thread->tcb.teb = create_teb(process, NULL, stack_top); if (IS_ERR(thread->tcb.teb)) { retval = PTR_ERR(thread->tcb.teb); goto out_free_file; } /* Init KThreaad */ KThreadInit(&thread->tcb, process); set_teb_selector((long)thread->tcb.teb); thread->start_address = (void *)pe_entry; /* FIXME */ /* init apc, to call LdrInitializeThunk */ thread_apc = kmalloc(sizeof(KAPC), GFP_KERNEL); if (!thread_apc) { retval = -ENOMEM; goto out_free_file; } KeInitializeApc(thread_apc, &thread->tcb, OriginalApcEnvironment, PspThreadSpecialApc, NULL, (PKNORMAL_ROUTINE)ntdll_entry, UserMode, (void *)(bprm->p + 12)); KeInsertQueueApc(thread_apc, (void *)interp_entry, (void *)extra_page, IO_NO_INCREMENT);#ifndef TIF_APC#define TIF_APC 13#endif set_tsk_thread_flag(current, TIF_APC);#ifdef ELF_PLAT_INIT /* * The ABI may specify that certain registers be set up in special * ways (on i386 %edx is the address of a DT_FINI function, for * example. In addition, it may also specify (eg, PowerPC64 ELF) * that the e_entry field is the address of the function descriptor * for the startup routine, rather than the address of the startup * routine itself. This macro performs whatever initialization to * the regs structure is required as well as any relocations to the * function descriptor entries when executing dynamically links apps. */ ELF_PLAT_INIT(regs, reloc_func_desc);#endif start_thread(regs, pe_entry, bprm->p); if (unlikely(current->ptrace & PT_PTRACED)) { if (current->ptrace & PT_TRACE_EXEC) ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); else send_sig(SIGTRAP, current, 0); } /* save current trap frame */ thread->tcb.trap_frame = (struct ktrap_frame *)regs; retval = 0; /* return from w32syscall_exit, not syscall_exit */ ((unsigned long *)regs)[-1] = (unsigned long)w32syscall_exit; asm volatile ("mov %0, %%fs\n" : : "r"(TEB_SELECTOR));out: return retval; /* error cleanup */out_free_eproc: objput(proc_obj); goto out_free_file;out_free_file: if (files) { put_files_struct(current->files); current->files = files; } /* free win32_section, if not mapped */ if (!maped && ws) { if (ws->ws_sections) kfree(ws->ws_sections); kfree(ws); } send_sig(SIGKILL, current, 0); goto out;} /* end load_pe_binary *//* * PspThreadSpecialApc */voidSTDCALLPspThreadSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2){ ktrace("PspThreadSpecialApc\n"); kfree(Apc);} /* end PspThreadSpecialApc */int __init init_pe_binfmt(void){ return register_binfmt(&pe_format);}void __exit exit_pe_binfmt(void){ /* Remove the COFF and ELF loaders. */ unregister_binfmt(&pe_format);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -