format PE DLL GUI 0.8 at 7FF00000h entry start include '../../struct.inc' include '../../proc32.inc' include 'fpo.inc' include 'export.inc' include 'pe.inc' section '.text' code readable executable FS_STACK_MAX equ dword [fs:4] FS_STACK_MIN equ dword [fs:8] FS_SELF_PTR equ dword [fs:0x18] FS_ERRNO equ dword [fs:0x34] FS_SYSCALL_PTR equ dword [fs:0xC0] ENOMEM = 12 DLL_PROCESS_DETACH = 0 DLL_PROCESS_ATTACH = 1 DLL_THREAD_ATTACH = 2 DLL_THREAD_DETACH = 3 SYSCALL_METHOD_I40 = 1 SYSCALL_METHOD_SYSENTER = 2 SYSCALL_METHOD_SYSCALL = 3 ; Pointer to this structure is passed as the third argument ; to 'start' procedure by the kernel. struct kernel_init_data version dw ? flags dw ? syscall_method dd ? ; either one of SYSCALL_METHOD_xxx or pointer to procedure exe_base dd ? stack_base dd ? stack_size dd ? exe_path dd ? command_line dd ? environment dd ? ends include 'sync.inc' include 'malloc.inc' include 'peloader.inc' include 'modules.inc' include 'cmdline.inc' include 'thread.inc' proc syscall_int40 int 0x40 ret endp proc syscall_sysenter push ebp mov ebp, esp push @f sysenter @@: pop edx pop ecx ret endp proc syscall_syscall push ecx syscall pop ecx ret endp proc kercall jmp FS_SYSCALL_PTR endp prologue@proc equ fpo_prologue epilogue@proc equ fpo_epilogue proc start stdcall, dll_base, reason, reserved ; 1. Do nothing unless called by the kernel for DLL_PROCESS_ATTACH. cmp [reason], DLL_PROCESS_ATTACH jnz .nothing ; 2. Initialize process. ; 2a. Validate version of the init struct. ; If not known, say a debug message and die. mov ebp, [reserved] mov esi, [dll_base] cmp [ebp+kernel_init_data.version], 1 jnz .version_mismatch ; 2b. Get the system call code. ; Note: relocations have not been fixed yet, ; so we cannot use absolute addresses, only RVAs. mov eax, [ebp+kernel_init_data.syscall_method] cmp eax, 0x10000 jae .syscall_absolute dec eax mov edx, rva syscall_int40 cmp eax, num_syscall_methods jae @f mov edx, [esi+eax*4+rva syscall_methods] @@: lea eax, [edx+esi] .syscall_absolute: mov FS_SYSCALL_PTR, eax ; 2c. Fixup relocations so that we can use absolute offsets instead of RVAs ; in rest of code. ; Note: this uses syscalls, so this step should be done after ; configuring FS_SYSCALL_PTR at step 2b. push kolibri_dll call fixup_pe_relocations pop ecx jc .die ; 2d. Initialize process heap. mov eax, [ebp+kernel_init_data.exe_base] mov edx, [eax+STRIPPED_PE_HEADER.SizeOfHeapReserve] cmp word [eax], 'MZ' jnz @f add eax, [eax+IMAGE_DOS_HEADER.e_lfanew] mov edx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeapReserve] @@: malloc_init ; 2e. Allocate and fill MODULE structs for main exe and kolibri.dll. mov eax, [ebp+kernel_init_data.exe_path] @@: inc eax cmp byte [eax-1], 0 jnz @b sub eax, [ebp+kernel_init_data.exe_path] push eax add eax, sizeof.MODULE stdcall malloc, eax test eax, eax jz .die mov ebx, eax stdcall malloc, sizeof.MODULE + kolibri_dll.size test eax, eax jz .die mov edx, modules_list mov [edx+MODULE.next], ebx mov [ebx+MODULE.next], eax mov [eax+MODULE.next], edx mov [edx+MODULE.prev], eax mov [eax+MODULE.prev], ebx mov [ebx+MODULE.prev], edx push esi mov esi, kolibri_dll mov ecx, kolibri_dll.size lea edi, [eax+MODULE.path] rep movsb pop esi call init_module_struct mov eax, ebx mov esi, [ebp+kernel_init_data.exe_path] pop ecx lea edi, [ebx+MODULE.path] rep movsb mov esi, [ebp+kernel_init_data.exe_base] call init_module_struct ; 2f. Copy rest of init struct and free memory. ; Parse command line to argc/argv here and move arguments to the heap ; in order to save memory: init struct and heap use different pages, ; but typically data from init struct are far from the entire page, ; so moving it to heap does not increase actual physical heap size ; and allows to free init struct. mov eax, [ebp+kernel_init_data.stack_base] mov FS_STACK_MIN, eax add eax, [ebp+kernel_init_data.stack_size] mov FS_STACK_MAX, eax mov esi, [ebp+kernel_init_data.command_line] xor edx, edx xor edi, edi call parse_cmdline inc ebx ; argv[0] = exe path .argc equ dll_base .argv equ reason .envp equ reserved mov [.argc], ebx sub esi, [ebp+kernel_init_data.command_line] lea esi, [esi+(ebx+1)*4] stdcall malloc, esi test eax, eax jz .die mov [.argv], eax mov edx, eax lea edi, [eax+(ebx+1)*4] mov eax, [modules_list + MODULE.next] add eax, MODULE.path mov [edx], eax add edx, 4 mov esi, [ebp+kernel_init_data.command_line] call parse_cmdline and dword [edx], 0 ; argv[argc] = NULL and [.envp], 0 mov eax, 68 mov ebx, 13 mov ecx, ebp call FS_SYSCALL_PTR ; 2g. Initialize mutex for list of MODULEs. mov ecx, modules_mutex call mutex_init ; 2h. For console applications, call console.dll!con_init with default parameters. mov eax, [modules_list + MODULE.next] mov esi, [eax+MODULE.base] mov al, [esi+STRIPPED_PE_HEADER.Subsystem] cmp byte [esi], 'M' jnz @f mov eax, [esi+3Ch] mov al, byte [esi+eax+IMAGE_NT_HEADERS.OptionalHeader.Subsystem] @@: cmp al, IMAGE_SUBSYSTEM_WINDOWS_CUI jnz .noconsole stdcall dlopen, console_dll, 0 test eax, eax jz .noconsole stdcall dlsym, eax, con_init_str test eax, eax jz .noconsole mov edx, [modules_list + MODULE.next] stdcall eax, -1, -1, -1, -1, [edx+MODULE.filename] .noconsole: ; 3. Configure modules: main EXE and possible statically linked DLLs. mov eax, [modules_list + MODULE.next] mov esi, [eax+MODULE.base] add eax, MODULE.path push eax call fixup_pe_relocations pop ecx jc .die mutex_lock modules_mutex mov esi, [modules_list + MODULE.next] call resolve_pe_imports mov ebx, eax mutex_unlock modules_mutex test ebx, ebx jnz .die ; 4. Call exe entry point. mov esi, [esi+MODULE.base] mov edx, [esi+STRIPPED_PE_HEADER.AddressOfEntryPoint] cmp byte [esi], 'M' jnz @f mov ecx, [esi+IMAGE_DOS_HEADER.e_lfanew] add ecx, esi mov edx, [ecx+IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint] @@: add edx, esi pop ecx mov [process_initialized], 1 call edx ; If exe entry point has returned control, die. jmp .die .version_mismatch: lea eax, [esi + rva syscall_int40] mov FS_SYSCALL_PTR, eax add esi, rva msg_version_mismatch call sys_msg_board_str .die: or eax, -1 call FS_SYSCALL_PTR .nothing: ret endp proc sys_msg_board_str push eax ebx @@: push ecx mov cl, [ecx] test cl, cl jz @f mov eax, 63 mov ebx, 1 call FS_SYSCALL_PTR pop ecx inc ecx jmp @b @@: pop ecx ebx eax ret endp align 4 syscall_methods dd rva syscall_int40, rva syscall_sysenter, rva syscall_syscall num_syscall_methods = ($ - syscall_methods) / 4 align 4 data export export 'kolibri.dll' \ , kercall, 'kercall' \ , malloc, 'malloc' \ , free, 'free' \ , calloc, 'calloc' \ , realloc, 'realloc' \ , realloc_in_place, 'realloc_in_place' \ , memalign, 'memalign' \ , create_mspace, 'create_mspace' \ , destroy_mspace, 'destroy_mspace' \ , mspace_malloc, 'mspace_malloc' \ , mspace_free, 'mspace_free' \ , mspace_calloc, 'mspace_calloc' \ , mspace_realloc, 'mspace_realloc' \ , mspace_realloc_in_place, 'mspace_realloc_in_place' \ , mspace_memalign, 'mspace_memalign' \ , dlopen, 'dlopen' \ , dlclose, 'dlclose' \ , dlsym, 'dlsym' \ , create_thread, 'create_thread' \ , exit_thread, 'exit_thread' \ end data kolibri_dll db '/rd/1/lib/kolibri.dll',0 .size = $ - kolibri_dll console_dll db 'console.dll',0 con_init_str db 'con_init',0 msg_version_mismatch db 'S : Version mismatch between kernel and kolibri.dll',13,10,0 msg_bad_relocation db 'Bad relocation type in ',0 msg_newline db 13,10,0 msg_relocated1 db 'S : fixups for ',0 msg_relocated2 db ' applied',13,10,0 msg_noreloc1 db 'Module ',0 msg_noreloc2 db ' is not at preferred base and has no fixups',0 loader_debugboard_prefix db 'S : ',0 notify_program db '/rd/1/@notify',0 msg_cannot_open db 'Cannot open ',0 msg_paths_begin db ' in any of ' module_path1 db '/rd/1/lib/' .size = $ - module_path1 db ', ' module_path2 db '/kolibrios/lib/' .size = $ - module_path2 db ', ',0 msg_export_name_not_found db 'Exported function ',0 msg_export_ordinal_not_found db 'Exported ordinal #',0 msg_export_not_found db ' not found in module ',0 msg_unknown db '',0 msg_invalid_forwarder db 'Invalid forwarded export in module ',0 section '.data' data readable writable if FOOTERS malloc_magic dd ? end if default_heap dd ? modules_list rd 2 modules_mutex MUTEX process_initialized db ?