ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/pbcdedit/pbcdedit
(Generate patch)

Comparing pbcdedit/pbcdedit (file contents):
Revision 1.3 by root, Wed Aug 14 21:27:54 2019 UTC vs.
Revision 1.9 by root, Wed Aug 14 22:54:28 2019 UTC

1#!/opt/bin/perl 1#!/usr/bin/perl
2 2
3# 3#
4# PBCDEDIT - Copyright 2019 Marc A. Lehmann <pbcbedit@schmorp.de> 4# PBCDEDIT - Copyright 2019 Marc A. Lehmann <pbcbedit@schmorp.de>
5# 5#
6# SPDX-License-Identifier: GPL-3.0-or-later 6# SPDX-License-Identifier: GPL-3.0-or-later
17# 17#
18# You should have received a copy of the GNU General Public License 18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <https://www.gnu.org/licenses/>. 19# along with this program. If not, see <https://www.gnu.org/licenses/>.
20# 20#
21 21
22use 5.014; # numerous features 22use 5.014; # numerous features needed
23 23
24our $VERSION = '1.0'; 24our $VERSION = '1.0';
25our $JSON_VERSION = 1; # the versiobn of the json objects generated by this program 25our $JSON_VERSION = 1; # the versiobn of the json objects generated by this program
26 26
27=head1 NAME 27=head1 NAME
41=head1 DESCRIPTION 41=head1 DESCRIPTION
42 42
43This program allows you to create, read and modify Boot Configuration Data 43This program allows you to create, read and modify Boot Configuration Data
44(BCD) stores used by Windows Vista and newer versions of Windows. 44(BCD) stores used by Windows Vista and newer versions of Windows.
45 45
46At this point, it is in relatively early stages of development and has
47received little to no real-world testing.
48
46Compared to other BCD editing programs it offers the following unique 49Compared to other BCD editing programs it offers the following unique
47features: 50features:
48 51
49=over 52=over
50 53
106The reverse of C<export>: Reads a JSON representation of a BCD data store 109The reverse of C<export>: Reads a JSON representation of a BCD data store
107from standard input, and creates or replaces the given BCD data store. 110from standard input, and creates or replaces the given BCD data store.
108 111
109=item edit F<path> instructions... 112=item edit F<path> instructions...
110 113
111#TODO 114Load a BCD data store, apply some instructions to it, and save it again.
115
116See the section L<EDITING BCD DATA STORES>, below, for more info.
117
118=item parse F<path> instructions...
119
120Same as C<edit>, above, except it doesn't save the data store again. Can
121be useful to extract some data from it.
112 122
113=item lsblk 123=item lsblk
114 124
115On a GNU/Linux system, you can get a list of partition device descriptors 125On a GNU/Linux system, you can get a list of partition device descriptors
116using this command - the external C<lsblk> command is required, as well as 126using this command - the external C<lsblk> command is required, as well as
618many questions, but I can walk you through some actual examples using mroe 628many questions, but I can walk you through some actual examples using mroe
619complex aspects. 629complex aspects.
620 630
621=item locate=<block=vhd,<block=file,<locate=<null>,path,\disk.vhdx>,\disk.vhdx>>,element,path 631=item locate=<block=vhd,<block=file,<locate=<null>,path,\disk.vhdx>,\disk.vhdx>>,element,path
622 632
623#todo 633Just like with C declarations, you best treat device descriptors as
634instructions to find your device and work your way from the inside out:
635
636 locate=<null>,path,\disk.vhdx
637
638First, the innermost device descriptor searches all partitions on the
639system for a file called F<\disk.vhdx>:
640
641 block=file,<see above>,\disk.vhdx
642
643Next, this takes the device locate has found and finds a file called
644F<\disk.vhdx> on it. This is the same file locate was using, but that is
645only because we find the device using the same path as finding the disk
646image, so this is purely incidental, although quite common.
647
648Bext, this file will be opened as a virtual disk:
649
650 block=vhd,<see above>
651
652And finally, inside this disk, another C<locate> will look for a partition
653with a path as specified in the C<path> element, which most likely will be
654F<\Windows\system32\winload.exe>:
655
656 locate=<see above>,element,path
657
658As a result, this will boot the first Windows it finds on the first
659F<disk.vhdx> disk image it can find anywhere.
624 660
625=item locate=<block=vhd,<block=file,<partition=<null>,harddisk,mbr,47cbc08a,242643632128>,\win10.vhdx>>,element,path 661=item locate=<block=vhd,<block=file,<partition=<null>,harddisk,mbr,47cbc08a,242643632128>,\win10.vhdx>>,element,path
626 662
627#todo 663Pretty much the same as the previous case, but witzh a bit of variance. First, look for a specific partition on
664an MBR-partitioned disk:
665
666 partition=<null>,harddisk,mbr,47cbc08a,242643632128
667
668Then open the file F<\win10.vhdx> on that partition:
669
670 block=file,<see above>,\win10.vhdx
671
672Then, again, the file is opened as a virtual disk image:
673
674 block=vhd,<see above>
675
676And again the windows loader (or whatever is in C<path>) will be searched:
677
678 locate=<see above>,element,path
628 679
629=item {b097d2b2-bc00-11e9-8a9a-525400123456}block<1>=ramdisk,<partition=<null>,harddisk,mbr,47cbc08a,242643632128>,0,0,0,\boot.wim 680=item {b097d2b2-bc00-11e9-8a9a-525400123456}block<1>=ramdisk,<partition=<null>,harddisk,mbr,47cbc08a,242643632128>,0,0,0,\boot.wim
630 681
631#todo 682This is quite different. First, it starts with a GUID. This GUID belongs
683to a BCD object of type C<device>, which has additional parameters:
632 684
685 "{b097d2b2-bc00-11e9-8a9a-525400123456}" : {
686 "type" : "device",
687 "description" : "sdi file for ramdisk",
688 "ramdisksdidevice" : "partition=<null>,harddisk,mbr,47cbc08a,1048576",
689 "ramdisksdipath" : "\boot.sdi"
690 },
691
692I will not go into many details, but this specifies a (presumably empty)
693template ramdisk image (F<\boot.sdi>) that is used to initiaolize the
694ramdisk. The F<\boot.wim> file is then extracted into it. As you cna also
695see, this F<.sdi> file resides on a different C<partition>.
696
697Continuitn, as always, form the inside out, first this device descriptor
698finds a specific partition:
699
700 partition=<null>,harddisk,mbr,47cbc08a,242643632128
701
702And then specifies a C<ramdisk> image on this partition:
703
704 block<1>=ramdisk,<see above>,0,0,0,\boot.wim
705
706I don't know what the purpose of the C<< <1> >> flag value is, but it
707seems to be always there on this kind of entry.
708
709If you have some good examples to add here, feel free to mail me.
710
711
712=head1 EDITING BCD DATA STORES
713
714The C<edit> and C<parse> subcommands allow you to read a BCD data store
715and modify it or extract data from it. This is done by exyecuting a series
716of "editing instructions" which are explained here.
717
718=over
719
720=item get I<object> I<element>
721
722Reads the BCD element I<element> from the BCD object I<object> and writes
723it to standard output, followed by a newline. The I<object> can be a GUID
724or a human-readable alias, or the special string C<{default}>, which will
725refer to the default BCD object.
726
727Example: find description of the default BCD object.
728
729 pbcdedit parse BCD get "{default}" description
730
731=item set I<object> I<element> I<value>
732
733Similar to C<get>, but sets the element to the given I<value> instead.
734
735Example: change bootmgr default too
736C<{b097d2ad-bc00-11e9-8a9a-525400123456}>:
737
738 pbcdedit edit BCD set "{bootmgr}" resumeobject "{b097d2ad-bc00-11e9-8a9a-525400123456}"
739
740=item eval I<perlcode>
741
742This takes the next argument, interprets it as Perl code and
743evaluates it. This allows you to do more complicated modifications or
744extractions.
745
746The following variables are predefined for your use:
747
748=over
749
750=item C<$PATH>
751
752The path to the BCD data store, as given to C<edit> or C<parse>.
753
754=item C<$BCD>
755
756The decoded BCD data store.
757
758=item C<$DEFAULT>
759
760The default BCD object name.
761
762=back
763
764The example given for C<get>, above, could be expressed like this with
765C<eval>:
766
767 pbcdedit edit BCD eval 'say $BCD->{$DEFAULT}{description}'
768
769The example given for C<set> could be expresed like this:
770
771 pbcdedit edit BCD eval '$BCD->{$DEFAULT}{resumeobject} = "{b097d2ad-bc00-11e9-8a9a-525400123456}"'
772
773=item do I<path>
774
775Similar to C<eval>, above, but instead of using the argument as perl code,
776it loads the perl code from the given file and executes it. This makes it
777easier to write more complicated or larger programs.
778
779=back
633 780
634=head1 SEE ALSO 781=head1 SEE ALSO
635 782
636For ideas on what you can do, and some introductory material, try 783For ideas on what you can do, and some introductory material, try
637L<http://www.mistyprojects.co.uk/documents/BCDEdit/index.html>. 784L<http://www.mistyprojects.co.uk/documents/BCDEdit/index.html>.
692 839
693# hack used for debugging 840# hack used for debugging
694sub xxd($$) { 841sub xxd($$) {
695 open my $xxd, "| xxd | sed -e 's/^/\Q$_[0]\E: /'"; 842 open my $xxd, "| xxd | sed -e 's/^/\Q$_[0]\E: /'";
696 syswrite $xxd, $_[1]; 843 syswrite $xxd, $_[1];
844}
845
846sub file_load($) {
847 my ($path) = @_;
848
849 open my $fh, "<:raw", $path
850 or die "$path: $!\n";
851 my $size = -s $fh;
852 $size = read $fh, my $buf, $size
853 or die "$path: short read\n";
854
855 $buf
697} 856}
698 857
699# sources and resources used for this: 858# sources and resources used for this:
700# registry: 859# registry:
701# https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md 860# https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md
1052} 1211}
1053 1212
1054# load and parse registry from file 1213# load and parse registry from file
1055sub regf_load($) { 1214sub regf_load($) {
1056 my ($path) = @_; 1215 my ($path) = @_;
1057 open my $regf, "<:raw", $path
1058 or die "$path: $!\n";
1059 my $size = -s $regf;
1060 $size = read $regf, my $buf, $size
1061 or die "$path: short read\n";
1062 1216
1063 regf_decode $buf 1217 regf_decode file_load $path
1064} 1218}
1065 1219
1066# encode and save registry to file 1220# encode and save registry to file
1067sub regf_save { 1221sub regf_save {
1068 my ($path, $hive) = @_; 1222 my ($path, $hive) = @_;
2089 }]] 2243 }]]
2090} 2244}
2091 2245
2092############################################################################# 2246#############################################################################
2093 2247
2248sub bcd_edit_eval {
2249 package pbcdedit;
2250
2251 our ($PATH, $BCD, $DEFAULT);
2252
2253 eval shift;
2254 die "$@" if $@;
2255}
2256
2257sub bcd_edit {
2258 my ($path, $bcd, @insns) = @_;
2259
2260 my $default = $bcd->{"{bootmgr}"}{resumeobject};
2261
2262 # prepare "officially visible" variables
2263 local $pbcdedit::PATH = $path;
2264 local $pbcdedit::BCD = $bcd;
2265 local $pbcdedit::DEFAULT = $default;
2266
2267 while (@insns) {
2268 my $insn = shift @insns;
2269
2270 if ($insn eq "get") {
2271 my $object = shift @insns;
2272 my $elem = shift @insns;
2273
2274 $object = $default if $object eq "{default}";
2275
2276 print $bcd->{$object}{$elem}, "\n";
2277
2278 } elsif ($insn eq "set") {
2279 my $object = shift @insns;
2280 my $elem = shift @insns;
2281 my $value = shift @insns;
2282
2283 $object = $default if $object eq "{default}";
2284
2285 $bcd->{$object}{$elem} = $value;
2286
2287 } elsif ($insn eq "eval") {
2288 bcd_edit_eval shift @insns;
2289
2290 } elsif ($insn eq "do") {
2291 my $path = shift @insns;
2292 my $file = file_load $path;
2293 bcd_edit_eval "#line 1 '$path'\n$file";
2294
2295 } else {
2296 die "$insn: not a recognized instruction for edit/parse\n";
2297 }
2298 }
2299
2300}
2301
2302#############################################################################
2303
2094# json to stdout 2304# json to stdout
2095sub prjson($) { 2305sub prjson($) {
2096 print $json_coder->encode ($_[0]); 2306 print $json_coder->encode ($_[0]);
2097} 2307}
2098 2308
2195 prjson bcd_decode regf_load shift; 2405 prjson bcd_decode regf_load shift;
2196 }, 2406 },
2197 2407
2198 import => sub { 2408 import => sub {
2199 regf_save shift, bcd_encode rdjson; 2409 regf_save shift, bcd_encode rdjson;
2410 },
2411
2412 edit => sub {
2413 my $path = shift;
2414 my $bcd = bcd_decode regf_load $path;
2415 bcd_edit $path, $bcd, @_;
2416 regf_save $path, bcd_encode $bcd;
2417 },
2418
2419 parse => sub {
2420 my $path = shift;
2421 my $bcd = bcd_decode regf_load $path;
2422 bcd_edit $path, $bcd, @_;
2200 }, 2423 },
2201 2424
2202 "export-regf" => sub { 2425 "export-regf" => sub {
2203 prjson regf_load shift; 2426 prjson regf_load shift;
2204 2427

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines