/
stage1.asm
460 lines (434 loc) · 8.52 KB
/
stage1.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
;
; *
; * DiskCryptor - open source partition encryption tool
; * Copyright (c) 2008-2009
; * ntldr <ntldr@diskcryptor.net> PGP key ID - 0xC48251EB4F8E4E6E
; *
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 3 as
; published by the Free Software Foundation.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
org 0
include 'win32a.inc'
include 'macro.inc'
include 'struct.inc'
use16
nop
nop
nop
nop
; all bootloader data are loaded to memory
; setup real mode segment registers
cli
mov ax, cs
mov ds, ax
mov gs, ax
xor bx, bx
mov es, bx
mov fs, bx
mov ss, bx
; setup initial realmode stack
mov sp, 4000h
sti
; save boot disk
push dx
; get code base
call next
next:
pop bp
add bp, 0 - $ + 1
; bp - code base
; get embedded boot_hook image address
lea bx, [bp+bd_block+boot_data]
; get virtual size of boot_hook image
mov ebx, [bx+boot_mod.virt_size]
; align virtual size to 1k
add ebx, (1024-1)
and ebx, not (1024-1)
; add boot data size and 2kb for stack
add ebx, (bd_kbs * 1024) + 2048
mov [ds:bp+bd_block+bd_data.bd_size], ebx
; calc needed memory size
shr bx, 10
; get base memory size
mov dx, [fs:0413h]
sub dx, bx
; copy boot data block to top of base memory
shl dx, 6
mov es, dx
xor di, di
lea si, [bp+bd_block]
mov cx, bd_size
cld
rep movsb
; restore boot disk
pop dx
; push return address
lea ax, [bp+pm_loader]
push ax
; jump to resident block
push es
push pm_enable
retf
pm_loader: ; protected mode loader
use32
lea ebx, [ecx + (bd_kbs * 1024)]
; get embedded PE image address
call next2
next2:
pop ebp
add ebp, bd_block + boot_data - next2
mov edx, ebp
add edx, [ebp+boot_mod.raw_size]
; ecx - boot data block
; ebp - boot_hook image
; edx - boot_load image
; ebx - new boot_hook image base
call load_module
; load boot_load module
mov ebp, edx
mov ebx, 8000h
call load_module
jmp $
load_module: ; ebp - module, ebx - address, ecx - bd_data
pushad
; push EP parameters to stack
push 5000h
push ecx
; zero memory
mov ecx, [ebp+boot_mod.virt_size]
mov edi, ebx
xor eax, eax
rep stosb
; copy module code
mov esi, ebp
mov edi, ebx
mov ecx, [ebp+boot_mod.raw_size]
rep movsb
; process relocs
mov ecx, [ebx+boot_mod.n_rels]
lea esi, [ebx+boot_mod.relocs]
do_relocs:
test ecx, ecx
jz relocs_done
lodsd
add [ebx+eax], ebx
dec ecx
jmp do_relocs
relocs_done:
; zero original image
mov edi, ebp
mov ecx, [ebp+boot_mod.raw_size]
rep stosb
; call EP
mov eax, [ebx+boot_mod.entry_rva]
add eax, ebx
call eax
add esp, 8
popad
ret
bd_block: ; boot data block
use16
org 0
bdb bd_data
NSEG = 0
DSEG = 1 shl 3 ; 32-bit data selector
CSEG = 2 shl 3 ; 32-bit code selector
ESEG = 3 shl 3 ; 32-bit extended data selector
RCSEG = 4 shl 3 ; 16-bit code selector
RDSEG = 5 shl 3 ; 16-bit data selector
gdtr: ; Global Descriptors Table Register
dw 6*8-1 ; limit of GDT (size minus one)
dd gdt ; linear address of GDT
gdt rw 4 ; null desciptor
dw 0FFFFh, 0, 9200h, 0CFh ; 32-bit data desciptor
dw 0FFFFh, 0, 9A00h, 0CFh ; 32-bit code desciptor
pm32_edes:
dw 0FFFFh, 0, 9200h, 0CFh ; 32-bit extended data desciptor
pm16_cdes:
dw 0FFFFh, 0, 9E00h, 0 ; 16 bit code desciptor
pm16_ddes:
dw 0FFFFh, 0, 9200h, 0 ; 16 bit data desciptor
pm_enable:
use16
; save boot disk
mov [cs:bdb.boot_dsk], dl
; get return address
xor edx, edx
pop dx
; setup segment registers
xor ecx, ecx
mov cx, cs
mov ds, cx
; get bd_block offset
shl ecx, 4
mov [bdb.bd_base], ecx
; setup temporary PM stack
mov [bdb.esp_32], 20000h
; inverse real mode block signature in runtime
; to prevent finding it in false location
not [bdb.sign1]
not [bdb.sign2]
; correct GDT address
add [gdtr+2], ecx
; correct descriptors
or [pm16_cdes+2], ecx
or [pm16_ddes+2], ecx
or [pm32_edes+2], ecx
; correct PM/RM jumps
add [pm_jump], ecx
mov word [rm_jump], cs
; setup callback pointers
lea eax, [ecx+call_rm]
mov [bdb.call_rm], eax
lea eax, [ecx+jump_rm]
mov [bdb.jump_rm], eax
lea eax, [ecx+hook_ints]
mov [bdb.hook_ints], eax
; calculate pmode return address
xor eax, eax
mov ax, gs
shl eax, 4
add eax, edx
mov [bdb.segoff], eax
; jump to pmode
call jump_to_pm
use32
; return to caller
jmp [fs:bdb.segoff]
regs_load:
use16
mov eax, [cs:bdb.rmc.eax]
mov ecx, [cs:bdb.rmc.ecx]
mov edx, [cs:bdb.rmc.edx]
mov ebx, [cs:bdb.rmc.ebx]
mov ebp, [cs:bdb.rmc.ebp]
mov esi, [cs:bdb.rmc.esi]
mov edi, [cs:bdb.rmc.edi]
push [cs:bdb.rmc.efl]
push [cs:bdb.rmc.ds]
push [cs:bdb.rmc.es]
pop es
pop ds
popfd
ret
regs_save:
use16
mov [cs:bdb.rmc.eax], eax
mov [cs:bdb.rmc.ecx], ecx
mov [cs:bdb.rmc.edx], edx
mov [cs:bdb.rmc.ebx], ebx
mov [cs:bdb.rmc.ebp], ebp
mov [cs:bdb.rmc.esi], esi
mov [cs:bdb.rmc.edi], edi
push es
push ds
pushfd
pop [cs:bdb.rmc.efl]
pop [cs:bdb.rmc.ds]
pop [cs:bdb.rmc.es]
ret
call_rm:
use32
pushad
; switch to RM
call jump_to_rm
use16
; load registers
call regs_load
pushf
cli
call far [cs:bdb.segoff]
; save changed registers
call regs_save
; return to pmode
call jump_to_pm
use32
popad
ret
jump_rm:
use32
; switch to RM
call jump_to_rm
use16
; load registers
call regs_load
; jump to RM code
jmp far [cs:bdb.segoff]
hook_ints:
use32
; switch to RM
call jump_to_rm
use16
; nook int15
xor ax, ax
mov fs, ax
; hook int13
mov eax, [fs:4Ch]
mov [bdb.old_int13], eax
mov word [fs:4Ch], new_int13
mov word [fs:4Eh], cs
; hook int15
mov eax, [fs:54h]
mov [bdb.old_int15], eax
mov word [fs:54h], new_int15
mov word [fs:56h], cs
; return to pmode
call jump_to_pm
use32
ret
new_int15:
use16
cmp ax, 0E820h
jnz i15_pass
cmp edx, 0534D4150h
jnz i15_pass
sti
stc
cld
cmp ebx, [cs:bdb.mem_map.n_map]
jnc i15_exit
push ds
pusha
push cs
pop ds
imul bx, (8+8+4)
lea si, [bx+bdb.mem_map.map]
mov cx, (8+8+4)
rep movsb
popa
pop ds
inc ebx
cmp ebx, [cs:bdb.mem_map.n_map]
jnz @F
xor ebx, ebx
@@:
mov eax, 0534D4150h
mov ecx, (8+8+4)
clc
jmp i15_exit
i15_pass:
jmp far [cs:bdb.old_int15]
i15_exit:
retf 2
new_int13:
use16
jmp @F
dd 6D4701BBh
@@:
; save segment registers
push fs
push gs
; save registers
call regs_save
; save flags
mov bp, sp
push word [ss:bp+8]
pop word [cs:bdb.push_fl]
call jump_to_pm
use32
; call to PM callback
call [fs:bdb.int_cbk]
; return to RM
call jump_to_rm
use16
; load registers
call regs_load
; load segment registers
pop gs
pop fs
retf 2
jump_to_pm:
use16
; disable interrupts
cli
; get return address
pop ax
movzx eax, ax
mov [cs:bdb.ret_32], eax
; save real mode stack
mov [cs:bdb.esp_16], esp
mov [cs:bdb.ss_16], ss
; setup ds
mov ax, cs
mov ds, ax
; load GDTR
lgdt [gdtr]
; switch to protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
; jump to PM code
pm_jump = $+2
jmp32 CSEG:pm_start
pm_start:
use32
; load 4 GB data descriptor
mov ax, ESEG
mov fs, ax
mov ax, DSEG
mov ds, ax
mov es, ax
mov gs, ax
mov ss, ax
; enable SSE
mov eax, cr4
or eax, 200h ; OSFXSR bit
mov cr4, eax
; load PM stack
mov esp, [fs:bdb.esp_32]
; return to caller
mov eax, [fs:bdb.ret_32]
add eax, [fs:bdb.bd_base]
push eax
ret
jump_to_rm:
use32
; get return address
pop [fs:bdb.ret_32]
; save PM stack
mov [fs:bdb.esp_32], esp
; load PM16 selector
mov ax, RDSEG
mov ds, ax
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax
; jump to PM16
jmp RCSEG:pm16_start
pm16_start:
use16
; clear PM bit in cr0
mov eax, cr0
and eax, 0FFFFFFFEh
mov cr0, eax
; jump to real mode
rm_jump = $+3
jmp 0:rm_start
rm_start:
; load RM segments
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; load RM stack
mov ss, [bdb.ss_16]
mov esp, [bdb.esp_16]
; return to caller
mov eax, [bdb.ret_32]
sub eax, [bdb.bd_base]
push ax
ret
bd_size = $
bd_kbs = (bd_size / 1024) + 1
boot_data: