Rev 6767 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6614 | clevermous | 1 | ; Check whether PE module has been loaded at preferred address. |
2 | ; If not, relocate the module. |
||
3 | ; |
||
4 | ; in: esi = PE base address |
||
5 | ; in: [esp+4] = module name for debug print |
||
6 | ; out: CF=1 - fail |
||
7 | proc fixup_pe_relocations uses edi ebp |
||
8 | ; 1. Fetch some data from PE header or stripped PE header. |
||
9 | ; We need: |
||
10 | ; * ImageBase - preferred address, compare with esi = actual load address; |
||
11 | ; ebp will keep the delta |
||
12 | ; * RVA and size of fixups directory |
||
13 | ; * flag IMAGE_FILE_RELOCS_STRIPPED from Characteristics |
||
14 | ; If the actual address equals the preferred address, do nothing. |
||
15 | ; If fixups directory is present, proceed to 2. |
||
16 | ; If there is no fixups directory, there are two options: |
||
17 | ; * either the directory has not been created |
||
18 | ; * or the module has no fixups (data-only module, for example). |
||
19 | ; In the first case, IMAGE_FILE_RELOCS_STRIPPED is set, and this is an error. |
||
20 | ; In the second case, IMAGE_FILE_RELOCS_STRIPPED is not set; do nothing. |
||
21 | mov ebp, esi |
||
22 | cmp word [esi], 'MZ' |
||
23 | jz .parse_mz |
||
24 | sub ebp, [esi+STRIPPED_PE_HEADER.ImageBase] |
||
25 | jnz @f |
||
26 | .nothing: |
||
27 | ret |
||
28 | @@: |
||
29 | mov dl, byte [esi+STRIPPED_PE_HEADER.Characteristics] |
||
30 | lea eax, [esi+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_BASERELOC*sizeof.IMAGE_DATA_DIRECTORY] |
||
31 | cmp [esi+STRIPPED_PE_HEADER.NumberOfRvaAndSizes], SPE_DIRECTORY_BASERELOC |
||
32 | ja .common |
||
33 | .norelocs: |
||
34 | test dl, IMAGE_FILE_RELOCS_STRIPPED |
||
35 | jz .nothing |
||
36 | stc |
||
37 | ret |
||
38 | .parse_mz: |
||
39 | mov eax, [esi+3Ch] |
||
40 | add eax, esi |
||
41 | sub ebp, [eax+IMAGE_NT_HEADERS.OptionalHeader.ImageBase] |
||
42 | jz .nothing |
||
43 | mov dl, byte [esi+IMAGE_NT_HEADERS.FileHeader.Characteristics] |
||
44 | cmp [eax+IMAGE_NT_HEADERS.OptionalHeader.NumberOfDirectories], IMAGE_DIRECTORY_ENTRY_BASERELOC |
||
45 | jbe .norelocs |
||
46 | add eax, IMAGE_NT_HEADERS.OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BASERELOC*sizeof.IMAGE_DATA_DIRECTORY |
||
47 | .common: |
||
48 | mov edi, [eax+IMAGE_DATA_DIRECTORY.VirtualAddress] |
||
49 | push [eax+IMAGE_DATA_DIRECTORY.isize] |
||
50 | virtual at esp |
||
51 | .sizeleft dd ? |
||
52 | end virtual |
||
53 | add edi, esi |
||
54 | cmp [.sizeleft], 0 |
||
55 | jz .norelocs |
||
56 | ; 2. We need to relocate and we have the relocation table. |
||
57 | ; esi = PE base address |
||
58 | ; edi = pointer to current data of relocation table |
||
59 | ; 2a. Relocation table is organized into blocks describing every page. |
||
60 | ; End of table is defined from table size fetched from the header. |
||
61 | ; Loop 2b-2g over all blocks until no more data is left. |
||
62 | .pageloop: |
||
63 | ; 2b. Load the header of the current block: address and size. |
||
64 | ; Advance total size. |
||
65 | ; Size in the block includes size of the header, subtract it. |
||
66 | ; If there is no data in this block, go to 2g. |
||
67 | mov edx, [edi+IMAGE_BASE_RELOCATION.VirtualAddress] |
||
68 | mov ecx, [edi+IMAGE_BASE_RELOCATION.SizeOfBlock] |
||
69 | sub [.sizeleft], ecx |
||
70 | add edi, sizeof.IMAGE_BASE_RELOCATION |
||
71 | sub ecx, sizeof.IMAGE_BASE_RELOCATION |
||
72 | jbe .pagedone |
||
73 | ; 2c. We are going to modify data, so mprotect the current page to be writable. |
||
74 | ; Save the old protection, we will restore it after the block is processed. |
||
75 | ; Ignore any error. |
||
76 | PROT_READ = 1 |
||
77 | PROT_WRITE = 2 |
||
78 | PROT_EXEC = 4 |
||
79 | push esi ecx |
||
80 | mov eax, 68 |
||
81 | mov ebx, 30 |
||
82 | mov ecx, PROT_READ+PROT_WRITE |
||
83 | add edx, esi |
||
84 | mov esi, 0x1000 |
||
85 | call FS_SYSCALL_PTR |
||
86 | pop ecx |
||
87 | push eax |
||
88 | ; 2d. Block data is an array of word values. Repeat 2e for every of those. |
||
89 | .relocloop: |
||
90 | sub ecx, 2 |
||
91 | jb .relocdone |
||
92 | ; 2e. Every value consists of a 4-bit type and 12-bit offset in the page. |
||
93 | ; x86 uses two types: 0 = no data (used for padding), 3 = 32-bit relative. |
||
94 | movzx eax, word [edi] |
||
95 | add edi, 2 |
||
96 | mov ebx, eax |
||
97 | and ebx, 0xFFF |
||
98 | shr eax, 12 |
||
99 | jz .relocloop |
||
100 | cmp al, IMAGE_REL_BASED_HIGHLOW |
||
101 | jnz .badreloc |
||
102 | add [edx+ebx], ebp |
||
103 | jmp .relocloop |
||
104 | .relocdone: |
||
105 | ; 2f. Restore memory protection changed in 2c. |
||
106 | pop ecx |
||
107 | cmp ecx, -1 |
||
108 | jz @f |
||
109 | mov eax, 68 |
||
110 | mov ebx, 30 |
||
111 | mov esi, 0x1000 |
||
112 | call FS_SYSCALL_PTR |
||
113 | @@: |
||
114 | pop esi |
||
115 | .pagedone: |
||
116 | cmp [.sizeleft], 0 |
||
117 | jnz .pageloop |
||
118 | pop eax ; pop .sizeleft |
||
119 | ; 3. For performance reasons, relocation should be avoided |
||
120 | ; by choosing an appropriate preferred address. |
||
121 | ; If we have actually relocated something, yell to the debug board, |
||
122 | ; so the programmer can notice that. |
||
123 | mov ecx, msg_relocated1 |
||
124 | call sys_msg_board_str |
||
125 | mov ecx, [esp+4] |
||
126 | call sys_msg_board_str |
||
127 | mov ecx, msg_relocated2 |
||
128 | call sys_msg_board_str |
||
129 | clc |
||
130 | ret |
||
131 | .badreloc: |
||
132 | pop eax |
||
133 | mov ecx, msg_bad_relocation1 |
||
134 | call sys_msg_board_str |
||
135 | mov ecx, [esp+4] |
||
136 | call sys_msg_board_str |
||
137 | mov ecx, msg_newline |
||
138 | call sys_msg_board_str |
||
139 | stc |
||
140 | ret |
||
141 | endp |