mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[mbr] replace gpt.S with a more generic msg.S
* msg.S now reads an ASCII message (with escaped colour sequences) from the following blocks, which is both more flexible and allows for more content to be displayed. * Also adds Bochs testing to the MBR build facility
This commit is contained in:
parent
b8579c04da
commit
bfbb9d2ed5
9 changed files with 325 additions and 122 deletions
|
@ -17,8 +17,7 @@
|
|||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
OBJECTS = mbr.o
|
||||
TARGET = mbr
|
||||
TEST_TARGET = msg
|
||||
|
||||
ASM = gcc
|
||||
CC = gcc
|
||||
|
@ -27,13 +26,14 @@ OBJDUMP = objdump
|
|||
OBJCOPY = objcopy
|
||||
CFLAGS = -m32
|
||||
LDFLAGS = -nostartfile
|
||||
BOCHS = "C:/Program Files/Bochs/bochsdbg.exe"
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET).bin
|
||||
all: mbr.bin msg.bin
|
||||
|
||||
clean:
|
||||
@-rm -f -v *.o *.out $(TARGET).map
|
||||
@-rm -f -v *.o *.out *.map *.bin *.img *.ini
|
||||
|
||||
%.o: %.c Makefile
|
||||
@echo "[CC] $@"
|
||||
|
@ -44,17 +44,25 @@ clean:
|
|||
@$(ASM) -c -o $*.o $(CFLAGS) $<
|
||||
|
||||
# Produce a disassembly dump, for verification purposes
|
||||
dis: $(TARGET).out
|
||||
dis: $(TEST_TARGET).out
|
||||
@echo "[DIS] $<"
|
||||
@$(OBJCOPY) -O binary -j .main --set-section-flags .main=alloc,load,readonly,code $< main.bin
|
||||
@$(OBJDUMP) -D -bbinary -mi8086 -Mintel main.bin | less
|
||||
@-rm -f main.bin
|
||||
|
||||
$(TARGET).out: $(OBJECTS) $(TARGET).ld
|
||||
@echo "[LD] $@"
|
||||
@$(LD) $(LDFLAGS) -T$(TARGET).ld -o $@ $(OBJECTS) -Map $(TARGET).map
|
||||
# Run the MBR in a Bochs environment (append msg.txt in subsequent blocks)
|
||||
test: $(TEST_TARGET).bin
|
||||
@test -s $(BOCHS) || { echo "Error: $(BOCHS) was not found on this system"; exit 1; }
|
||||
@cat $(TEST_TARGET).bin msg.txt > disk.img
|
||||
@truncate -c -s 10M disk.img
|
||||
-@$(BOCHS) -f bochsrc.bxrc -q
|
||||
|
||||
$(TARGET).bin: $(TARGET).out
|
||||
%.out: %.o mbr.ld
|
||||
@echo "[LD] $@"
|
||||
@$(LD) $(LDFLAGS) -Tmbr.ld -o $@ $< -Map $*.map
|
||||
|
||||
%.bin: %.out
|
||||
@echo "[MBR] $@"
|
||||
@# Note: -j only works for sections that have the 'ALLOC' flag set
|
||||
@$(OBJCOPY) -O binary -j .main --gap-fill=0x00 $< $@
|
||||
@-rm -f $< $*.map
|
||||
|
|
58
res/mbr/bochsrc.bxrc
Normal file
58
res/mbr/bochsrc.bxrc
Normal file
|
@ -0,0 +1,58 @@
|
|||
# configuration file generated by Bochs
|
||||
plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, gameport=true, iodebug=true
|
||||
config_interface: win32config
|
||||
display_library: win32, options="gui_debug"
|
||||
memory: host=32, guest=32
|
||||
romimage: file="C:\Program Files\Bochs\BIOS-bochs-latest", address=0x00000000, options=none
|
||||
vgaromimage: file="C:\Program Files\Bochs\VGABIOS-lgpl-latest"
|
||||
boot: disk
|
||||
floppy_bootsig_check: disabled=0
|
||||
# no floppya
|
||||
# no floppyb
|
||||
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata0-master: type=disk, path="C:\Projects\rufus\res\mbr\disk.img", mode=flat, cylinders=64, heads=10, spt=32, sect_size=512, model="Virtual HDD", biosdetect=auto, translation=lba
|
||||
ata0-slave: type=none
|
||||
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata1-master: type=none
|
||||
ata1-slave: type=none
|
||||
ata2: enabled=false
|
||||
ata3: enabled=false
|
||||
optromimage1: file=none
|
||||
optromimage2: file=none
|
||||
optromimage3: file=none
|
||||
optromimage4: file=none
|
||||
optramimage1: file=none
|
||||
optramimage2: file=none
|
||||
optramimage3: file=none
|
||||
optramimage4: file=none
|
||||
pci: enabled=1, chipset=i440fx
|
||||
vga: extension=vbe, update_freq=5, realtime=1
|
||||
cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
|
||||
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string=" Intel(R) Pentium(R) 4 CPU "
|
||||
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
|
||||
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, x86_64=true
|
||||
cpuid: 1g_pages=false, pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true
|
||||
cpuid: vmx=1
|
||||
print_timestamps: enabled=0
|
||||
debugger_log: -
|
||||
magic_break: enabled=1
|
||||
port_e9_hack: enabled=0
|
||||
private_colormap: enabled=0
|
||||
clock: sync=none, time0=local, rtc_sync=0
|
||||
# no cmosimage
|
||||
log: -
|
||||
logprefix: %t%e%d
|
||||
debug: action=ignore
|
||||
info: action=report
|
||||
error: action=report
|
||||
panic: action=ask
|
||||
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
|
||||
mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
|
||||
sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none
|
||||
speaker: enabled=true, mode=sound
|
||||
parport1: enabled=true, file=none
|
||||
parport2: enabled=false
|
||||
com1: enabled=true, mode=null
|
||||
com2: enabled=false
|
||||
com3: enabled=false
|
||||
com4: enabled=false
|
100
res/mbr/gpt.S
100
res/mbr/gpt.S
|
@ -1,100 +0,0 @@
|
|||
/********************************************************************************/
|
||||
/* GPT - A protective MBR that displays a notice if a user attempts to boot a */
|
||||
/* GPT drive in BIOS/Legacy mode. */
|
||||
/* */
|
||||
/* Copyright (c) 2019 Pete Batard <pete@akeo.ie> */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the Free */
|
||||
/* Software Foundation, either version 3 of the License, or (at your option) */
|
||||
/* any later version. */
|
||||
/* */
|
||||
/* 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/>. */
|
||||
/* */
|
||||
/********************************************************************************/
|
||||
|
||||
/********************************************************************************/
|
||||
/* GNU Assembler Settings: */
|
||||
/********************************************************************************/
|
||||
.intel_syntax noprefix
|
||||
.code16
|
||||
/********************************************************************************/
|
||||
|
||||
/********************************************************************************/
|
||||
/* Constants: */
|
||||
/********************************************************************************/
|
||||
MBR_ADDR = 0x7c00
|
||||
MBR_SIZE = 0x200
|
||||
MBR_RESERVED = 0x1b8 # Start of the reserved section (partition table, etc.)
|
||||
PT_MAX = 0x04 # Number of partition entries in the partition table
|
||||
PT_ENTRY_SIZE = 0x10 # Size of a partition entry in the partition table
|
||||
|
||||
/********************************************************************************/
|
||||
/* MBR: This section resides at 0x00007c00 and is exactly 512 bytes */
|
||||
/********************************************************************************/
|
||||
.section main, "ax"
|
||||
.globl mbr
|
||||
mbr:
|
||||
inc cx
|
||||
dec bx
|
||||
inc bp
|
||||
dec di
|
||||
cld
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov si, offset sep
|
||||
call print_string
|
||||
mov si, offset hdr
|
||||
call print_string
|
||||
mov si, offset sep
|
||||
call print_string
|
||||
mov si, offset txt
|
||||
call print_string
|
||||
hlt
|
||||
|
||||
print_string:
|
||||
lodsb
|
||||
cmp al, 0x00
|
||||
jz 0f
|
||||
mov ah, 0x0e
|
||||
mov bx, 0x0007
|
||||
int 0x10
|
||||
jmp print_string
|
||||
0: ret
|
||||
|
||||
/********************************************************************************/
|
||||
/* Data section */
|
||||
/********************************************************************************/
|
||||
sep:
|
||||
.string "****************************************\r\n"
|
||||
hdr:
|
||||
.string "*** ERROR: LEGACY BOOT OF UEFI MEDIA ***\r\n"
|
||||
txt:
|
||||
.ascii "\r\n" \
|
||||
"This drive can only boot in UEFI mode.\r\n" \
|
||||
"It can not boot in BIOS/Legacy mode.\r\n" \
|
||||
"\r\n" \
|
||||
"If you want to boot this drive in BIOS/Legacy mode, you\r\n" \
|
||||
"should recreate it in Rufus using the following settings:\r\n" \
|
||||
"* Partition scheme -> MBR\r\n" \
|
||||
"* Target system -> BIOS...\r\n" \
|
||||
"\0"
|
||||
|
||||
/********************************************************************************/
|
||||
/* From offset 0x1b8, the MBR contains the partition table and signature data */
|
||||
/********************************************************************************/
|
||||
.org MBR_RESERVED
|
||||
disk_signature:
|
||||
.space 0x04
|
||||
filler:
|
||||
.space 0x02
|
||||
partition_table:
|
||||
.space PT_ENTRY_SIZE * PT_MAX
|
||||
mbr_signature:
|
||||
.word 0xAA55
|
BIN
res/mbr/gpt.bin
BIN
res/mbr/gpt.bin
Binary file not shown.
220
res/mbr/msg.S
Normal file
220
res/mbr/msg.S
Normal file
|
@ -0,0 +1,220 @@
|
|||
/********************************************************************************/
|
||||
/* MSG - A protective MBR that displays an ASCII message located in the */
|
||||
/* following sectors. */
|
||||
/* */
|
||||
/* Copyright (c) 2019-2020 Pete Batard <pete@akeo.ie> */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the Free */
|
||||
/* Software Foundation, either version 3 of the License, or (at your option) */
|
||||
/* any later version. */
|
||||
/* */
|
||||
/* 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/>. */
|
||||
/* */
|
||||
/********************************************************************************/
|
||||
|
||||
/********************************************************************************/
|
||||
/* GNU Assembler Settings: */
|
||||
/********************************************************************************/
|
||||
.intel_syntax noprefix
|
||||
.code16
|
||||
/********************************************************************************/
|
||||
|
||||
/********************************************************************************/
|
||||
/* Constants: */
|
||||
/********************************************************************************/
|
||||
MBR_ADDR = 0x7c00
|
||||
MBR_RESERVED = 0x1b8 # Start of the reserved section (partition table, etc.)
|
||||
NB_SECTORS = 0x08 # Number of sectors to read
|
||||
PT_MAX = 0x04 # Number of partition entries in the partition table
|
||||
PT_ENTRY_SIZE = 0x10 # Size of a partition entry in the partition table
|
||||
|
||||
/********************************************************************************/
|
||||
/* Reference list of colours: */
|
||||
/* You can escape these numeric values in your message text to set the colours *
|
||||
/* for the background and foreground. For instance "\17HIGHLIGHT" will display */
|
||||
/* light grey text (0x07) over a blue (0x01) background */
|
||||
/********************************************************************************/
|
||||
BLACK = 0x00
|
||||
BLUE = 0x01
|
||||
GREEN = 0x02
|
||||
CYAN = 0x03
|
||||
RED = 0x04
|
||||
MAGENTA = 0x05
|
||||
BROWN = 0x06
|
||||
LIGHT_GREY = 0x07
|
||||
DARK_GREY = 0x08
|
||||
LIGHT_BLUE = 0x09
|
||||
LIGHT_GREEN = 0x0a
|
||||
LIGHT_CYAN = 0x0b
|
||||
LIGHT_RED = 0x0c
|
||||
LIGHT_MAGENTA = 0x0d
|
||||
LIGHT_YELLOW = 0x0e
|
||||
WHITE = 0x0f
|
||||
|
||||
/********************************************************************************/
|
||||
/* MBR: This section resides at 0x00007c00 and is exactly 512 bytes */
|
||||
/********************************************************************************/
|
||||
.section main, "ax"
|
||||
.globl mbr
|
||||
mbr:
|
||||
// xchg bx, bx # Uncomment to trigger Bochs magic breakpoint
|
||||
inc cx
|
||||
dec bx
|
||||
inc bp
|
||||
dec di
|
||||
cld
|
||||
xor ax, ax
|
||||
cli # Disable interrupts when fiddling with the stack
|
||||
mov ss, ax # First order of the day it to set up the stack
|
||||
mov sp, MBR_ADDR # This places the stack right before the MBR copy in RAM
|
||||
sti
|
||||
mov ds, ax # MBR and stack reside in segment 0
|
||||
mov bx, 0x0413 # McAfee thinks we are a virus if we use 413 directly...
|
||||
mov ax,[bx]
|
||||
sub ax, NB_SECTORS / 2 # Amount of RAM we need to read the message sectors
|
||||
mov [bx],ax
|
||||
shl ax, 6 # Convert to segment address
|
||||
mov es, ax # Keep allocated RAM segment in ES
|
||||
|
||||
clear_display:
|
||||
mov bh, 0x07
|
||||
mov ax, 0x007f
|
||||
int 0x10 # Set Video Mode to 640x480 16 color graphics (VGA)
|
||||
xor bx, bx
|
||||
xor cx, cx
|
||||
mov dx, 0x184f
|
||||
mov ax, 0x0600
|
||||
int 0x10 # Clear screen
|
||||
xor dx, dx
|
||||
mov ah, 0x02
|
||||
int 0x10 # Set cursor pos to top left
|
||||
|
||||
read_sectors: # Copy the next sectors into RAM
|
||||
mov ah, 0x41
|
||||
mov bx, 0x55aa
|
||||
int 0x13
|
||||
jb no_ext # failure to get ext
|
||||
cmp bx, 0xaa55
|
||||
jnz no_ext
|
||||
test cx, 1 # is packet access supported?
|
||||
jz no_ext
|
||||
|
||||
ext: # http://en.wikipedia.org/wiki/INT_13H#INT_13h_AH.3D42h:_Extended_Read_Sectors_From_Drive
|
||||
xor eax, eax
|
||||
push eax # bits 32-63 of sector address
|
||||
inc eax
|
||||
push eax # bits 0-31 of sector address
|
||||
push es # destination segment
|
||||
push 0x0000 # destination address
|
||||
push NB_SECTORS # number of sectors to be read
|
||||
push 0x0010 # size of DAP struct
|
||||
mov si, sp # DAP address (= stack)
|
||||
mov ah, 0x42 # Extended Read Sectors From Drive
|
||||
int 0x13
|
||||
lahf
|
||||
add sp,0x10
|
||||
sahf
|
||||
jmp check_error
|
||||
|
||||
no_ext: # http://en.wikipedia.org/wiki/INT_13H#INT_13h_AH.3D02h:_Read_Sectors_From_Drive
|
||||
mov ax, 0x0200 + NB_SECTORS
|
||||
mov cx, 0x0002 # Sector address (starts at 1)
|
||||
mov dx, 0x0080 # Drive ID
|
||||
xor bx, bx # Destination address in ES
|
||||
int 0x13
|
||||
|
||||
check_error:
|
||||
mov bx, 0x0007 # Default text to light grey on black
|
||||
jc display_err
|
||||
|
||||
display_msg: # Display the message
|
||||
xor si, si
|
||||
mov ax, es
|
||||
mov ds, ax
|
||||
call print_msg
|
||||
jmp halt_system
|
||||
|
||||
display_err: # Read error -> display shorter message from this MBR
|
||||
mov si, offset err_msg
|
||||
call print_msg
|
||||
|
||||
halt_system: # Halt the system
|
||||
hlt
|
||||
jmp halt_system # Just in case...
|
||||
|
||||
/********************************************************************************/
|
||||
/* Subroutines */
|
||||
/********************************************************************************/
|
||||
|
||||
print_msg: # Print NUL terminated string in DS:SI to console
|
||||
lodsb
|
||||
cmp al, 0x00 # NUL?
|
||||
jz 4f
|
||||
cmp al, 0x0d # Ignore CR
|
||||
jz print_msg
|
||||
cmp al, 0x0a # Handle LF
|
||||
jnz 0f
|
||||
push bx
|
||||
mov ah, 0x03
|
||||
int 0x10 # Get Cursor pos
|
||||
inc dh # Move to next line
|
||||
mov dl, 0 # Set column to 0
|
||||
mov ah, 0x02
|
||||
int 0x10 # Set Cursor pos
|
||||
pop bx
|
||||
jmp print_msg
|
||||
0: cmp al, 0x5c # '\' Escape sequence to set FG/BG color
|
||||
jnz 3f
|
||||
mov cl, 2
|
||||
1: lodsb
|
||||
cmp al, 0x46
|
||||
jg print_msg # Invalid escape sequence
|
||||
sub al, 0x30 # '0'
|
||||
cmp al, 0x09
|
||||
jle 2f
|
||||
sub al, 0x07
|
||||
2: shl bl, 4
|
||||
and al, 0x0f
|
||||
or bl, al
|
||||
dec cl
|
||||
jnz 1b
|
||||
jmp print_msg
|
||||
3: mov cx, 0x0001
|
||||
mov ah, 0x09
|
||||
int 0x10
|
||||
push bx
|
||||
xor bx, bx
|
||||
mov ah, 0x03
|
||||
int 0x10
|
||||
inc dl
|
||||
mov ah, 0x02
|
||||
int 0x10
|
||||
pop bx
|
||||
jmp print_msg
|
||||
4: ret
|
||||
|
||||
/********************************************************************************/
|
||||
/* Data section */
|
||||
/********************************************************************************/
|
||||
err_msg:
|
||||
.string "*** ERROR: THIS MEDIA CANNOT BOOT IN LEGACY MODE ***"
|
||||
|
||||
/********************************************************************************/
|
||||
/* From offset 0x1b8, the MBR contains the partition table and signature data */
|
||||
/********************************************************************************/
|
||||
.org MBR_RESERVED
|
||||
disk_signature:
|
||||
.space 0x04
|
||||
filler:
|
||||
.space 0x02
|
||||
partition_table:
|
||||
.space PT_ENTRY_SIZE * PT_MAX
|
||||
mbr_signature:
|
||||
.word 0xAA55
|
BIN
res/mbr/msg.bin
Normal file
BIN
res/mbr/msg.bin
Normal file
Binary file not shown.
11
res/mbr/msg.txt
Normal file
11
res/mbr/msg.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
****************************************
|
||||
*** ERROR: LEGACY BOOT OF UEFI MEDIA ***
|
||||
****************************************
|
||||
|
||||
This drive can only boot in UEFI mode.
|
||||
It can not boot in BIOS/Legacy mode.
|
||||
|
||||
If you want to boot this drive in BIOS/Legacy mode, you
|
||||
should recreate it in Rufus using the following settings:
|
||||
* Partition scheme -> MBR
|
||||
* Target system -> BIOS...
|
|
@ -14,11 +14,17 @@ a different ID according to the one found in its partition table entry. Eg. if
|
|||
the partition table lists the disk ID for the first partition as 0x81, then it
|
||||
will be swapped for 0x80.
|
||||
|
||||
An additional MBR (msg.S) also exists in this directory, that can be used to
|
||||
display an ASCII message contained in the sectors directly following the MBR.
|
||||
This can be used, for instance, to display a notice for media that cannot be
|
||||
booted in BIOS/Legacy mode.
|
||||
|
||||
# Compilation
|
||||
|
||||
Any gcc suite (except possibly the X-Code one on OS-X) should be able to compile
|
||||
the MBR by invoking 'make'. A 'make dis', that produces a disassembly dump is
|
||||
also provided for your convenience.
|
||||
also provided for your convenience. If you have the Bochs emulator installed,
|
||||
you can also invoke 'make test' to test the MBR with Bochs.
|
||||
|
||||
# Primer
|
||||
|
||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_ACCEPTFILES
|
||||
CAPTION "Rufus 3.9.1617"
|
||||
CAPTION "Rufus 3.9.1618"
|
||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||
|
@ -394,8 +394,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,9,1617,0
|
||||
PRODUCTVERSION 3,9,1617,0
|
||||
FILEVERSION 3,9,1618,0
|
||||
PRODUCTVERSION 3,9,1618,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -413,13 +413,13 @@ BEGIN
|
|||
VALUE "Comments", "https://rufus.ie"
|
||||
VALUE "CompanyName", "Akeo Consulting"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "3.9.1617"
|
||||
VALUE "FileVersion", "3.9.1618"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
VALUE "OriginalFilename", "rufus-3.9.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "3.9.1617"
|
||||
VALUE "ProductVersion", "3.9.1618"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
Loading…
Reference in a new issue