; ------------------------------------------------------------- ;
; KWINE is a fork of program PELoad written by 0CodErr
; author of fork - rgimad
; ------------------------------------------------------------- ;
ORG 0
BITS 32
; ------------------------------------------------------------- ;
PATH_SIZE      equ 4096
PARAMS_SIZE    equ 4096
STACK_SIZE     equ 4096
END_           equ IMAGE_BASE - (PATH_SIZE + PARAMS_SIZE + STACK_SIZE)
; ------------------------------------------------------------- ;
IMAGE_BASE     equ 400000H
; ------------------------------------------------------------- ;
MENUET01       db 'MENUET01'
version        dd 1
program.start  dd start_
program.end    dd END_
program.memory dd END_ + PATH_SIZE + PARAMS_SIZE + STACK_SIZE
program.stack  dd END_ + PATH_SIZE + PARAMS_SIZE + STACK_SIZE
program.params dd END_ + PATH_SIZE
program.path   dd END_
; ------------------------------------------------------------- ;
load.library:
        mov    eax, 68
        mov    ebx, 19
        mov    ecx, [esp + 4]
        int    64
        ret    4
; ------------------------------------------------------------- ;
getprocaddress:
        mov    edx, [esp + 8]
        xor    eax, eax
        test   edx, edx
        jz     .end
.next:
        xor    eax, eax
        cmp    [edx], dword 0
        jz     .end
        mov    esi, [edx]
        mov    edi, [esp + 4]
.next_:
        lodsb
        scasb
        jne    .fail
        or     al, al
        jnz    .next_
        jmp    .ok
.fail:
        add    edx, 8
        jmp    .next
.ok:
        mov    eax, [edx + 4]
.end:
        ret    8
; ------------------------------------------------------------- ;
realloc.app.mem:
        mov    eax, 64
        mov    ebx, 1
        mov    ecx, [esp + 4]
        int    64
        ret    4
; ------------------------------------------------------------- ;				
set.current.directory:
        mov    eax, 30
        mov    ebx, 1
        mov    ecx, [esp + 4]
        int    64
        ret    4			
; ------------------------------------------------------------- ;
%if 0 ; comment
int2str:
%define number [esp + 8 + 8 * 4]
%define buffer [esp + 4 + 8 * 4]
        pushad
		    mov    edi,  buffer
		    mov    eax, "    " ; 4 spaces
		    stosd
		    stosd
		    stosw
		    xor    al, al
		    stosb
				dec    edi
				dec    edi
				mov    ecx, 10
	      mov    eax, number
.next:
		    xor    edx, edx
		    div    ecx         ; ecx = 10
		    add    edx,  48    ; edx = (eax MOD ecx) + 48
		    mov    [edi], dl
		    dec    edi
		    test   eax, eax
		    jnz    .next
				popad
        ret    8
%undef number
%undef buffer
%endif ; endcomment
; ------------------------------------------------------------- ;
; test_file_path db "/hd3/1/mntest.exe",0
                        ; complex
                        ; address
                        ; data
                        ; hello
                        ; numbers  +-
                        ; proc
                        ; sptrim
                        ; se
                        ; clear
                        ; locals   +-
                        ; tokenise -
                        ; mntest
file_path      dd 0
lib_name       dd 0
lib            dd 0
func           dd 0
func_name      dd 0
; ------------------------------------------------------------- ;
sz_pe_load     db "KWINE",0
; ------------------------------------------------------------- ;
con_init            dd 0
con_write_asciiz    dd 0
con_exit            dd 0
console             dd 0
sz_con_init         db "con_init",0
sz_con_write_asciiz db "con_write_asciiz",0
sz_con_exit         db "con_exit",0
sz_console          db "/sys/lib/console.obj",0
; ------------------------------------------------------------- ;
MZ                   dw 0
PE                   dw 0
lfa_new              dd 0
NumberOfSections     dd 0
SizeOfOptionalHeader dd 0
EntryPoint           dd 0
SizeOfImage          dd 0
SizeOfHeaders        dd 0
DataDirectories      dd 0
SectionsTable        dd 0
Import               dd 0
; ------------------------------------------------------------- ;
ERROR_MESSAGE      dd 0
err_params         db "Parameters error",0
err_file_path      db "No input file path",0
err_read_file      db "Read file error",0
err_mz_not_found   db "No DOS signature found",0
err_pe_not_found   db "No PE signature found",0
err_load_library   db "Error load library: ",0
err_func_not_found db "Not found function: ",0
								 
; ------------------------------------------------------------- ;
%if 0 ; comment
msg_buffer resb 256
sz_new_line          db 10,0
sz_space             db " ",0
sz_space_colon_space db " : ",0
%endif ; endcomment
sz_empty             db "",0


start_:
; ------------------------------------------------------------- ;
; find params and file path
        ; mov    eax, test_file_path
        mov    eax, [program.params]
				cmp    [eax], byte 34 ; quote
				jne    .no_quote
        inc    eax
				mov    edi, eax
.find_quote_or_zero:
				cmp    [edi], byte 0
				je     .found
				cmp    [edi], byte 34 ; quote
        je     .found
        inc    edi	
        jmp    .find_quote_or_zero				
.no_quote:	
				mov    edi, eax
.find_space_or_zero:
				cmp    [edi], byte 0
				je     .found
				cmp    [edi], byte 32 ; space
        je     .found
        inc    edi	
        jmp    .find_space_or_zero				
.found:
				mov    [edi], byte 0
				mov    [file_path], eax
; check file path
        mov    eax, [file_path]
        mov    al, [eax]
				test   al, al
        jne     file_path_ok
				mov    [ERROR_MESSAGE], dword err_file_path
        jmp    ERROR
file_path_ok:
; check MZ signature (IMAGE_DOS_HEADER.e_magic)
        push   dword [file_path];filepath
        dec    esp
        mov    [esp], byte 0
        push   dword MZ;buffer
        push   dword 2;count
        push   dword 0
        push   dword 0;position
        push   dword 0
        mov    ebx, esp
        mov    eax, 70
        int    64
				test   eax, eax
        je     read_ok
				mov    [ERROR_MESSAGE], dword err_read_file
        jmp    ERROR
read_ok:
        cmp    word [MZ], "MZ"
        je     MZ_exists
				mov    [ERROR_MESSAGE], dword err_mz_not_found
        jmp    ERROR
MZ_exists:
; get lfa_new (IMAGE_DOS_HEADER.e_lfanew)
        push   dword [file_path];filepath
        dec    esp
        mov    [esp], byte 0
        push   dword lfa_new;buffer
        push   dword 4;count
        push   dword 0
        push   dword 60;position
        push   dword 0
        mov    ebx, esp
        mov    eax, 70
        int    64
; check PE signature (IMAGE_OPTIONAL_HEADER.Magic)
        push   dword [file_path];filepath
        dec    esp
        mov    [esp], byte 0
        push   dword PE;buffer
        push   dword 2;count
        push   dword 0
        push   dword [lfa_new];position
        push   dword 0
        mov    ebx, esp
        mov    eax, 70
        int    64
        cmp    word [PE], "PE"
        je     PE_exists
				mov    [ERROR_MESSAGE], dword err_pe_not_found
        jmp    ERROR
PE_exists:
; get size of headers (IMAGE_OPTIONAL_HEADER.SizeOfHeaders)
	      push   dword [file_path];filepath
        dec    esp
        mov    [esp], byte 0
        push   dword SizeOfHeaders;buffer
        push   dword 4;count
        push   dword 0
				mov    eax, [lfa_new]
				add    eax, 84
        push   eax;position
        push   dword 0
        mov    ebx, esp
        mov    eax, 70
        int    64
; resize	app memory and load headers
        mov    eax, IMAGE_BASE
        add    eax, [SizeOfHeaders]
        push   eax
				call   realloc.app.mem

	      push   dword [file_path];filepath
        dec    esp
        mov    [esp], byte 0
        push   dword IMAGE_BASE;buffer
        push   dword [SizeOfHeaders];count
        push   dword 0
        push   dword 0;position
        push   dword 0
        mov    ebx, esp
        mov    eax, 70
        int    64

        add    esp, (25 * 5) ; restore our stack top

				mov    edx, [lfa_new]
; get SizeOfImage (IMAGE_OPTIONAL_HEADER.SizeOfImage)
				mov    eax, [IMAGE_BASE + edx + 80]
				mov    [SizeOfImage], eax
; get EntryPoint (IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint)
				mov    eax, [IMAGE_BASE + edx + 40]
				mov    [EntryPoint], eax
; get DataDirectories (IMAGE_OPTIONAL_HEADER.DataDirectory)
				lea    eax, [edx + 120]
				mov    [DataDirectories], eax
; get SizeOfOptionalHeader (IMAGE_FILE_HEADER.SizeOfOptionalHeader)
				movzx  eax, word [IMAGE_BASE + edx + 20]
				mov    [SizeOfOptionalHeader], ax
; get SectionsTable
        lea    eax, [edx + 24]
        add    ax, [SizeOfOptionalHeader]
				mov    [SectionsTable], eax
; get Import
				mov    eax, IMAGE_BASE
				add    eax, [DataDirectories]
				add    eax, 1 * 8
				mov    eax, [eax]
				mov    [Import], eax
; get NumberOfSections (IMAGE_FILE_HEADER.NumberOfSections)
				movzx  eax, word [IMAGE_BASE + edx + 6]
				mov    [NumberOfSections], eax
; resize	app memory and load sections to their virtual address
        mov    eax, IMAGE_BASE
        add    eax, [SizeOfImage]
        push   eax
				call   realloc.app.mem

				mov    ecx, [NumberOfSections]
next_section:
        lea    eax, [ecx - 1]
        lea    eax, [eax * 4 + eax]
				lea    eax, [eax * 8]
				add    eax, IMAGE_BASE
				add    eax, [SectionsTable]

	      push   dword [file_path] ; filepath
        dec    esp
        mov    [esp], byte 0
				mov    edx, [eax + 12]
				add    edx, IMAGE_BASE
        push   edx               ; buffer   (IMAGE_SECTION_HEADER.VirtualAddress)
        push   dword [eax + 16]  ; count    (IMAGE_SECTION_HEADER.SizeOfRawData)
        push   dword 0
        push   dword [eax + 20]  ; position (IMAGE_SECTION_HEADER.PointerToRawData)
        push   dword 0
        mov    ebx, esp
        mov    eax, 70
        int    64

        dec    ecx
				jnz     next_section

        mov    eax, [NumberOfSections]
				lea    eax, [eax * 4 + eax]
				lea    eax, [eax * 4 + eax]
				add    esp, eax ; restore our stack top




; ==========================================================
%if 0 ; comment
        push   sz_console
        call   load.library
        ; mov    [console], eax
        mov    ecx, eax
        mov    ebx, getprocaddress
				push   ecx
				push   sz_con_init
				call   ebx
				mov    [con_init], eax
				push   ecx
				push   sz_con_write_asciiz
				call   ebx
				mov    [con_write_asciiz], eax
				push   ecx
				push   sz_con_exit
				call   ebx
				mov    [con_exit], eax
        push   sz_pe_load
        push   -1
        push   -1
        push   -1
        push   -1
        call   [con_init]			

				mov    ecx, [NumberOfSections]
next_sect:
        lea    eax, [ecx - 1]
        lea    eax, [eax * 4 + eax]
				lea    eax, [eax * 8]
				add    eax, IMAGE_BASE
				add    eax, [SectionsTable]
				push   eax

        push   eax
        call   [con_write_asciiz]
        push   sz_space_colon_space
        call   [con_write_asciiz]
	

				pop    eax
				add    eax, 20
				mov    eax, [eax]
        push   eax
				push   msg_buffer
				call   int2str
        push   msg_buffer
        call   [con_write_asciiz]

        push   sz_new_line
        call   [con_write_asciiz]


        dec    ecx
				jnz     next_sect
%endif ; endcomment				
; ==============================================
; program.path = program.path_without_filename & "lib/"
				mov    edi, [program.path]
				xor    al, al
				xor    ecx, ecx
				dec    ecx
				repne scasb
				std
				mov    al, "/"
				repne scasb
				cld
				inc    edi
				inc    edi
				mov    eax, "lib/"
				stosd
;				
				mov    [lib_name], edi

				xor    ecx, ecx
next_descriptor:
        lea    eax, [ecx * 4 + ecx]
				lea    eax, [eax * 4]				
				add    eax, IMAGE_BASE
				add    eax, [Import]
        mov    edx, [eax + 12]
				add    edx, IMAGE_BASE
				
%if 0 ; comment					
pushad							
        push   edx 
        call   [con_write_asciiz]
        push   sz_new_line
        call   [con_write_asciiz]			
popad
%endif ; endcomment	

pushad
; concatenate (program.path_without_filename & "lib/") & lib_name
        mov    esi, edx
				mov    edi, [lib_name]
.copy_lib_name:				
				lodsb
				stosb
				test   al, al
				jnz    .copy_lib_name
; try to load library			
			  push   dword [program.path]
			  call   load.library
				test   eax, eax
				jnz    .lib_loaded
; concatenate "Error load library: " & 	lib_name			
				sub    edi, [lib_name]
				mov    esi, edi
				mov    edi, err_load_library				
				xor    al, al
				xor    ecx, ecx
				dec    ecx
				repne scasb
				dec    edi
				mov    ecx, esi
				mov    esi, edx
				rep movsb
;							
popad
				mov    [ERROR_MESSAGE], dword err_load_library
        jmp    ERROR				
.lib_loaded:
        mov    [lib], eax			
popad
				xor    ebx, ebx
next_function:				
				mov    edx, [eax + 16]
				lea    esi, [edx + ebx * 4 + IMAGE_BASE]
				mov    [func], esi	
				mov    edx, [esi]
				test   edx, edx
				jz     .done
				inc    edx
				inc    edx
				add    edx, IMAGE_BASE		
				
%if 0 ; comment									
pushad			
        push   edx 
        call   [con_write_asciiz]
        push   sz_new_line
        call   [con_write_asciiz]
popad
%endif ; endcomment	

pushad
        mov    [func_name], edx
; look for address of imported function								
				push   dword [lib]
				push   edx
				call   getprocaddress
				test   eax, eax
				jnz    .func_found
popad				
; concatenate "Not found function: " & 	name of function			
				mov    edi, err_func_not_found				
				xor    al, al
				xor    ecx, ecx
				dec    ecx
				repne scasb
				dec    edi
        mov    esi, edx
.copy_func_name:				
				lodsb
				stosb
				test   al, al
				jnz    .copy_func_name
;										
        dec    edi
        mov    eax, " in "
				stosd

				mov    esi, [lib_name]
.copy_lib_name:				
				lodsb
				stosb
				test   al, al
				jnz    .copy_lib_name				

				mov    [ERROR_MESSAGE], dword err_func_not_found
        jmp    ERROR				
.func_found:						
				mov    edx, [func]
        mov    [edx], eax
popad								
				inc    ebx
				jmp    next_function
.done:				
				
        inc    ecx
        lea    eax, [ecx * 4 + ecx]
				lea    eax, [eax * 4]				
				add    eax, IMAGE_BASE
				add    eax, [Import]					
        mov    eax, [eax + 12]			
				cmp    eax, dword 0
				jnz    next_descriptor				
								
				
; set.current.directory				
				mov    edi, [file_path]
				xor    al, al
				xor    ecx, ecx
				dec    ecx
				repne scasb
				std
				mov    al, "/"
				repne scasb
				cld
				mov    [edi + 1], byte 0
				push   dword [file_path]
				call   set.current.directory
				mov    [edi + 1], byte "/" ; restore full file_path
				
				; ---------------------- ; 
				; call   load_console_lib  ;
				; ---------------------- ; 
				
; go to EntryPoint
        mov    eax, [EntryPoint]	
        add    eax, IMAGE_BASE
        jmp    eax
				
				
        ; push   dword [EntryPoint]
				; push   msg_buffer
				; call   int2str
        ; push   msg_buffer
        ; call   [con_write_asciiz]
				
%if 0 ; comment	
        push   0
        call   [con_exit]
%endif ; endcomment	

%if 0 ; comment	
; dump ---------------------------------------				
	      push   dword dump_path;filepath
        dec    esp
        mov    [esp], byte 0
        push   dword 0 ;buffer
        mov    eax, IMAGE_BASE
        add    eax, [SizeOfImage]						
        push   eax;count
        push   dword 0
        push   dword 0;position
        push   dword 2
        mov    ebx, esp
        mov    eax, 70
        int    64				
				
				
				xor    eax, eax
				dec    eax
				int    64
				
				dump_path db "/hd3/1/dump.bin",0
%endif ; endcomment					
; ==========================================================


ERROR:

        push   sz_console
        call   load.library
        ; mov    [console], eax
        mov    ecx, eax
        mov    ebx, getprocaddress
				push   ecx
				push   sz_con_init
				call   ebx
				mov    [con_init], eax
				push   ecx
				push   sz_con_write_asciiz
				call   ebx
				mov    [con_write_asciiz], eax
				push   ecx
				push   sz_con_exit
				call   ebx
				mov    [con_exit], eax

        push   sz_pe_load
        push   -1
        push   -1
        push   -1
        push   -1
        call   [con_init]
        push   dword [ERROR_MESSAGE]
        call   [con_write_asciiz]
        push   0
        call   [con_exit]

				xor    eax, eax
				dec    eax
				int    64



; load_console_lib:
        ; push   sz_console
        ; call   load.library

        ; push   eax
        ; push   sz_con_init
        ; call   getprocaddress
        ; mov    [con_init], eax
				
        ; push   sz_empty
        ; push   -1
        ; push   -1
        ; push   -1
        ; push   -1
        ; call   [con_init]

        ; ret