forked from KolibriOS/kolibrios
various fixes
git-svn-id: svn://kolibrios.org@6810 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
5d60fdc440
commit
6198f1e4c9
@ -333,6 +333,7 @@ msg_export_name_not_found db 'Exported function ',0
|
|||||||
msg_export_ordinal_not_found db 'Exported ordinal #',0
|
msg_export_ordinal_not_found db 'Exported ordinal #',0
|
||||||
msg_export_not_found db ' not found in module ',0
|
msg_export_not_found db ' not found in module ',0
|
||||||
msg_unknown db '<unknown>',0
|
msg_unknown db '<unknown>',0
|
||||||
|
msg_invalid_forwarder db 'Invalid forwarded export in module ',0
|
||||||
|
|
||||||
section '.data' data readable writable
|
section '.data' data readable writable
|
||||||
if FOOTERS
|
if FOOTERS
|
||||||
|
@ -15,6 +15,7 @@ macro init_module_struct_pe_specific
|
|||||||
cmp [esi+STRIPPED_PE_HEADER.NumberOfRvaAndSizes], SPE_DIRECTORY_EXPORT
|
cmp [esi+STRIPPED_PE_HEADER.NumberOfRvaAndSizes], SPE_DIRECTORY_EXPORT
|
||||||
jbe @f
|
jbe @f
|
||||||
mov edx, [esi+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY+IMAGE_DATA_DIRECTORY.VirtualAddress]
|
mov edx, [esi+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY+IMAGE_DATA_DIRECTORY.VirtualAddress]
|
||||||
|
mov edx, [esi+edx+IMAGE_EXPORT_DIRECTORY.TimeDateStamp]
|
||||||
@@:
|
@@:
|
||||||
mov [eax+MODULE.timestamp], edx
|
mov [eax+MODULE.timestamp], edx
|
||||||
mov edx, esi
|
mov edx, esi
|
||||||
@ -117,6 +118,7 @@ end virtual
|
|||||||
fpo_delta = fpo_delta + 4
|
fpo_delta = fpo_delta + 4
|
||||||
; 2c. Check whether we have mprotect-ed the current page at the previous step.
|
; 2c. Check whether we have mprotect-ed the current page at the previous step.
|
||||||
; If so, go to 2e.
|
; If so, go to 2e.
|
||||||
|
add edx, esi
|
||||||
cmp [.next_page_addr+fpo_delta], edx
|
cmp [.next_page_addr+fpo_delta], edx
|
||||||
jz .mprotected_earlier
|
jz .mprotected_earlier
|
||||||
; 2d. We are going to modify data, so mprotect the current page to be writable.
|
; 2d. We are going to modify data, so mprotect the current page to be writable.
|
||||||
@ -130,7 +132,6 @@ PROT_EXEC = 4
|
|||||||
mov eax, 68
|
mov eax, 68
|
||||||
mov ebx, 30
|
mov ebx, 30
|
||||||
mov ecx, PROT_READ+PROT_WRITE
|
mov ecx, PROT_READ+PROT_WRITE
|
||||||
add edx, esi
|
|
||||||
mov esi, 0x1000
|
mov esi, 0x1000
|
||||||
call FS_SYSCALL_PTR
|
call FS_SYSCALL_PTR
|
||||||
pop ecx
|
pop ecx
|
||||||
@ -182,13 +183,10 @@ PROT_EXEC = 4
|
|||||||
; 2i. Restore memory protection changed in 2d.
|
; 2i. Restore memory protection changed in 2d.
|
||||||
pop ecx
|
pop ecx
|
||||||
fpo_delta = fpo_delta - 4
|
fpo_delta = fpo_delta - 4
|
||||||
cmp ecx, -1
|
|
||||||
jz @f
|
|
||||||
mov eax, 68
|
mov eax, 68
|
||||||
mov ebx, 30
|
mov ebx, 30
|
||||||
mov esi, 0x1000
|
mov esi, 0x1000
|
||||||
call FS_SYSCALL_PTR
|
call FS_SYSCALL_PTR
|
||||||
@@:
|
|
||||||
pop esi
|
pop esi
|
||||||
fpo_delta = fpo_delta - 4
|
fpo_delta = fpo_delta - 4
|
||||||
.pagedone:
|
.pagedone:
|
||||||
@ -242,12 +240,14 @@ export_base dd ?
|
|||||||
export_ptr dd ?
|
export_ptr dd ?
|
||||||
export_size dd ?
|
export_size dd ?
|
||||||
import_module dd ?
|
import_module dd ?
|
||||||
import_dir dd ?
|
|
||||||
import_descriptor dd ?
|
import_descriptor dd ?
|
||||||
|
next_forwarder dd ?
|
||||||
|
bound_import_descriptor dd ?
|
||||||
bound_import_dir dd ?
|
bound_import_dir dd ?
|
||||||
bound_import_cur_module dd ?
|
bound_modules_count dd ?
|
||||||
relocated_bound_modules_count dd ?
|
bound_modules_ptr dd ?
|
||||||
relocated_bound_modules_ptr dd ?
|
bound_module dd ?
|
||||||
|
bound_modules_left dd ?
|
||||||
cur_page dd -0x1000 ; the page at 0xFFFFF000 is never allocated
|
cur_page dd -0x1000 ; the page at 0xFFFFF000 is never allocated
|
||||||
cur_page_old_access dd ?
|
cur_page_old_access dd ?
|
||||||
next_page dd -1
|
next_page dd -1
|
||||||
@ -281,9 +281,9 @@ local .label1, .loop, .done
|
|||||||
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
||||||
mov ebp, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
mov ebp, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
||||||
test ebx, ebx
|
test ebx, ebx
|
||||||
jnz .label1
|
jnz @f
|
||||||
mov ebx, ebp
|
mov ebx, ebp
|
||||||
.label1:
|
@@:
|
||||||
; FirstThunk and OriginalFirstThunk are RVAs.
|
; FirstThunk and OriginalFirstThunk are RVAs.
|
||||||
add ebx, [esi+MODULE.base]
|
add ebx, [esi+MODULE.base]
|
||||||
add ebp, [esi+MODULE.base]
|
add ebp, [esi+MODULE.base]
|
||||||
@ -345,14 +345,20 @@ local .ordinal, .common
|
|||||||
; we have two parallel arrays of import descriptors and bound descriptors,
|
; we have two parallel arrays of import descriptors and bound descriptors,
|
||||||
; pointed to by two directories. Timestamp field has a special value -1
|
; pointed to by two directories. Timestamp field has a special value -1
|
||||||
; in import descriptors, real timestamps are in bound descriptors.
|
; in import descriptors, real timestamps are in bound descriptors.
|
||||||
; There can be different strategies; we loop over bound descriptors
|
|
||||||
; and scan for corresponding import descriptors only if needed,
|
|
||||||
; this accelerates the fast path where all timestamps are correct and
|
|
||||||
; dependencies are not relocated.
|
|
||||||
; * No import: not really different from normal import with no descriptors.
|
; * No import: not really different from normal import with no descriptors.
|
||||||
; There are two large parts in this function:
|
; Forwarded exports are the part where binding goes really interesting.
|
||||||
; step 2 handles unbound and old-style bound import, where we loop over import descriptors;
|
; The address of forwarded export can change with any library in the chain.
|
||||||
; step 3 handles new-style bound import, where we loop over bound descriptors.
|
; In old-style bound import, a descriptor can list only the library itself,
|
||||||
|
; so it is impossible to bind forwarded exports at all; thunks that point to
|
||||||
|
; forwarded exports are linked in the list starting from ForwarderChain in import descriptor.
|
||||||
|
; New-style bound import exists exactly to address this problem; it allows to
|
||||||
|
; list several related libraries for one imported module.
|
||||||
|
; However, even with new-style bound import, some forwarded exports can
|
||||||
|
; still remain unbound: binding tool can fail to load dependent libraries
|
||||||
|
; during binding time; the tool from MS SDK for unknown reason just refuses to
|
||||||
|
; bind forwarded exports except for built-in white list if subsystem version is
|
||||||
|
; < 6.0. So even with new-style bound import, ForwarderChain still can be non-empty.
|
||||||
|
; Thus, we always need to look at old-style import descriptor.
|
||||||
; 1. Fetch addresses of two directories. We are not interested in their sizes.
|
; 1. Fetch addresses of two directories. We are not interested in their sizes.
|
||||||
; ebp = import RVA
|
; ebp = import RVA
|
||||||
; ebx = bound import RVA
|
; ebx = bound import RVA
|
||||||
@ -378,88 +384,69 @@ local .ordinal, .common
|
|||||||
jbe .common
|
jbe .common
|
||||||
mov ebx, [eax+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT*sizeof.IMAGE_DATA_DIRECTORY]
|
mov ebx, [eax+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT*sizeof.IMAGE_DATA_DIRECTORY]
|
||||||
.common:
|
.common:
|
||||||
mov [import_dir], ebp
|
; If import directory is not present, no import - nothing to do.
|
||||||
; If bound import is present, go to 3.
|
; Ignore bound import directory in this case.
|
||||||
; If both directories are absent, no import - nothing to do.
|
|
||||||
; Otherwise, advance to 2.
|
|
||||||
test ebx, ebx
|
|
||||||
jnz .bound_import
|
|
||||||
test ebp, ebp
|
test ebp, ebp
|
||||||
jz .done
|
jz .done
|
||||||
; 2. Unbound import or old-style bound import.
|
|
||||||
; Repeat 2a-2h for all descriptors in the directory.
|
|
||||||
add ebp, [esi+MODULE.base] ; directories contain RVA
|
add ebp, [esi+MODULE.base] ; directories contain RVA
|
||||||
.normal_import_loop:
|
add ebx, [esi+MODULE.base] ; directories contain RVA
|
||||||
; 2a. Check whether this descriptor is an end mark with zero fields.
|
mov [bound_import_dir], ebx
|
||||||
|
mov [bound_import_descriptor], ebx
|
||||||
|
; Repeat remaining steps for all descriptors in the directory.
|
||||||
|
.descriptor_loop:
|
||||||
|
; 2. Check whether this descriptor is an end mark with zero fields.
|
||||||
; Look at Name field.
|
; Look at Name field.
|
||||||
mov edi, [ebp+IMAGE_IMPORT_DESCRIPTOR.Name]
|
mov edi, [ebp+IMAGE_IMPORT_DESCRIPTOR.Name]
|
||||||
test edi, edi
|
test edi, edi
|
||||||
jz .done
|
jz .done
|
||||||
; 2b. Load the target module.
|
; 3. Load the target module.
|
||||||
add edi, [esi+MODULE.base] ; Name field is RVA
|
add edi, [esi+MODULE.base] ; Name field is RVA
|
||||||
call load_imported_module ; should preserve esi,ebp
|
call load_imported_module ; should preserve esi,ebp
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz .failed
|
jz .failed
|
||||||
mov [import_module], eax
|
mov [import_module], eax
|
||||||
; 2c. Check whether the descriptor has a non-stale old-style binding.
|
; 4. Check whether the descriptor has a non-stale old-style binding.
|
||||||
; Zero timestamp means "not bound".
|
; Zero timestamp means "not bound".
|
||||||
|
; Timestamp 0xFFFFFFFF means "new-style binding".
|
||||||
; Mismatched timestamp means "stale binding".
|
; Mismatched timestamp means "stale binding".
|
||||||
; In both cases, go to 2g.
|
; In first and third cases, go to 9.
|
||||||
|
; In second case, go to 10 for further checks.
|
||||||
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp]
|
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp]
|
||||||
test edx, edx
|
test edx, edx
|
||||||
jz .resolve_normal_import
|
jz .resolve_generic
|
||||||
|
cmp edx, -1
|
||||||
|
jz .new_binding
|
||||||
cmp edx, [eax+MODULE.timestamp]
|
cmp edx, [eax+MODULE.timestamp]
|
||||||
jnz .resolve_normal_import
|
jnz .resolve_generic
|
||||||
; 2d. The descriptor has a non-stale old-style binding.
|
; 5. The descriptor has a non-stale old-style binding.
|
||||||
; There are two cases when we still need to do something:
|
; There are two cases when we still need to do something:
|
||||||
; * if the target module has been relocated, we need to add
|
; * if the target module has been relocated, we need to add
|
||||||
; relocation delta to all addresses;
|
; relocation delta to all addresses;
|
||||||
; * if some exports are forwarded, old-style binding cannot bind them:
|
; * if some exports are forwarded, we need to resolve them.
|
||||||
; there is only one timestamp field, we can't verify timestamps
|
|
||||||
; of forward targets.
|
|
||||||
; Thunks for forwarded exports contain index of next forwarded export
|
; Thunks for forwarded exports contain index of next forwarded export
|
||||||
; instead of target address, making a single-linked list terminated by -1.
|
; instead of target address, making a single-linked list terminated by -1.
|
||||||
; ForwarderChain is the head of the list.
|
; ForwarderChain is the head of the list.
|
||||||
; If both problems are present, we resort to 2g as if binding is stale,
|
; Check for the first problem first; the corresponding code can handle both.
|
||||||
; it shouldn't be encountered normally anyway: relocations should be avoided,
|
; If the target module is relocated, go to 8.
|
||||||
; and forwarded exports should be new-style bound.
|
; If the target module is not relocated, but has forwarded exports, go to 7.
|
||||||
; If the target module is not relocated, go to 2f.
|
; Otherwise, advance to 6.
|
||||||
; If the target module is relocated and there are no forwarded exports,
|
.old_binding:
|
||||||
; advance to 2e.
|
|
||||||
cmp [eax+MODULE.basedelta], 0
|
cmp [eax+MODULE.basedelta], 0
|
||||||
jz .normal_import_check_forwarders
|
jnz .old_binding_relocate
|
||||||
|
.check_forwarder_chain:
|
||||||
cmp [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain], -1
|
cmp [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain], -1
|
||||||
jnz .resolve_normal_import
|
jnz .resolve_forward_chain
|
||||||
; 2e. Binding is correct, but we need to add MODULE.basedelta
|
.next_descriptor:
|
||||||
; to all imported addresses in FirstThunk array.
|
; 6. Advance to next descriptor and continue the loop.
|
||||||
; For consistency with generic-case resolve_import_from_module,
|
add ebp, sizeof.IMAGE_IMPORT_DESCRIPTOR
|
||||||
; check for end of thunks by looking at OriginalFirstThunk array.
|
jmp .descriptor_loop
|
||||||
; After that, go to 2h.
|
.resolve_forward_chain:
|
||||||
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
; 7. Resolve all thunks from ForwarderChain list.
|
||||||
add edx, [esi+MODULE.base]
|
|
||||||
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
|
||||||
add ebx, [esi+MODULE.base]
|
|
||||||
mov edi, [eax+MODULE.basedelta]
|
|
||||||
.normal_import_add_delta:
|
|
||||||
cmp dword [ebx], 0
|
|
||||||
jz .normal_import_next
|
|
||||||
call .ensure_writable ; should preserve esi,edi,ebp,ebx,edx
|
|
||||||
add dword [edx], edi
|
|
||||||
add edx, 4
|
|
||||||
add ebx, 4
|
|
||||||
jmp .normal_import_add_delta
|
|
||||||
.normal_import_check_forwarders:
|
|
||||||
; 2f. The target module is not relocated.
|
|
||||||
; Exports that are not forwarded are correct.
|
|
||||||
; Go through ForwarderChain list and resolve all exports from it.
|
|
||||||
; After that, go to 2h.
|
|
||||||
mov edi, [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain]
|
|
||||||
cmp edi, -1
|
|
||||||
jz .normal_import_next ; don't prepare_import_from_module for empty list
|
|
||||||
mov eax, [import_module]
|
mov eax, [import_module]
|
||||||
mov eax, [eax+MODULE.base]
|
mov eax, [eax+MODULE.base]
|
||||||
call prepare_import_from_module
|
call prepare_import_from_module
|
||||||
.normal_import_forward_chain:
|
mov edi, [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain]
|
||||||
|
.resolve_forward_chain_loop:
|
||||||
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
||||||
add ebx, [esi+MODULE.base]
|
add ebx, [esi+MODULE.base]
|
||||||
mov ecx, [ebx+edi*4]
|
mov ecx, [ebx+edi*4]
|
||||||
@ -474,207 +461,256 @@ local .ordinal, .common
|
|||||||
mov edi, [edx] ; next forwarded export
|
mov edi, [edx] ; next forwarded export
|
||||||
mov [edx], ebx ; store the address
|
mov [edx], ebx ; store the address
|
||||||
cmp edi, -1
|
cmp edi, -1
|
||||||
jnz .normal_import_forward_chain
|
jnz .resolve_forward_chain_loop
|
||||||
jmp .normal_import_next
|
; After resolving, we are done with this import descriptor, go to 6.
|
||||||
.resolve_normal_import:
|
jmp .next_descriptor
|
||||||
; 2g. Run generic-case resolver.
|
.done:
|
||||||
|
call .restore_protection
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
.old_binding_relocate:
|
||||||
|
; 8. The descriptor has a non-stale old-style binding,
|
||||||
|
; but the target module is relocated, so we need to add MODULE.basedelta to
|
||||||
|
; all addresses. Also, there can be forwarded exports.
|
||||||
|
; For consistency with generic-case resolve_import_from_module,
|
||||||
|
; check for end of thunks by looking at OriginalFirstThunk array.
|
||||||
|
; Note: we assume here that ForwarderChain list is ordered.
|
||||||
|
; After that, go to 6.
|
||||||
|
mov edi, [eax+MODULE.basedelta]
|
||||||
|
cmp [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain], -1
|
||||||
|
jz @f
|
||||||
|
mov eax, [import_module]
|
||||||
|
mov eax, [eax+MODULE.base]
|
||||||
|
call prepare_import_from_module
|
||||||
|
@@:
|
||||||
|
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
||||||
|
add edx, [esi+MODULE.base]
|
||||||
|
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
||||||
|
add ebx, [esi+MODULE.base]
|
||||||
|
mov eax, [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain]
|
||||||
|
lea eax, [edx+eax*4]
|
||||||
|
mov [next_forwarder], eax
|
||||||
|
.old_binding_relocate_loop:
|
||||||
|
cmp dword [ebx], 0
|
||||||
|
jz .next_descriptor
|
||||||
|
call .ensure_writable ; should preserve esi,edi,ebp,ebx,edx
|
||||||
|
cmp edx, [next_forwarder]
|
||||||
|
jz .old_binding_relocate_forwarder
|
||||||
|
add dword [edx], edi
|
||||||
|
.old_binding_relocate_next:
|
||||||
|
add edx, 4
|
||||||
|
add ebx, 4
|
||||||
|
jmp .old_binding_relocate_loop
|
||||||
|
.old_binding_relocate_forwarder:
|
||||||
|
mov ecx, [ebx]
|
||||||
|
get_address_for_thunk
|
||||||
|
test eax, eax
|
||||||
|
jz .failed
|
||||||
|
mov edx, [next_forwarder]
|
||||||
|
mov ecx, [edx]
|
||||||
|
mov [edx], eax
|
||||||
|
mov eax, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
||||||
|
add eax, [esi+MODULE.base]
|
||||||
|
lea eax, [eax+ecx*4]
|
||||||
|
mov [next_forwarder], eax
|
||||||
|
jmp .old_binding_relocate_next
|
||||||
|
.resolve_generic:
|
||||||
|
; 9. Run generic-case resolver.
|
||||||
mov [import_descriptor], ebp
|
mov [import_descriptor], ebp
|
||||||
resolve_import_from_module .failed ; should preserve esi
|
resolve_import_from_module .failed ; should preserve esi
|
||||||
mov ebp, [import_descriptor]
|
mov ebp, [import_descriptor]
|
||||||
.normal_import_next:
|
; After that, go to 6.
|
||||||
; 2h. Advance to next descriptor and continue the loop.
|
jmp .next_descriptor
|
||||||
add ebp, sizeof.IMAGE_IMPORT_DESCRIPTOR
|
.new_binding:
|
||||||
jmp .normal_import_loop
|
; New-style bound import.
|
||||||
.bound_import:
|
; 10. Locate the new-style descriptor corresponding to the current
|
||||||
; 3. New-style bound import.
|
; import descriptor.
|
||||||
; Repeat 3a-3o for all descriptors in bound import directory.
|
; 10a. Check the current new-style descriptor: the one that follows
|
||||||
mov [bound_import_dir], ebx
|
; previous one, if there was the previous one, or the first one.
|
||||||
add ebx, [esi+MODULE.base]
|
; In most cases, new-style descriptors are in the same order as
|
||||||
.bound_import_loop:
|
; import descriptors, so full loop in 10b can be avoided.
|
||||||
; 3a. Check whether this descriptor is an end mark with zero fields.
|
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.Name]
|
||||||
|
add edx, [esi+MODULE.base]
|
||||||
|
mov ebx, [bound_import_descriptor]
|
||||||
movzx edi, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.OffsetModuleName]
|
movzx edi, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.OffsetModuleName]
|
||||||
mov [bound_import_cur_module], edi
|
|
||||||
test edi, edi
|
test edi, edi
|
||||||
jz .done
|
jz .look_new_binding_hard
|
||||||
|
add edi, [bound_import_dir]
|
||||||
|
xor ecx, ecx
|
||||||
|
@@:
|
||||||
|
mov al, [edx+ecx]
|
||||||
|
cmp al, [edi+ecx]
|
||||||
|
jnz .look_new_binding_hard
|
||||||
|
test al, al
|
||||||
|
jz .new_binding_found
|
||||||
|
inc ecx
|
||||||
|
jmp @b
|
||||||
|
.look_new_binding_hard:
|
||||||
|
; 10b. We are out of luck with the current new-style descriptor,
|
||||||
|
; so loop over all of them looking for the matching one.
|
||||||
|
mov ebx, [bound_import_dir]
|
||||||
|
.look_new_binding_loop:
|
||||||
|
movzx edi, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.OffsetModuleName]
|
||||||
|
add edi, [bound_import_dir]
|
||||||
|
xor ecx, ecx
|
||||||
|
@@:
|
||||||
|
mov al, [edx+ecx]
|
||||||
|
cmp al, [edi+ecx]
|
||||||
|
jnz .look_new_binding_next
|
||||||
|
test al, al
|
||||||
|
jz .new_binding_found
|
||||||
|
inc ecx
|
||||||
|
jmp @b
|
||||||
|
.look_new_binding_next:
|
||||||
|
movzx ecx, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs]
|
||||||
|
lea ebx, [ebx+(ecx+1)*sizeof.IMAGE_BOUND_IMPORT_DESCRIPTOR]
|
||||||
|
jmp .look_new_binding_loop
|
||||||
|
.new_binding_found:
|
||||||
|
; 10c. Store the next descriptor for subsequent scans.
|
||||||
|
movzx ecx, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs]
|
||||||
|
lea eax, [ebx+(ecx+1)*sizeof.IMAGE_BOUND_IMPORT_DESCRIPTOR]
|
||||||
|
mov [bound_import_descriptor], eax
|
||||||
; Bound import descriptors come in groups.
|
; Bound import descriptors come in groups.
|
||||||
; The first descriptor in each group corresponds to the main imported module.
|
; The first descriptor in each group corresponds to the main imported module.
|
||||||
; If some exports from the module are forwarded, additional descriptors
|
; If some exports from the module are forwarded, additional descriptors
|
||||||
; are created for modules where those exports are forwarded to.
|
; are created for modules where those exports are forwarded to.
|
||||||
; Number of additional descriptors is given by one field in the first descriptor.
|
; Number of additional descriptors is given by one field in the first descriptor.
|
||||||
; 3b. Prepare for loop at 3c-3f with loading targets of all exports.
|
; 11. We have already loaded the main module, validate its timestamp.
|
||||||
; This includes the target module and all modules in chains of forwarded exports.
|
; If timestamp does not match, go to 9 to run generic-case resolver.
|
||||||
movzx ebp, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs]
|
mov eax, [import_module]
|
||||||
mov [relocated_bound_modules_count], 0
|
mov edx, [eax+MODULE.timestamp]
|
||||||
mov [relocated_bound_modules_ptr], 0
|
cmp edx, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.TimeDateStamp]
|
||||||
mov [import_module], 0
|
jnz .resolve_generic
|
||||||
.bound_import_forwarder_loop:
|
; 12. If there are no additional libraries,
|
||||||
; 3c. Load a referenced module.
|
; the situation is exactly same as old-style binding, so go to 5.
|
||||||
; Names in bound import descriptors are relative to bound import directory,
|
test ecx, ecx
|
||||||
; not RVAs.
|
jz .old_binding
|
||||||
|
; 13. Load additional libraries and validate their timestamps.
|
||||||
|
; If at least one timestamp is invalid, resort to generic-case resolving.
|
||||||
|
; 13a. Allocate memory for all bound modules, including the main module.
|
||||||
|
lea ecx, [(ecx+1)*4]
|
||||||
|
stdcall malloc, ecx
|
||||||
|
test eax, eax
|
||||||
|
jz .failed
|
||||||
|
mov [bound_modules_ptr], eax
|
||||||
|
; 13b. Store the main module.
|
||||||
|
mov edx, [import_module]
|
||||||
|
mov [eax], edx
|
||||||
|
xor ecx, ecx
|
||||||
|
; 13c. Loop over all additional descriptors.
|
||||||
|
.newstyle_load_loop:
|
||||||
|
inc ecx
|
||||||
|
mov [bound_modules_count], ecx
|
||||||
|
movzx edi, [ebx+ecx*sizeof.IMAGE_BOUND_IMPORT_DESCRIPTOR+IMAGE_BOUND_IMPORT_DESCRIPTOR.OffsetModuleName]
|
||||||
add edi, [bound_import_dir]
|
add edi, [bound_import_dir]
|
||||||
call load_imported_module ; should preserve ebx,esi,ebp
|
call load_imported_module ; should preserve ebx,esi,ebp
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz .bound_import_failed
|
jz .newstyle_failed
|
||||||
; The target module is first in the list.
|
mov ecx, [bound_modules_count]
|
||||||
cmp [import_module], 0
|
mov edx, [ebx+ecx*sizeof.IMAGE_BOUND_IMPORT_DESCRIPTOR+IMAGE_BOUND_IMPORT_DESCRIPTOR.TimeDateStamp]
|
||||||
jnz @f
|
cmp [eax+MODULE.timestamp], edx
|
||||||
mov [import_module], eax
|
jnz .newstyle_stale
|
||||||
@@:
|
mov edx, [bound_modules_ptr]
|
||||||
; 3d. Check whether timestamp in the descriptor matches module timestamp.
|
mov [edx+ecx*4], eax
|
||||||
; If not, go to 3h which after some preparations will resort to generic-case
|
cmp cx, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs]
|
||||||
; resolve_import_from_module; in this case, we stop processing the group,
|
jb .newstyle_load_loop
|
||||||
; resolve_import_from_module will take care about additional modules anyway.
|
inc ecx
|
||||||
mov edx, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.TimeDateStamp]
|
mov [bound_modules_count], ecx
|
||||||
test edx, edx
|
; New-style binding has correct timestamp.
|
||||||
jz .bound_import_wrong_timestamp
|
; There still can be same two problems as in step 5 with old-style binding.
|
||||||
cmp edx, [eax+MODULE.timestamp]
|
; 14. Check whether at least one module is relocated. If so, go to 16.
|
||||||
jnz .bound_import_wrong_timestamp
|
.newstyle_check_reloc:
|
||||||
; 3e. Collect all referenced modules that have been relocated.
|
mov eax, [edx]
|
||||||
cmp [eax+MODULE.basedelta], 0
|
cmp [eax+MODULE.basedelta], 0
|
||||||
jz .bound_import_forwarder_next
|
jnz .newstyle_need_reloc
|
||||||
mov edi, eax
|
add edx, 4
|
||||||
; We don't want to reallocate too often, since reallocation
|
dec ecx
|
||||||
; may involve copying our data to a new place.
|
jnz .newstyle_check_reloc
|
||||||
; We always reserve space that is a power of two; in this way,
|
; 15. Bound modules are not relocated.
|
||||||
; the wasted space is never greater than the used space,
|
; The only remaining problem could be unbound forwarders.
|
||||||
; and total time of copying the data is O(number of modules).
|
; Free memory allocated at 13a and let steps 6 and 7 do their work.
|
||||||
mov eax, [relocated_bound_modules_ptr]
|
stdcall free, [bound_modules_ptr]
|
||||||
mov edx, [relocated_bound_modules_count]
|
jmp .check_forwarder_chain
|
||||||
; X is a power of two or zero if and only if (X and (X - 1)) is zero
|
.newstyle_stale:
|
||||||
lea ecx, [edx-1]
|
stdcall free, [bound_modules_ptr]
|
||||||
test ecx, edx
|
jmp .resolve_generic
|
||||||
jnz .bound_import_norealloc
|
; 16. The descriptor has a non-stale new-style binding,
|
||||||
; if the current size is zero, allocate 1 item,
|
; but at least one of target modules is relocated, so we need to add
|
||||||
; otherwise double number of items.
|
; MODULE.basedelta to addresses from relocated modules.
|
||||||
; Item size is 4 bytes.
|
; Also, there can be forwarded exports.
|
||||||
lea edx, [edx*8]
|
|
||||||
test edx, edx
|
|
||||||
jnz @f
|
|
||||||
mov edx, 4
|
|
||||||
@@:
|
|
||||||
stdcall realloc, [relocated_bound_modules_ptr], edx
|
|
||||||
test eax, eax
|
|
||||||
jz .bound_import_failed
|
|
||||||
mov [relocated_bound_modules_ptr], eax
|
|
||||||
.bound_import_norealloc:
|
|
||||||
mov edx, [relocated_bound_modules_count]
|
|
||||||
inc [relocated_bound_modules_count]
|
|
||||||
mov [eax+edx*4], edi
|
|
||||||
.bound_import_forwarder_next:
|
|
||||||
; 3f. Advance to the next descriptor in the group.
|
|
||||||
add ebx, sizeof.IMAGE_BOUND_IMPORT_DESCRIPTOR
|
|
||||||
movzx edi, [ebx+IMAGE_BOUND_IMPORT_DESCRIPTOR.OffsetModuleName]
|
|
||||||
dec ebp
|
|
||||||
jns .bound_import_forwarder_loop
|
|
||||||
; 3g. All timestamps are correct.
|
|
||||||
; If all targets are not relocated, then we have nothing to do
|
|
||||||
; with exports from the current module, so continue loop at 3a;
|
|
||||||
; ebx already points to the next descriptor.
|
|
||||||
; Otherwise, go to 3i.
|
|
||||||
cmp [relocated_bound_modules_count], 0
|
|
||||||
jz .bound_import_loop
|
|
||||||
jmp .bound_import_fix
|
|
||||||
.bound_import_wrong_timestamp:
|
|
||||||
; 3h. We have aborted the loop over the group;
|
|
||||||
; advance ebx so that it points to the first descriptor of the next group,
|
|
||||||
; make a mark so that 3l will know that we need to reimport everything.
|
|
||||||
; We don't need [relocated_bound_modules_count] in this case anymore,
|
|
||||||
; use zero value as a mark.
|
|
||||||
lea ebx, [ebx+(ebp+1)*sizeof.IMAGE_BOUND_IMPORT_DESCRIPTOR]
|
|
||||||
mov [relocated_bound_modules_count], 0
|
|
||||||
.bound_import_fix:
|
|
||||||
; 3i. We need to do something with exported addresses.
|
|
||||||
; Find corresponding import descriptors; there can be more than one.
|
|
||||||
; Repeat 3j-3n for all import descriptors.
|
|
||||||
mov ebp, [import_dir]
|
|
||||||
add ebp, [esi+MODULE.base]
|
|
||||||
.look_related_descriptors:
|
|
||||||
; 3j. Check whether we have reached end of import table.
|
|
||||||
; If so, go to 3o.
|
|
||||||
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.Name]
|
|
||||||
test edx, edx
|
|
||||||
jz .bound_import_next
|
|
||||||
; 3k. Check whether the current import descriptor matches the current
|
|
||||||
; bound import descriptor. Check Name fields.
|
|
||||||
; If so, advance to 3l.
|
|
||||||
; Otherwise, advance to the next import descriptor and return to 3j.
|
|
||||||
add edx, [esi+MODULE.base]
|
|
||||||
mov edi, [bound_import_cur_module]
|
|
||||||
@@:
|
|
||||||
mov al, [edx]
|
|
||||||
cmp [edi], al
|
|
||||||
jnz .next_related_descriptor
|
|
||||||
test al, al
|
|
||||||
jz .found_related_descriptor
|
|
||||||
inc edx
|
|
||||||
inc edi
|
|
||||||
jmp @b
|
|
||||||
.next_related_descriptor_restore:
|
|
||||||
mov ebp, [import_descriptor]
|
|
||||||
.next_related_descriptor:
|
|
||||||
add ebp, sizeof.IMAGE_IMPORT_DESCRIPTOR
|
|
||||||
jmp .look_related_descriptors
|
|
||||||
.found_related_descriptor:
|
|
||||||
; 3l. Check what we should do:
|
|
||||||
; advance to 3m, if we need to reimport everything,
|
|
||||||
; go to 3n, if we just need to relocate something.
|
|
||||||
mov [import_descriptor], ebp
|
|
||||||
cmp [relocated_bound_modules_count], 0
|
|
||||||
jnz .bound_import_add_delta
|
|
||||||
; 3m. Apply resolve_import_from_module and return to 3j.
|
|
||||||
resolve_import_from_module .bound_import_failed ; should preserve ebx,esi
|
|
||||||
jmp .next_related_descriptor_restore
|
|
||||||
.bound_import_add_delta:
|
|
||||||
; 3n. Loop over all imported symbols.
|
|
||||||
; For every imported symbol, check whether it fits within one of relocated
|
|
||||||
; modules, and if so, apply relocation to it.
|
|
||||||
; For consistency with generic-case resolve_import_from_module,
|
; For consistency with generic-case resolve_import_from_module,
|
||||||
; determine end of thunks from OriginalFirstThunk array.
|
; check for end of thunks by looking at OriginalFirstThunk array.
|
||||||
|
; Note: we assume here that ForwarderChain list is ordered.
|
||||||
|
; After that, go to 6.
|
||||||
|
.newstyle_need_reloc:
|
||||||
|
mov eax, [import_module]
|
||||||
|
mov eax, [eax+MODULE.base]
|
||||||
|
call prepare_import_from_module
|
||||||
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
mov edx, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
||||||
add edx, [esi+MODULE.base]
|
add edx, [esi+MODULE.base]
|
||||||
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
mov ebx, [ebp+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
|
||||||
add ebx, [esi+MODULE.base]
|
add ebx, [esi+MODULE.base]
|
||||||
.bound_import_add_delta_loop:
|
mov eax, [ebp+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain]
|
||||||
|
lea eax, [edx+eax*4]
|
||||||
|
mov [next_forwarder], eax
|
||||||
|
.new_binding_relocate_loop:
|
||||||
cmp dword [ebx], 0
|
cmp dword [ebx], 0
|
||||||
jz .next_related_descriptor_restore
|
jz .new_binding_relocate_done
|
||||||
mov ecx, [relocated_bound_modules_ptr]
|
cmp edx, [next_forwarder]
|
||||||
mov ebp, [relocated_bound_modules_count]
|
jz .new_binding_resolve_thunk
|
||||||
push esi
|
mov [bound_module], 0
|
||||||
.find_delta_module:
|
mov eax, [bound_modules_count]
|
||||||
mov esi, [ecx]
|
mov [bound_modules_left], eax
|
||||||
mov eax, [edx]
|
mov edi, [bound_modules_ptr]
|
||||||
sub eax, [esi+MODULE.base]
|
; There should be at least one module containing address [edx].
|
||||||
add eax, [esi+MODULE.basedelta]
|
; There can be more than one if preferred address ranges for two modules intersect;
|
||||||
cmp eax, [esi+MODULE.size]
|
; in this case, we are forced to resolve address from scratch.
|
||||||
jb .found_delta_module
|
.new_binding_lookup_module:
|
||||||
add ecx, 4
|
mov ecx, [edx]
|
||||||
dec ebp
|
mov eax, [edi]
|
||||||
jnz .find_delta_module
|
sub ecx, [eax+MODULE.base]
|
||||||
pop esi
|
add ecx, [eax+MODULE.basedelta]
|
||||||
.bound_import_add_delta_next:
|
cmp ecx, [eax+MODULE.size]
|
||||||
add ebx, 4
|
jae @f
|
||||||
|
cmp [bound_module], 0
|
||||||
|
jnz .new_binding_resolve_thunk
|
||||||
|
mov [bound_module], eax
|
||||||
|
@@:
|
||||||
|
add edi, 4
|
||||||
|
dec [bound_modules_left]
|
||||||
|
jnz .new_binding_lookup_module
|
||||||
|
mov edi, [bound_module]
|
||||||
|
mov edi, [edi+MODULE.basedelta]
|
||||||
|
test edi, edi
|
||||||
|
jz .new_binding_relocate_next
|
||||||
|
call .ensure_writable ; should preserve esi,edi,ebp,ebx,edx
|
||||||
|
add dword [edx], edi
|
||||||
|
.new_binding_relocate_next:
|
||||||
add edx, 4
|
add edx, 4
|
||||||
jmp .bound_import_add_delta_loop
|
add ebx, 4
|
||||||
.found_delta_module:
|
jmp .new_binding_relocate_loop
|
||||||
mov ebp, [esi+MODULE.basedelta]
|
.new_binding_resolve_thunk:
|
||||||
pop esi
|
mov [bound_modules_left], edx
|
||||||
call .ensure_writable ; should preserve esi,ebp,ebx,edx
|
call .ensure_writable
|
||||||
add [edx], ebp
|
mov ecx, [ebx]
|
||||||
jmp .bound_import_add_delta_next
|
get_address_for_thunk
|
||||||
.bound_import_next:
|
test eax, eax
|
||||||
; 3o. Free the data we might have allocated and return to 3a.
|
jz .newstyle_failed
|
||||||
cmp [relocated_bound_modules_ptr], 0
|
mov edx, [bound_modules_left]
|
||||||
jz .bound_import_loop
|
mov ecx, [edx]
|
||||||
stdcall free, [relocated_bound_modules_ptr]
|
mov [edx], eax
|
||||||
jmp .bound_import_loop
|
cmp edx, [next_forwarder]
|
||||||
.done:
|
jnz .new_binding_relocate_next
|
||||||
call .restore_protection
|
mov eax, [ebp+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
|
||||||
xor eax, eax
|
add eax, [esi+MODULE.base]
|
||||||
ret
|
lea eax, [eax+ecx*4]
|
||||||
.bound_import_failed:
|
mov [next_forwarder], eax
|
||||||
cmp [relocated_bound_modules_ptr], 0
|
jmp .new_binding_relocate_next
|
||||||
jz .failed
|
.new_binding_relocate_done:
|
||||||
stdcall free, [relocated_bound_modules_ptr]
|
stdcall free, [bound_modules_ptr]
|
||||||
|
jmp .next_descriptor
|
||||||
|
.newstyle_failed:
|
||||||
|
stdcall free, [bound_modules_ptr]
|
||||||
.failed:
|
.failed:
|
||||||
call .restore_protection
|
call .restore_protection
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
@ -797,6 +833,8 @@ proc prepare_import_from_module c, export_base, export_ptr, export_size
|
|||||||
cmp [eax+STRIPPED_PE_HEADER.NumberOfRvaAndSizes], SPE_DIRECTORY_EXPORT
|
cmp [eax+STRIPPED_PE_HEADER.NumberOfRvaAndSizes], SPE_DIRECTORY_EXPORT
|
||||||
jbe .noexport
|
jbe .noexport
|
||||||
mov edx, [eax+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY+IMAGE_DATA_DIRECTORY.VirtualAddress]
|
mov edx, [eax+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY+IMAGE_DATA_DIRECTORY.VirtualAddress]
|
||||||
|
test edx, edx
|
||||||
|
jz .noexport
|
||||||
add edx, eax
|
add edx, eax
|
||||||
mov [export_ptr], edx
|
mov [export_ptr], edx
|
||||||
mov edx, [eax+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY+IMAGE_DATA_DIRECTORY.isize]
|
mov edx, [eax+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY+IMAGE_DATA_DIRECTORY.isize]
|
||||||
@ -808,6 +846,8 @@ proc prepare_import_from_module c, export_base, export_ptr, export_size
|
|||||||
cmp [ecx+IMAGE_NT_HEADERS.OptionalHeader.NumberOfDirectories], IMAGE_DIRECTORY_ENTRY_EXPORT
|
cmp [ecx+IMAGE_NT_HEADERS.OptionalHeader.NumberOfDirectories], IMAGE_DIRECTORY_ENTRY_EXPORT
|
||||||
jbe .noexport
|
jbe .noexport
|
||||||
mov edx, [ecx+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress+IMAGE_DIRECTORY_ENTRY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY]
|
mov edx, [ecx+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress+IMAGE_DIRECTORY_ENTRY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY]
|
||||||
|
test edx, edx
|
||||||
|
jz .noexport
|
||||||
add edx, eax
|
add edx, eax
|
||||||
mov [export_ptr], edx
|
mov [export_ptr], edx
|
||||||
mov edx, [ecx+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.isize+IMAGE_DIRECTORY_ENTRY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY]
|
mov edx, [ecx+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.isize+IMAGE_DIRECTORY_ENTRY_EXPORT*sizeof.IMAGE_DATA_DIRECTORY]
|
||||||
@ -885,7 +925,7 @@ endl
|
|||||||
push ecx esi
|
push ecx esi
|
||||||
repz cmpsb
|
repz cmpsb
|
||||||
pop esi ecx
|
pop esi ecx
|
||||||
jz .found
|
jz .hint_ok
|
||||||
.ignore_hint:
|
.ignore_hint:
|
||||||
; 4. Binary search over name table.
|
; 4. Binary search over name table.
|
||||||
; Export names are sorted with respect to repz cmpsb.
|
; Export names are sorted with respect to repz cmpsb.
|
||||||
@ -921,23 +961,13 @@ endl
|
|||||||
; Generic error handler.
|
; Generic error handler.
|
||||||
.export_name_not_found:
|
.export_name_not_found:
|
||||||
mov ebx, esi
|
mov ebx, esi
|
||||||
mov esi, [module]
|
call .get_module_name
|
||||||
test esi, esi
|
|
||||||
jnz @f
|
|
||||||
mutex_lock modules_mutex
|
|
||||||
mov ecx, [export_base]
|
|
||||||
call find_module_by_addr
|
|
||||||
mutex_unlock modules_mutex
|
|
||||||
@@:
|
|
||||||
mov eax, msg_unknown
|
|
||||||
test esi, esi
|
|
||||||
jz @f
|
|
||||||
mov eax, [esi+MODULE.filename]
|
|
||||||
@@:
|
|
||||||
ccall loader_say_error, msg_export_name_not_found, ebx, msg_export_not_found, eax, 0
|
ccall loader_say_error, msg_export_name_not_found, ebx, msg_export_not_found, eax, 0
|
||||||
.return0:
|
.return0:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
ret
|
ret
|
||||||
|
.hint_ok:
|
||||||
|
mov eax, edx
|
||||||
.found:
|
.found:
|
||||||
; 5. We have found an index in AddressOfNames/AddressOfNameOrdinals arrays,
|
; 5. We have found an index in AddressOfNames/AddressOfNameOrdinals arrays,
|
||||||
; convert it to index in AddressOfFunctions array.
|
; convert it to index in AddressOfFunctions array.
|
||||||
@ -958,9 +988,9 @@ endl
|
|||||||
; 7. Check whether the address is inside the export directory.
|
; 7. Check whether the address is inside the export directory.
|
||||||
; If not, we are done.
|
; If not, we are done.
|
||||||
add eax, [export_base]
|
add eax, [export_base]
|
||||||
mov esi, eax
|
mov ebx, eax
|
||||||
sub esi, edx
|
sub ebx, edx
|
||||||
cmp esi, [export_size]
|
cmp ebx, [export_size]
|
||||||
jb .export_is_forwarded
|
jb .export_is_forwarded
|
||||||
ret
|
ret
|
||||||
.export_is_forwarded:
|
.export_is_forwarded:
|
||||||
@ -976,7 +1006,10 @@ endl
|
|||||||
jz .dot_found
|
jz .dot_found
|
||||||
cmp byte [eax-1], 0
|
cmp byte [eax-1], 0
|
||||||
jnz @b
|
jnz @b
|
||||||
jmp .export_name_not_found
|
call .get_module_name
|
||||||
|
ccall loader_say_error, msg_invalid_forwarder, eax, 0
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
.dot_found:
|
.dot_found:
|
||||||
; 8b. Allocate the memory.
|
; 8b. Allocate the memory.
|
||||||
sub eax, ebx
|
sub eax, ebx
|
||||||
@ -1057,6 +1090,23 @@ endl
|
|||||||
stdcall free, edi
|
stdcall free, edi
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
fpo_delta = fpo_delta + 4
|
||||||
|
.get_module_name:
|
||||||
|
mov esi, [module]
|
||||||
|
test esi, esi
|
||||||
|
jnz @f
|
||||||
|
mutex_lock modules_mutex
|
||||||
|
mov ecx, [export_base]
|
||||||
|
call find_module_by_addr
|
||||||
|
mutex_unlock modules_mutex
|
||||||
|
@@:
|
||||||
|
mov eax, msg_unknown
|
||||||
|
test esi, esi
|
||||||
|
jz @f
|
||||||
|
mov eax, [esi+MODULE.filename]
|
||||||
|
@@:
|
||||||
|
retn
|
||||||
endp
|
endp
|
||||||
|
|
||||||
; Resolve symbol from a module by name.
|
; Resolve symbol from a module by name.
|
||||||
|
Loading…
Reference in New Issue
Block a user