Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2016. All rights reserved.      ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. ; Checks whether the given file is already loaded as PE.
  9. ; If so, returns pointer to PEDESCR which can be used for map_pe_usermode.
  10. ;   out: eax = 0, ebx undefined
  11. ;   out: esi -> PEDESCR
  12. ; If not, loads the given file; if it is PE, creates PEDESCR;
  13. ;   out: eax -> file data, ebx = file size
  14. ;   out: esi -> PEDESCR
  15. ; if it is not PE, returns loaded file as is.
  16. ;   out: eax -> file data, ebx = file size
  17. ;   out: esi = 0
  18. ; On error:
  19. ;   out: eax = negative error code, ebx = 0
  20. ;   out: esi = 0
  21. proc load_file_maybe_pe stdcall uses edi, file_name:dword
  22.     locals
  23.       fileinfo rb 40
  24.       filedata dd ?
  25.       defaultbase dd ?
  26.       entry dd ?
  27.       stacksize dd ?
  28.     endl
  29.         and     [filedata], 0
  30. ; 1. Lock the common mutex for PE list.
  31.         mov     ecx, pe_list_mutex
  32.         call    mutex_lock
  33. ; 2. Check whether this PE file is already mapped somewhere.
  34. ; 2a. Get the timestamp. If failed, pass filesystem error to the caller.
  35.         lea     eax, [fileinfo]
  36.         stdcall get_fileinfo, [file_name], eax
  37.         mov     edi, eax
  38.         neg     edi
  39.         jnz     .fail_unlock
  40. ; 2b. Scan the list of PE files, for each file compare timestamp and name.
  41. ; If all parameters match, go to 6. Otherwide, proceed to 3.
  42.         mov     esi, [pe_list.fd]
  43. .scan_existing:
  44.         cmp     esi, pe_list
  45.         jz      .load_new
  46.         mov     eax, dword [fileinfo+24]; last modified time
  47.         mov     edx, dword [fileinfo+28]; last modified date
  48.         cmp     dword [esi+PEDESCR.timestamp], eax
  49.         jnz     .continue_scan
  50.         cmp     dword [esi+PEDESCR.timestamp+4], edx
  51.         jnz     .continue_scan
  52.         stdcall strncmp, [esi+PEDESCR.name], [file_name], -1
  53.         test    eax, eax
  54.         jz      .already_loaded
  55. .continue_scan:
  56.         mov     esi, [esi+PEDESCR.fd]
  57.         jmp     .scan_existing
  58.  
  59. ; Either this file is not PE, or it has not been mapped yet.
  60. .load_new:
  61. ; 3. Load and unpack file data.
  62. ; If failed, return -5 "file not found".
  63.         stdcall load_file, [file_name]
  64.         movi    edi, -5
  65.         test    eax, eax
  66.         jz      .fail_unlock
  67.         mov     [filedata], eax
  68.         mov     dword [fileinfo+32], ebx
  69. ; 4. Check that the file is valid PE, has image data and is not too large.
  70. ; If not, pass the loaded file to the caller as is.
  71.         cmp     ebx, 40h
  72.         jb      .not_pe
  73.         cmp     word [eax], 'MZ'
  74.         jz      .check_mz
  75.         cmp     [eax+STRIPPED_PE_HEADER.Signature], STRIPPED_PE_SIGNATURE
  76.         jnz     .not_pe
  77.         mov     ecx, [eax+STRIPPED_PE_HEADER.SizeOfStackReserve]
  78.         mov     [stacksize], ecx
  79.         mov     ecx, [eax+STRIPPED_PE_HEADER.ImageBase]
  80.         mov     esi, [eax+STRIPPED_PE_HEADER.SizeOfImage]
  81.         mov     edi, [eax+STRIPPED_PE_HEADER.AddressOfEntryPoint]
  82.         jmp     .pe
  83. .check_mz:
  84.         mov     ecx, [eax+3Ch]
  85.         add     eax, ecx
  86.         add     ecx, IMAGE_NT_HEADERS.OptionalHeader
  87.         jc      .not_pe
  88.         cmp     ecx, ebx
  89.         ja      .not_pe
  90.         cmp     [eax+IMAGE_NT_HEADERS.Signature], 'PE'
  91.         jnz     .not_pe
  92.         movzx   edx, [eax+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader]
  93.         cmp     edx, IMAGE_OPTIONAL_HEADER32.DataDirectory
  94.         jb      .not_pe
  95.         add     ecx, edx
  96.         jc      .not_pe
  97.         cmp     ecx, ebx
  98.         ja      .not_pe
  99.         cmp     [eax+IMAGE_NT_HEADERS.OptionalHeader.Magic], 10Bh
  100.         jnz     .not_pe
  101.         mov     ecx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfStackReserve]
  102.         mov     [stacksize], ecx
  103.         mov     ecx, [eax+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
  104.         mov     esi, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage]
  105.         mov     edi, [eax+IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint]
  106. .pe:
  107.         test    esi, esi
  108.         jz      .not_pe
  109.         cmp     esi, 16*1024*1024
  110.         ja      .not_pe
  111.         mov     [defaultbase], ecx
  112.         mov     [entry], edi
  113.         add     esi, 0xFFF
  114.         shr     esi, 12
  115. ; 5. Allocate and initialize PEDESCR structure.
  116. ; 5a. Calculate structure size: sizeof.PEDESCR + dword per image page + size of PE name.
  117.         mov     edi, [file_name]
  118.         mov     ecx, -1
  119.         xor     eax, eax
  120.         repnz scasb
  121.         not     ecx
  122.         lea     eax, [ecx+esi*4+sizeof.PEDESCR]
  123. ; 5b. Allocate memory.
  124. ; If failed, return -30 "no memory".
  125.         push    ecx
  126.         call    malloc
  127.         pop     ecx
  128.         movi    edi, -30
  129.         test    eax, eax
  130.         jz      .fail_and_free_data
  131. ; 5c. Initialize PEDESCR structure.
  132.         mov     [eax+PEDESCR.size], esi
  133.         lea     edi, [eax+esi*4+sizeof.PEDESCR]
  134.         mov     esi, [file_name]
  135.         mov     [eax+PEDESCR.name], edi
  136.         rep movsb
  137.         mov     esi, eax
  138.         lea     edi, [eax+sizeof.PEDESCR]
  139.         mov     ecx, [eax+PEDESCR.size]
  140.         xor     eax, eax
  141.         rep stosd
  142.         mov     eax, dword [fileinfo+24]
  143.         mov     dword [esi+PEDESCR.timestamp], eax
  144.         mov     eax, dword [fileinfo+28]
  145.         mov     dword [esi+PEDESCR.timestamp+4], eax
  146.         mov     eax, [defaultbase]
  147.         mov     [esi+PEDESCR.defaultbase], eax
  148.         mov     eax, [entry]
  149.         mov     [esi+PEDESCR.entry], eax
  150.         mov     eax, [stacksize]
  151.         mov     [esi+PEDESCR.stacksize], eax
  152.         and     dword [esi+PEDESCR.refcount], 0; no SMAPs yet; later it will be incremented
  153.         lea     ecx, [esi+PEDESCR.page_array_lock]
  154.         call    mutex_init
  155. ; 5d. Insert PEDESCR structure in tail of the common list.
  156.         mov     [esi+PEDESCR.fd], pe_list
  157.         mov     eax, [pe_list.bk]
  158.         mov     [pe_list.bk], esi
  159.         mov     [esi+PEDESCR.bk], eax
  160.         mov     [eax+PEDESCR.fd], esi
  161. .already_loaded:
  162. ; We have got the PEDESCR structure,
  163. ; either already-existed from step 2 or created at step 5.
  164. ; In the last case we have also got the file data,
  165. ; in the first case [filedata] is still zero.
  166. ; 6. Increment reference counter in PEDESCR structure.
  167.         inc     [esi+PEDESCR.refcount]
  168. ; 7. Release the common mutex for PE list.
  169. ; We have got a new reference to our PEDESCR, it will not go away unexpectedly.
  170.         mov     ecx, pe_list_mutex
  171.         call    mutex_unlock
  172.         mov     eax, [filedata]
  173.         mov     ebx, dword [fileinfo+32]
  174.         ret
  175. .fail_and_free_data:
  176.         stdcall kernel_free, [filedata]
  177. .fail_unlock:
  178.         mov     ecx, pe_list_mutex
  179.         call    mutex_unlock
  180. .fail:
  181.         mov     eax, edi
  182.         xor     ebx, ebx
  183.         xor     esi, esi
  184.         ret
  185. .not_pe:
  186.         mov     ecx, pe_list_mutex
  187.         call    mutex_unlock
  188.         mov     eax, [filedata]
  189.         xor     esi, esi
  190.         ret
  191. endp
  192.  
  193. proc map_pe_usermode stdcall uses ebx esi edi, descr:dword, filedata:dword, filesize:dword
  194.            locals
  195.              img_base     dd ?
  196.              peheader     dd ?
  197.              header_size  dd ?
  198.              num_sections dd ?
  199.              sections     dd ?
  200.              section_idx  dd ?
  201.              page_index   dd ?
  202.              page_offset  dd ?
  203.              cur_page     dd ?
  204.              cur_access   db ?
  205.                           rb 3
  206.              pages        dd ?
  207.              num_allocated_pages dd ?
  208.            endl
  209.  
  210. ; 1. Basic preparations.
  211. ; 1a. Check that the process heap has been initialized.
  212. ; Return -30 "no memory" if not.
  213.         mov     esi, [descr]
  214.         movi    edi, -30
  215.         mov     eax, [current_process]
  216.         cmp     [eax+PROC.heap_top], 0
  217.         jz      .fail_dereference
  218. ; 1b. If filedata is passed, fill the required fields from header now.
  219.         mov     eax, [filedata]
  220.         mov     ebx, [filesize]
  221.         dec     edi ; -30 -> -31
  222.         test    eax, eax
  223.         jz      @f
  224.         call    .validate_header
  225.         jc      .fail_dereference
  226. @@:
  227.  
  228. ; 2. Generate array of pages for mapping in address space in the process.
  229. ; It is possible to join this step with step 13, avoiding temporary allocation
  230. ; and putting the result directly in the page table, but that would require
  231. ; doing potentially long operations like loading/unpacking the file
  232. ; while holding address space lock, which could block other threads
  233. ; that just want to lazy-allocate their zero-only pages not related to PE.
  234. ; So, keep generating and mapping separate.
  235. ; 2a. Allocate memory.
  236.         inc     edi ; -31 -> -30
  237.         mov     eax, [esi+PEDESCR.size]
  238.         shl     eax, 2
  239.         call    malloc
  240.         test    eax, eax
  241.         jz      .fail_dereference
  242.         mov     [pages], eax
  243. ; 2b. Acquire the lock.
  244.         lea     ecx, [esi+PEDESCR.page_array_lock]
  245.         call    mutex_lock
  246. ; 2c. Prepare for loop over pages: set page index and page offset to zero.
  247.         xor     ecx, ecx
  248.         mov     [page_index], ecx
  249.         mov     [page_offset], ecx
  250.         mov     [num_allocated_pages], ecx
  251. .fill_pages:
  252. ; 2d. For each page, test whether we need to regenerate it.
  253. ; Pages that need to be regenerated are marked as zero in pages array.
  254.         mov     eax, [esi+sizeof.PEDESCR+ecx*4]
  255.         test    eax, eax
  256.         jz      .create_page
  257. ; 2e. For each page that we do not need to regenerate,
  258. ; increment reference counter if it is less than 0xFF
  259. ; and go to 2t.
  260.         lea     edx, [eax+1]
  261.         test    edx, 0xFF
  262.         jz      .page_created
  263.         mov     [esi+sizeof.PEDESCR+ecx*4], edx
  264.         jmp     .page_created
  265. .create_page:
  266. ; 2f. If the file has not been already loaded/unpacked,
  267. ; do it now, validating the content.
  268.         cmp     [filedata], 0
  269.         jnz     @f
  270.         stdcall load_file, [esi+PEDESCR.name]
  271.         test    eax, eax
  272.         jz      .fail_free_pages
  273.         call    .validate_header
  274.         jc      .fail_free_pages
  275. @@:
  276. ; 2h. Initialize for generating a page:
  277. ; do not allocate a page until we will be sure that data are present,
  278. ; there are no access rights yet.
  279.         and     [cur_page], 0
  280.         mov     [cur_access], 0
  281. ; 2i. Check whether the page overlaps file header.
  282. ; If not, go to 2m.
  283.         mov     eax, [page_offset]
  284.         cmp     eax, [header_size]
  285.         jae     .no_header
  286. ; 2j. Allocate the page data.
  287.         stdcall kernel_alloc, 0x1000
  288.         test    eax, eax
  289.         jz      .fail_free_pages
  290.         mov     [cur_page], eax
  291. ; 2k. Set access rights for header: readonly; copy header data.
  292.         mov     [cur_access], IMAGE_SCN_MEM_READ shr 28
  293.         mov     esi, [filedata]
  294.         mov     edi, eax
  295.         add     esi, [page_offset]
  296.         mov     ecx, [header_size]
  297.         sub     ecx, [page_offset]
  298.         cmp     ecx, 0x1000
  299.         jb      @f
  300.         mov     ecx, 0x1000
  301. @@:
  302.         mov     edx, ecx
  303.         shr     ecx, 2
  304.         rep movsd
  305.         mov     ecx, edx
  306.         and     ecx, 3
  307.         rep movsb
  308. ; 2l. Fill the rest of the page with zeroes.
  309.         mov     ecx, 0x1000
  310.         sub     ecx, edx
  311.         mov     edx, ecx
  312.         shr     ecx, 2
  313.         and     edx, 3
  314.         xor     eax, eax
  315.         rep stosd
  316.         mov     ecx, edx
  317.         rep stosb
  318. .no_header:
  319. ; 2m. Prepare for loop over sections.
  320. ; Skip the loop if there are no sections.
  321.         mov     eax, [num_sections]
  322.         mov     ebx, [sections]
  323.         test    eax, eax
  324.         jz      .no_sections
  325.         mov     [section_idx], eax
  326. .sections_loop:
  327. ; 2n. For every section, check whether it has data overlapped with
  328. ; the current page; if so, allocate the page if not yet, copy the data
  329. ; and fill rest of page with zeroes.
  330. ; If data are present, there can be two cases:
  331. ; - the current page has data from the beginning,
  332. ; - first byte of the current page is not covered by the section.
  333. ; The first case is typical, the second case is rare.
  334. ; If the page has not been allocated yet, we can optimize by storing zeroes
  335. ; only in areas that are not covered by the current section.
  336. ; However, this becomes twisted in the second case,
  337. ; so don't bother to optimize the rare case.
  338.         cmp     [ebx+COFF_SECTION.SizeOfRawData], 0
  339.         jz      .section_data_done
  340.         mov     esi, [page_offset]
  341.         sub     esi, [ebx+COFF_SECTION.VirtualAddress]
  342.         cmp     esi, [ebx+COFF_SECTION.SizeOfRawData]
  343.         jb      .beginning_inside
  344.         add     esi, 1000h
  345.         jnc     .section_data_done
  346.         jz      .section_data_done
  347. ; Rare case: there is an overlap, but the first byte is not covered.
  348. ; If the page has not been allocated, allocate it now and store 4K zeroes.
  349.         cmp     [cur_page], 0
  350.         jnz     @f
  351.         stdcall kernel_alloc, 0x1000
  352.         test    eax, eax
  353.         jz      .fail_free_pages
  354.         mov     [cur_page], eax
  355.         mov     edi, eax
  356.         xor     eax, eax
  357.         mov     ecx, 0x1000/4
  358.         rep stosd
  359. @@:
  360.         mov     edi, [ebx+COFF_SECTION.VirtualAddress]
  361.         and     edi, 0xFFF
  362.         xor     esi, esi
  363. .copy_data:
  364.         mov     eax, [ebx+COFF_SECTION.SizeOfRawData]
  365.         sub     eax, esi
  366.         mov     ecx, 0x1000
  367.         sub     ecx, edi
  368.         add     edi, [cur_page]
  369.         cmp     ecx, eax
  370.         jb      @f
  371.         mov     ecx, eax
  372. @@:
  373.         add     esi, [filedata]
  374.         add     esi, [ebx+COFF_SECTION.PtrRawData]
  375.         mov     edx, ecx
  376.         shr     ecx, 2
  377.         and     edx, 3
  378.         rep movsd
  379.         mov     ecx, edx
  380.         rep movsb
  381.         jmp     .section_data_done
  382. .beginning_inside:
  383. ; Normal case: do not store zeroes which will be immediately overwritten.
  384.         xor     edi, edi
  385.         cmp     [cur_page], edi
  386.         jnz     .copy_data
  387.         stdcall kernel_alloc, 0x1000
  388.         test    eax, eax
  389.         jz      .fail_free_pages
  390.         mov     [cur_page], eax
  391.         mov     edi, eax
  392.         mov     ecx, [ebx+COFF_SECTION.SizeOfRawData]
  393.         sub     ecx, esi
  394.         cmp     ecx, 0x1000
  395.         jb      @f
  396.         mov     ecx, 0x1000
  397. @@:
  398.         add     esi, [filedata]
  399.         add     esi, [ebx+COFF_SECTION.PtrRawData]
  400.         mov     edx, ecx
  401.         shr     ecx, 2
  402.         rep movsd
  403.         mov     ecx, edx
  404.         and     ecx, 3
  405.         rep movsb
  406.         mov     ecx, 0x1000
  407.         sub     ecx, edx
  408.         mov     edx, ecx
  409.         shr     ecx, 2
  410.         and     edx, 3
  411.         xor     eax, eax
  412.         rep stosd
  413.         mov     ecx, edx
  414.         rep stosb
  415. .section_data_done:
  416. ; 2o. Get size of the section header.
  417. ; Characteristics is the last dword in both
  418. ; COFF_SECTION and STRIPPED_PE_SECTION, so this helps to access it.
  419.         movi    ecx, sizeof.STRIPPED_PE_SECTION
  420.         cmp     [peheader], 0
  421.         jz      @f
  422.         mov     cl, sizeof.COFF_SECTION
  423. @@:
  424. ; 2p. If the current page intersects virtual address range of the section,
  425. ; update access rights using section access rights.
  426.         cmp     [ebx+COFF_SECTION.VirtualSize], 0
  427.         jz      .section_access_done
  428.         mov     esi, [page_offset]
  429.         sub     esi, [ebx+COFF_SECTION.VirtualAddress]
  430.         cmp     esi, [ebx+COFF_SECTION.VirtualSize]
  431.         jb      @f
  432.         add     esi, 0x1000
  433.         jnc     .section_access_done
  434.         jz      .section_access_done
  435. @@:
  436.         mov     eax, [ebx+ecx-4]
  437.         shr     eax, 28
  438.         or      [cur_access], al
  439. .section_access_done:
  440. ; 2q. Advance to the next section, while there are sections left.
  441.         add     ebx, ecx
  442.         dec     [section_idx]
  443.         jnz     .sections_loop
  444. .no_sections:
  445. ; 2r. Shareable pages can not be lazy-allocated
  446. ; even if they only contain uninitialized data.
  447. ; If the page is shareable and has not been allocated yet, do it now.
  448.         test    [cur_access], IMAGE_SCN_MEM_SHARED shr 28
  449.         jz      @f
  450.         cmp     [cur_page], 0
  451.         jnz     @f
  452.         stdcall kernel_alloc, 0x1000
  453.         test    eax, eax
  454.         jz      .fail_free_pages
  455.         mov     [cur_page], eax
  456.         mov     edi, eax
  457.         xor     eax, eax
  458.         mov     ecx, 0x1000/4
  459.         rep stosd
  460. @@:
  461. ; 2s. Get and store the item for page array: 0xFF for pages with zeroes,
  462. ; physical address of the page plus 1 for reference counter otherwise,
  463. ; with access rights in bits 8-11 in both cases.
  464.         mov     edi, 0xFF
  465.         mov     eax, [cur_page]
  466.         test    eax, eax
  467.         jz      @f
  468.         call    get_pg_addr
  469.         lea     edi, [eax+1]
  470.         stdcall free_kernel_space, [cur_page]
  471. @@:
  472.         movzx   eax, [cur_access]
  473.         shl     eax, 8
  474.         or      eax, edi
  475.         mov     ecx, [page_index]
  476.         mov     esi, [descr]
  477.         mov     [esi+sizeof.PEDESCR+ecx*4], eax
  478. .page_created:
  479. ; 2t. Transform the item from page array to page table entry:
  480. ; - drop reference counter,
  481. ; - map zero-only page to LAZY_ALLOC_PAGE
  482. ;   with optional flags LAZY_ALLOC_{UNREADABLE,UNWRITABLE},
  483. ;   PF handler will lazy-allocate it;
  484. ; - for pages with data,
  485. ;   map readable and executable to user bit,
  486. ;   for shareable pages map writable to writable bit,
  487. ;   for non-shareable pages ignore writable to support copy-on-write.
  488.         mov     edx, eax
  489.         and     eax, not 0xFFF
  490.         jz      .page_set_zero
  491.         inc     [num_allocated_pages]
  492.         or      eax, PG_READ+PG_SHARED
  493.         test    dh, (IMAGE_SCN_MEM_READ+IMAGE_SCN_MEM_EXECUTE) shr 28
  494.         jz      @f
  495.         or      al, PG_USER
  496. @@:
  497.         test    dh, IMAGE_SCN_MEM_SHARED shr 28
  498.         jz      @f
  499.         test    dh, IMAGE_SCN_MEM_WRITE shr 28
  500.         jz      @f
  501.         or      al, PG_WRITE
  502. @@:
  503.         jmp     .pte_generated
  504. .page_set_zero:
  505.         mov     al, LAZY_ALLOC_PAGE
  506.         test    dh, (IMAGE_SCN_MEM_READ+IMAGE_SCN_MEM_EXECUTE) shr 28
  507.         jnz     @f
  508.         or      al, LAZY_ALLOC_UNREADABLE
  509. @@:
  510.         test    dh, IMAGE_SCN_MEM_WRITE shr 28
  511.         jnz     @f
  512.         or      al, LAZY_ALLOC_UNWRITABLE
  513. @@:
  514. .pte_generated:
  515.         mov     edi, [pages]
  516.         mov     [edi+ecx*4], eax
  517. ; 2u. Advance to the next page, until PEDESCR.size is reached.
  518.         inc     ecx
  519.         inc     [page_index]
  520.         add     [page_offset], 0x1000
  521.         cmp     ecx, [esi+PEDESCR.size]
  522.         jb      .fill_pages
  523. ; 2v. Release the lock.
  524.         lea     ecx, [esi+PEDESCR.page_array_lock]
  525.         call    mutex_unlock
  526. ; 3. Allocate a new SMAP.
  527.         movi    eax, sizeof.SMAP
  528.         call    malloc
  529.         test    eax, eax
  530.         jz      .fail_free_pages_unlocked
  531.         mov     ebx, eax
  532. ; 4. Lock the address space so that a random PF from other thread
  533. ; between end of step 5 and beginning of step 7 would not trash anything.
  534.         mov     ecx, [current_process]
  535.         add     ecx, PROC.heap_lock
  536.         call    mutex_lock
  537. ; 5. Allocate space in the address space.
  538. ; Prefer PEDESCR.defaultbase, but allow address anywhere else
  539. ; if allocation at PEDESCR.defaultbase is not possible.
  540.         mov     edi, [esi+PEDESCR.size]
  541.         shl     edi, 12
  542.         stdcall user_alloc_at_nolock, [esi+PEDESCR.defaultbase], edi
  543.         test    eax, eax
  544.         jnz     @f
  545.         stdcall user_alloc_nolock, edi
  546.         test    eax, eax
  547.         jz      .user_alloc_failed
  548. @@:
  549.         mov     [img_base], eax
  550. ; 6. Fill SMAP with values and insert it to the list of SMAPs.
  551.         mov     [ebx+SMAP.type], SMAP_TYPE_PE
  552.         mov     ecx, [current_process]
  553.         add     ecx, PROC.smap_list
  554.         mov     edx, [ecx+SMAP.fd]
  555.         mov     [ebx+SMAP.fd], edx
  556.         mov     [ebx+SMAP.bk], ecx
  557.         mov     [ecx+SMAP.fd], ebx
  558.         mov     [edx+SMAP.bk], ebx
  559.         mov     [ebx+SMAP.base], eax
  560.         mov     [ebx+SMAP.size], edi
  561.         mov     [ebx+SMAP.parent], esi
  562. ; 7. Copy page table entries prepared at step 2 to the page table.
  563.         mov     edx, eax
  564.         shr     edx, 12
  565.         mov     ecx, [esi+PEDESCR.size]
  566.         mov     esi, [pages]
  567.         lea     edi, [page_tabs+edx*4]
  568.         rep movsd
  569.         mov     eax, [num_allocated_pages]
  570.         shl     eax, 12
  571. ; 8. Release the address space lock.
  572.         mov     ecx, [current_process]
  573.         add     [ecx+PROC.mem_used], eax
  574.         add     ecx, PROC.heap_lock
  575.         call    mutex_unlock
  576. ; 9. Cleanup and return allocated address.
  577.         mov     eax, [pages]
  578.         call    free
  579.         cmp     [filedata], 0
  580.         jz      @f
  581.         stdcall kernel_free, [filedata]
  582. @@:
  583.         mov     eax, [img_base]
  584.         ret
  585. .fail_and_free_data:
  586.         stdcall kernel_free, [filedata]
  587. .fail:
  588.         mov     eax, edi
  589.         ret
  590. .user_alloc_failed:
  591.         mov     ecx, [current_process]
  592.         add     ecx, PROC.heap_lock
  593.         call    mutex_unlock
  594.         mov     eax, ebx
  595.         call    free
  596. .fail_free_pages_unlocked:
  597.         lea     ecx, [esi+PEDESCR.page_array_lock]
  598.         call    mutex_lock
  599. .fail_free_pages:
  600.         mov     ecx, [page_index]
  601.         test    ecx, ecx
  602.         jz      .fail_free_pages_array
  603.         mov     eax, [esi+sizeof.PEDESCR+(ecx-1)*4]
  604.         mov     edx, eax
  605.         and     eax, not 0xFFF
  606.         jz      .fail_free_next
  607.         and     edx, 0xFF
  608.         cmp     edx, 0xFF
  609.         jz      .fail_free_next
  610.         dec     dword [esi+sizeof.PEDESCR+(ecx-1)*4]
  611.         dec     edx
  612.         jnz     .fail_free_next
  613.         mov     [esi+sizeof.PEDESCR+(ecx-1)*4], edx
  614.         call    free_page
  615. .fail_free_next:
  616.         dec     [page_index]
  617.         jmp     .fail_free_pages
  618. .fail_free_pages_array:
  619.         lea     ecx, [esi+PEDESCR.page_array_lock]
  620.         call    mutex_unlock
  621.         mov     eax, [pages]
  622.         call    free
  623.         movi    edi, -30
  624. .fail_dereference:
  625.         cmp     [filedata], 0
  626.         jz      @f
  627.         stdcall kernel_free, [filedata]
  628. @@:
  629.         call    dereference_pe
  630.         mov     eax, edi
  631.         ret
  632.  
  633. .validate_header:
  634.         mov     [filedata], eax
  635.         cmp     ebx, 40h
  636.         jb      .validate_header.error
  637.         mov     [peheader], 0
  638.         cmp     word [eax], STRIPPED_PE_SIGNATURE
  639.         jz      .validate_header.stripped
  640.         cmp     word [eax], 'MZ'
  641.         jnz     .validate_header.error
  642.         mov     ecx, [eax+3Ch]
  643.         add     eax, ecx
  644.         add     ecx, IMAGE_NT_HEADERS.OptionalHeader
  645.         jc      .validate_header.error
  646.         cmp     ecx, ebx
  647.         ja      .validate_header.error
  648.         cmp     [eax+IMAGE_NT_HEADERS.Signature], 'PE'
  649.         jnz     .validate_header.error
  650.         mov     [peheader], eax
  651.         movzx   edx, [eax+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader]
  652.         cmp     edx, IMAGE_OPTIONAL_HEADER32.DataDirectory
  653.         jb      .validate_header.error
  654.         add     ecx, edx
  655.         jc      .validate_header.error
  656.         cmp     ecx, ebx
  657.         ja      .validate_header.error
  658.         lea     edx, [eax+IMAGE_NT_HEADERS.OptionalHeader+edx]
  659.         mov     [sections], edx
  660.         movzx   edx, [eax+IMAGE_NT_HEADERS.FileHeader.NumberOfSections]
  661.         mov     [num_sections], edx
  662.         imul    edx, sizeof.COFF_SECTION
  663.         add     ecx, edx
  664.         jc      .validate_header.error
  665.         cmp     ecx, ebx
  666.         ja      .validate_header.error
  667.         mov     edx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeaders]
  668.         mov     [header_size], edx
  669.         cmp     edx, ebx
  670.         ja      .validate_header.error
  671.         mov     edx, [num_sections]
  672.         mov     ecx, [sections]
  673.         test    edx, edx
  674.         jz      .validate_header.sections_ok
  675. @@:
  676.         mov     eax, [ecx+COFF_SECTION.PtrRawData]
  677.         add     eax, [ecx+COFF_SECTION.SizeOfRawData]
  678.         jc      .validate_header.error
  679.         cmp     eax, ebx
  680.         ja      .validate_header.error
  681.         add     ecx, sizeof.COFF_SECTION
  682.         dec     edx
  683.         jnz     @b
  684. .validate_header.sections_ok:
  685. .validate_header.ok:
  686.         clc
  687.         retn
  688. .validate_header.stripped:
  689.         movzx   ecx, [eax+STRIPPED_PE_HEADER.NumberOfRvaAndSizes]
  690.         lea     ecx, [sizeof.STRIPPED_PE_HEADER+ecx*8]
  691.         movzx   edx, [eax+STRIPPED_PE_HEADER.NumberOfSections]
  692.         mov     [num_sections], edx
  693.         imul    edx, sizeof.STRIPPED_PE_SECTION
  694.         add     edx, ecx
  695.         cmp     edx, ebx
  696.         ja      .validate_header.error
  697.         mov     edx, [eax+STRIPPED_PE_HEADER.SizeOfHeaders]
  698.         mov     [header_size], edx
  699.         cmp     edx, ebx
  700.         ja      .validate_header.error
  701.         add     ecx, eax
  702.         mov     [sections], ecx
  703.         mov     edx, [num_sections]
  704.         test    edx, edx
  705.         jz      .validate_header.stripped.sections_ok
  706. @@:
  707.         mov     eax, [ecx+STRIPPED_PE_SECTION.PtrRawData]
  708.         add     eax, [ecx+STRIPPED_PE_SECTION.SizeOfRawData]
  709.         jc      .validate_header.error
  710.         cmp     eax, ebx
  711.         ja      .validate_header.error
  712.         add     ecx, sizeof.STRIPPED_PE_SECTION
  713.         dec     edx
  714.         jnz     @b
  715. .validate_header.stripped.sections_ok:
  716.         clc
  717.         retn
  718. .validate_header.error:
  719.         stc
  720.         retn
  721. endp
  722.  
  723. ; in: edi -> SMAP
  724. ; in: address space lock must be held
  725. proc release_pemap stdcall uses ebx esi, process:dword
  726.     locals
  727.         num_released_pages dd 0
  728.         mapped_pagedir dd -1
  729.     endl
  730.         mov     esi, [edi+SMAP.base]
  731.         mov     ebx, [edi+SMAP.parent]
  732.         shr     esi, 12
  733.         dec     esi
  734.         add     ebx, sizeof.PEDESCR
  735.         call    .get_page_tab_entry
  736.         mov     ecx, [eax]
  737.         and     ecx, not MEM_BLOCK_DONT_FREE
  738.         mov     [eax],  ecx
  739.         shr     ecx, 12
  740.         dec     ecx
  741.         jz      .released
  742. .release:
  743.         inc     esi
  744.         call    .get_page_tab_entry
  745.         mov     edx, [eax]
  746.         test    dl, 1
  747.         jz      .next
  748.         test    edx, PG_SHARED
  749.         jz      .next
  750.         mov     dword [eax], 0
  751.         inc     [num_released_pages]
  752.         xor     edx, [ebx]
  753.         test    edx, not 0xFFF
  754.         jnz     .next
  755.         mov     edx, [ebx]
  756.         mov     eax, edx
  757.         and     edx, 0xFF
  758.         cmp     edx, 0xFF
  759.         jz      .next
  760.         dec     eax
  761.         test    dword [ebx], IMAGE_SCN_MEM_SHARED shr 20
  762.         jnz     @f
  763.         test    eax, 0xFF
  764.         jnz     @f
  765.         call    free_page
  766.         xor     eax, eax
  767. @@:
  768.         mov     [ebx], eax
  769. .next:
  770.         add     ebx, 4
  771.         dec     ecx
  772.         jnz     .release
  773.         mov     eax, [num_released_pages]
  774.         shl     eax, 12
  775.         mov     edx, [process]
  776.         sub     [edx+PROC.mem_used], eax
  777.         cmp     [mapped_pagedir], -1
  778.         jz      .released
  779.         stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
  780. .released:
  781.         ret
  782.  
  783. .get_page_tab_entry:
  784.         mov     eax, [process]
  785.         cmp     eax, [current_process]
  786.         jnz     @f
  787.         lea     eax, [page_tabs+esi*4]
  788.         retn
  789. @@:
  790.         push    edx
  791.         mov     edx, esi
  792.         shr     edx, 10
  793.         cmp     edx, [mapped_pagedir]
  794.         jz      @f
  795.         mov     [mapped_pagedir], edx
  796.         mov     eax, [eax+PROC.pdt_0+edx*4]
  797.         and     eax, not 0xFFF
  798.         stdcall map_page, [tmp_task_ptab], eax, PG_SWR
  799. @@:
  800.         mov     eax, [tmp_task_ptab]
  801.         mov     edx, esi
  802.         and     edx, 0x3FF
  803.         lea     eax, [eax+edx*4]
  804.         pop     edx
  805.         retn
  806. endp
  807.  
  808. proc unmap_pe_usermode stdcall uses ebx esi edi, address:dword
  809.         mov     ecx, [current_process]
  810.         lea     edi, [ecx+PROC.smap_list]
  811.         add     ecx, PROC.heap_lock
  812.         call    mutex_lock
  813.         mov     esi, edi
  814.         mov     eax, [address]
  815. .scan:
  816.         mov     edi, [edi+SMAP.fd]
  817.         cmp     edi, esi
  818.         jz      .notfound
  819.         cmp     [edi+SMAP.base], eax
  820.         jnz     .scan
  821.         mov     eax, [edi+SMAP.fd]
  822.         mov     edx, [edi+SMAP.bk]
  823.         mov     [eax+SMAP.bk], edx
  824.         mov     [edx+SMAP.fd], eax
  825.         call    mutex_unlock
  826.         stdcall destroy_smap, [current_process]
  827.         xor     eax, eax
  828.         ret
  829. .notfound:
  830.         call    mutex_unlock
  831.         or      eax, -1
  832.         ret
  833. endp
  834.